diff --git a/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue b/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue
index 212155ea518507dcc2aa7b3e64d579393965d39d..2d468583e80afb27e67b7bacb0d15b5e7e5058ee 100644
--- a/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue
+++ b/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue
@@ -96,9 +96,6 @@ export default {
         this.paginateDashboard(newPage);
       },
     },
-    showDashboard() {
-      return this.projects.length || this.isLoadingProjects;
-    },
     projectsPerPage() {
       return this.projectsPage.pageInfo.perPage;
     },
@@ -163,7 +160,7 @@ export default {
 </script>
 
 <template>
-  <div v-if="showDashboard" class="environments-dashboard">
+  <div class="environments-dashboard">
     <gl-modal
       :modal-id="$options.modalId"
       :title="$options.addProjectsModalHeader"
@@ -196,17 +193,14 @@ export default {
       />
     </gl-modal>
     <div class="page-title-holder flex-fill d-flex gl-align-items-center">
-      <h1
-        class="page-title gl-font-size-h-display text-nowrap flex-fill"
-        data-testid="dashboard-title"
-      >
+      <h1 class="js-dashboard-title page-title gl-font-size-h-display text-nowrap flex-fill">
         {{ $options.dashboardHeader }}
       </h1>
-      <gl-button v-gl-modal="$options.modalId" data-testid="add-projects-button" variant="confirm">
+      <gl-button v-gl-modal="$options.modalId" class="js-add-projects-button" variant="confirm">
         {{ $options.addProjectsButton }}
       </gl-button>
     </div>
-    <p class="gl-mt-3 gl-mb-6" data-testid="page-limits-message">
+    <p class="mt-2 mb-4 js-page-limits-message">
       <gl-sprintf :message="$options.informationText">
         <template #link="{ content }">
           <gl-link :href="environmentsDashboardHelpPath" target="_blank">
@@ -240,30 +234,26 @@ export default {
       </div>
 
       <gl-dashboard-skeleton v-else-if="isLoadingProjects" />
+
+      <gl-empty-state
+        v-else
+        :title="$options.emptyDashboardHeader"
+        :svg-path="emptyDashboardSvgPath"
+        :svg-height="150"
+      >
+        <template #description>
+          {{ $options.emptyDashboardDocs }}
+          <gl-link :href="emptyDashboardHelpPath" class="js-documentation-link">{{
+            $options.viewDocumentationButton
+          }}</gl-link
+          >.
+        </template>
+        <template #actions>
+          <gl-button v-gl-modal="$options.modalId" variant="confirm" class="js-add-projects-button">
+            {{ s__('ModalButton|Add projects') }}
+          </gl-button>
+        </template>
+      </gl-empty-state>
     </div>
   </div>
-  <gl-empty-state
-    v-else
-    :title="$options.emptyDashboardHeader"
-    :description="$options.emptyDashboardDocs"
-    :svg-path="emptyDashboardSvgPath"
-  >
-    <template #actions>
-      <gl-button
-        v-gl-modal="$options.modalId"
-        variant="confirm"
-        class="gl-mb-3 gl-mx-2"
-        data-testid="add-projects-button"
-      >
-        {{ $options.addProjectsButton }}
-      </gl-button>
-      <gl-button
-        :href="emptyDashboardHelpPath"
-        class="gl-mb-3 gl-mx-2"
-        data-testid="documentation-link"
-      >
-        {{ $options.viewDocumentationButton }}
-      </gl-button>
-    </template>
-  </gl-empty-state>
 </template>
diff --git a/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue b/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue
index 6032dcc6e846281b3477c1aa1910b2f326e58f72..7baf0fa801c848be9e9315d60d9d2facee1999d2 100644
--- a/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue
+++ b/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue
@@ -17,18 +17,9 @@ import ProjectSelector from '~/vue_shared/components/project_selector/project_se
 import DashboardProject from './project.vue';
 
 export default {
-  title: s__('OperationsDashboard|Operations Dashboard'),
   informationText: s__(
     'OperationsDashboard|The Operations and Environments dashboards share the same list of projects. When you add or remove a project from one, GitLab adds or removes the project from the other. %{linkStart}More information%{linkEnd}',
   ),
-  moreInformationButton: s__('OperationsDashboard|More information'),
-  addProjectsSubmitButton: s__('OperationsDashboard|Add projects'),
-  addProjectsModalHeader: s__('OperationsDashboard|Add projects'),
-  dashboardHeader: s__('OperationsDashboard|Operations Dashboard'),
-  emptyStateTitle: s__(`OperationsDashboard|Add a project to the dashboard`),
-  emptyStateDescription: s__(
-    `OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses.`,
-  ),
   components: {
     DashboardProject,
     GlDashboardSkeleton,
@@ -83,9 +74,6 @@ export default {
         this.setProjects(projects);
       },
     },
-    showDashboard() {
-      return this.projects.length || this.isLoadingProjects;
-    },
     isSearchingProjects() {
       return this.searchCount > 0;
     },
@@ -94,7 +82,7 @@ export default {
     },
     actionPrimary() {
       return {
-        text: this.addProjectsSubmitButton,
+        text: s__('OperationsDashboard|Add projects'),
         attributes: {
           disabled: this.okDisabled,
           variant: 'confirm',
@@ -147,10 +135,10 @@ export default {
 </script>
 
 <template>
-  <div v-if="showDashboard" class="operations-dashboard">
+  <div class="operations-dashboard">
     <gl-modal
       :modal-id="$options.modalId"
-      :title="$options.addProjectsModalHeader"
+      :title="s__('OperationsDashboard|Add projects')"
       :action-primary="actionPrimary"
       :action-cancel="$options.modal.actionCancel"
       data-testid="add-projects-modal"
@@ -173,11 +161,8 @@ export default {
     </gl-modal>
 
     <div class="page-title-holder flex-fill d-flex gl-align-items-center">
-      <h1
-        class="page-title gl-font-size-h-display text-nowrap flex-fill"
-        data-testid="dashboard-title"
-      >
-        {{ $options.title }}
+      <h1 class="js-dashboard-title page-title gl-font-size-h-display text-nowrap flex-fill">
+        {{ s__('OperationsDashboard|Operations Dashboard') }}
       </h1>
       <gl-button
         v-if="projects.length"
@@ -186,7 +171,7 @@ export default {
         category="primary"
         data-testid="add-projects-button"
       >
-        {{ $options.addProjectsSubmitButton }}
+        {{ s__('OperationsDashboard|Add projects') }}
       </gl-button>
     </div>
     <p class="gl-mt-2 gl-mb-4">
@@ -211,30 +196,34 @@ export default {
       </vue-draggable>
 
       <gl-dashboard-skeleton v-else-if="isLoadingProjects" />
+
+      <gl-empty-state
+        v-else
+        :title="s__(`OperationsDashboard|Add a project to the dashboard`)"
+        :svg-path="emptyDashboardSvgPath"
+        :svg-height="150"
+      >
+        <template #description>
+          {{
+            s__(
+              `OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses.`,
+            )
+          }}
+          <gl-link :href="emptyDashboardHelpPath" data-testid="documentation-link">{{
+            s__('OperationsDashboard|More information')
+          }}</gl-link
+          >.
+        </template>
+        <template #actions>
+          <gl-button
+            v-gl-modal="$options.modalId"
+            variant="confirm"
+            data-testid="add-projects-button"
+          >
+            {{ s__('OperationsDashboard|Add projects') }}
+          </gl-button>
+        </template>
+      </gl-empty-state>
     </div>
   </div>
-  <gl-empty-state
-    v-else
-    :title="$options.emptyStateTitle"
-    :description="$options.emptyStateDescription"
-    :svg-path="emptyDashboardSvgPath"
-  >
-    <template #actions>
-      <gl-button
-        v-gl-modal="$options.modalId"
-        variant="confirm"
-        data-testid="add-projects-button"
-        class="gl-mb-3 gl-mx-2"
-      >
-        {{ $options.addProjectsSubmitButton }}
-      </gl-button>
-      <gl-button
-        :href="emptyDashboardHelpPath"
-        data-testid="documentation-link"
-        class="gl-mb-3 gl-mx-2"
-      >
-        {{ $options.moreInformationButton }}
-      </gl-button>
-    </template>
-  </gl-empty-state>
 </template>
diff --git a/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap b/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d68cbec111ca36805d7a556e0b939a82b7b29ea3
--- /dev/null
+++ b/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap
@@ -0,0 +1,99 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`dashboard should match the snapshot 1`] = `
+<div
+  class="environments-dashboard"
+>
+  <gl-modal-stub
+    arialabel=""
+    dismisslabel="Close"
+    modalclass=""
+    modalid="add-projects-modal"
+    ok-disabled="true"
+    ok-title="Add projects"
+    size="md"
+    title="Add projects"
+    titletag="h4"
+  >
+    <p>
+      This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other.
+      <gl-link-stub
+        href="/help/user/operations_dashboard/index.html"
+        target="_blank"
+      >
+        More information
+      </gl-link-stub>
+    </p>
+    <project-selector-stub
+      maxlistheight="402"
+      projectsearchresults=""
+      selectedprojects=""
+      totalresults="0"
+    />
+  </gl-modal-stub>
+  <div
+    class="d-flex flex-fill gl-align-items-center page-title-holder"
+  >
+    <h1
+      class="flex-fill gl-font-size-h-display js-dashboard-title page-title text-nowrap"
+    >
+      Environments Dashboard
+    </h1>
+    <gl-button-stub
+      buttontextclasses=""
+      category="primary"
+      class="js-add-projects-button"
+      icon=""
+      role="button"
+      size="medium"
+      tabindex="0"
+      variant="confirm"
+    >
+      Add projects
+    </gl-button-stub>
+  </div>
+  <p
+    class="js-page-limits-message mb-4 mt-2"
+  >
+    This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other.
+    <gl-link-stub
+      href="/help/user/operations_dashboard/index.html"
+      target="_blank"
+    >
+      More information
+    </gl-link-stub>
+  </p>
+  <div
+    class="gl-mt-3"
+  >
+    <gl-empty-state-stub
+      contentclass=""
+      invertindarkmode="true"
+      svgheight="150"
+      svgpath="/assets/illustrations/empty-state/empty-radar-md.svg"
+      title="Add a project to the dashboard"
+    >
+      The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses.
+      <gl-link-stub
+        class="js-documentation-link"
+        href="/help/user/operations_dashboard/index.html"
+      >
+        View documentation
+      </gl-link-stub>
+      .
+      <gl-button-stub
+        buttontextclasses=""
+        category="primary"
+        class="js-add-projects-button"
+        icon=""
+        role="button"
+        size="medium"
+        tabindex="0"
+        variant="confirm"
+      >
+        Add projects
+      </gl-button-stub>
+    </gl-empty-state-stub>
+  </div>
+</div>
+`;
diff --git a/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js b/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js
index 7ffc3b4fc735406057a2293c9289b155c1e7d5fa..eaa38fa100689db38707f760537d0ee5f180b912 100644
--- a/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js
+++ b/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js
@@ -1,8 +1,8 @@
 import { GlButton, GlEmptyState, GlModal, GlSprintf, GlLink, GlPagination } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
 import Vue, { nextTick } from 'vue';
 // eslint-disable-next-line no-restricted-imports
 import Vuex from 'vuex';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import component from 'ee/environments_dashboard/components/dashboard/dashboard.vue';
 import Environment from 'ee/environments_dashboard/components/dashboard/environment.vue';
 import ProjectHeader from 'ee/environments_dashboard/components/dashboard/project_header.vue';
@@ -50,7 +50,7 @@ describe('dashboard', () => {
       environmentsDashboardHelpPath: '/help/user/operations_dashboard/index.html',
     };
 
-    wrapper = shallowMountExtended(component, {
+    wrapper = shallowMount(component, {
       propsData,
       store,
       stubs: { GlSprintf },
@@ -62,24 +62,53 @@ describe('dashboard', () => {
   });
 
   const findPagination = () => wrapper.findComponent(GlPagination);
-  const findDashboardTitle = () => wrapper.findByTestId('dashboard-title');
-  const findPageLimitsMessage = () => wrapper.findByTestId('page-limits-message');
 
-  describe('empty state', () => {
-    it('should render the empty state component', () => {
-      expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
+  it('should match the snapshot', () => {
+    expect(wrapper.element).toMatchSnapshot();
+  });
+
+  it('renders the dashboard title', () => {
+    expect(wrapper.find('.js-dashboard-title').text()).toBe('Environments Dashboard');
+  });
+
+  it('should render the empty state component', () => {
+    expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
+  });
+
+  it('should not render pagination in empty state', () => {
+    expect(findPagination().exists()).toBe(false);
+  });
+
+  describe('page limits information message', () => {
+    let message;
+
+    beforeEach(() => {
+      message = wrapper.find('.js-page-limits-message');
+    });
+
+    it('renders the message', () => {
+      expect(trimText(message.text())).toBe(
+        'This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. More information',
+      );
     });
 
-    it('should not the render title', () => {
-      expect(findDashboardTitle().exists()).toBe(false);
+    it('includes the correct documentation link in the message', () => {
+      const helpLink = message.findComponent(GlLink);
+
+      expect(helpLink.text()).toBe('More information');
+      expect(helpLink.attributes('href')).toBe(propsData.environmentsDashboardHelpPath);
     });
+  });
+
+  describe('add projects button', () => {
+    let button;
 
-    it('should not the render description', () => {
-      expect(findPageLimitsMessage().exists()).toBe(false);
+    beforeEach(() => {
+      button = wrapper.findComponent(GlButton);
     });
 
-    it('should not render pagination', () => {
-      expect(findPagination().exists()).toBe(false);
+    it('is labelled correctly', () => {
+      expect(button.text()).toBe('Add projects');
     });
   });
 
@@ -96,43 +125,6 @@ describe('dashboard', () => {
       ];
     });
 
-    it('renders the dashboard title', () => {
-      expect(findDashboardTitle().text()).toBe('Environments Dashboard');
-    });
-
-    describe('page limits information message', () => {
-      let message;
-
-      beforeEach(() => {
-        message = findPageLimitsMessage();
-      });
-
-      it('renders the message', () => {
-        expect(trimText(message.text())).toBe(
-          'This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. More information',
-        );
-      });
-
-      it('includes the correct documentation link in the message', () => {
-        const helpLink = message.findComponent(GlLink);
-
-        expect(helpLink.text()).toBe('More information');
-        expect(helpLink.attributes('href')).toBe(propsData.environmentsDashboardHelpPath);
-      });
-    });
-
-    describe('add projects button', () => {
-      let button;
-
-      beforeEach(() => {
-        button = wrapper.findComponent(GlButton);
-      });
-
-      it('is labelled correctly', () => {
-        expect(button.text()).toBe('Add projects');
-      });
-    });
-
     describe('project header', () => {
       it('should have one project header per project', () => {
         const headers = wrapper.findAllComponents(ProjectHeader);
diff --git a/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js b/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js
index 698785370e7a237ec82819be5417ad85f8b9002e..c4721a635d03a634d05d2037c1b07988937d84b7 100644
--- a/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js
+++ b/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js
@@ -59,50 +59,18 @@ describe('dashboard component', () => {
     mockAxios.restore();
   });
 
-  describe('when no projects have been added', () => {
-    beforeEach(() => {
-      store.state.projects = [];
-      store.state.isLoadingProjects = false;
-    });
-
-    it('should render the empty state', () => {
-      expect(findEmptyState().exists()).toBe(true);
-    });
+  it('renders dashboard title', () => {
+    const dashboardTitle = wrapper.element.querySelector('.js-dashboard-title');
 
-    it('should link to the documentation', () => {
-      const link = wrapper.findByTestId('documentation-link');
-
-      expect(link.exists()).toBe(true);
-      expect(link.attributes().href).toEqual(emptyDashboardHelpPath);
-    });
-
-    it('should render the add projects button', () => {
-      const button = findAddProjectButton();
-
-      expect(button.exists()).toBe(true);
-      expect(button.text()).toEqual('Add projects');
-    });
+    expect(dashboardTitle.innerText.trim()).toEqual(mockText.DASHBOARD_TITLE);
   });
 
-  describe('wrapped components', () => {
-    const projectCount = 3;
-
-    beforeEach(() => {
-      store.state.projects = mockProjectData(projectCount);
-      wrapper = mountComponent();
+  describe('add projects button', () => {
+    it('renders add projects text', () => {
+      expect(findAddProjectButton().text()).toBe(mockText.ADD_PROJECTS);
     });
 
-    describe('dashboard layout', () => {
-      it('renders dashboard title', () => {
-        const dashboardTitle = wrapper.findByTestId('dashboard-title');
-
-        expect(dashboardTitle.text()).toEqual(mockText.DASHBOARD_TITLE);
-      });
-
-      it('renders add projects text', () => {
-        expect(findAddProjectButton().text()).toBe(mockText.ADD_PROJECTS);
-      });
-
+    describe('when a project is added', () => {
       it('immediately requests the project list again', async () => {
         mockAxios.reset();
         mockAxios
@@ -121,8 +89,17 @@ describe('dashboard component', () => {
         expect(findAllProjects()).toHaveLength(2);
       });
     });
+  });
 
+  describe('wrapped components', () => {
     describe('dashboard project component', () => {
+      const projectCount = 1;
+
+      beforeEach(() => {
+        store.state.projects = mockProjectData(projectCount);
+        wrapper = mountComponent();
+      });
+
       it('includes a dashboard project component for each project', () => {
         expect(findAllProjects()).toHaveLength(projectCount);
       });
@@ -212,5 +189,30 @@ describe('dashboard component', () => {
         expect(store.state.selectedProjects).toHaveLength(0);
       });
     });
+
+    describe('when no projects have been added', () => {
+      beforeEach(() => {
+        store.state.projects = [];
+        store.state.isLoadingProjects = false;
+      });
+
+      it('should render the empty state', () => {
+        expect(findEmptyState().exists()).toBe(true);
+      });
+
+      it('should link to the documentation', () => {
+        const link = findEmptyState().find('[data-testid="documentation-link"]');
+
+        expect(link.exists()).toBe(true);
+        expect(link.attributes().href).toEqual(emptyDashboardHelpPath);
+      });
+
+      it('should render the add projects button', () => {
+        const button = findAddProjectButton();
+
+        expect(button.exists()).toBe(true);
+        expect(button.text()).toEqual('Add projects');
+      });
+    });
   });
 });
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ba50eaa0e2d971896ed7732f0398d3c91539af41..6d87e193bde0e0a29b8e512211775df30efc6f01 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -31809,6 +31809,9 @@ msgstr ""
 msgid "Modal updated"
 msgstr ""
 
+msgid "ModalButton|Add projects"
+msgstr ""
+
 msgid "Modal|Close"
 msgstr ""