From 6be6c7761d35bca8fa08a69d146469a6c82aa247 Mon Sep 17 00:00:00 2001
From: Florie Guibert <fguibert@gitlab.com>
Date: Thu, 10 Feb 2022 15:34:03 +1000
Subject: [PATCH] Issue boards - Fetch recent board in GraphQL

No user facing changes
---
 .../boards/components/boards_selector.vue     |  54 ++---
 .../graphql/group_recent_boards.query.graphql |  14 ++
 .../project_recent_boards.query.graphql       |  14 ++
 app/assets/javascripts/boards/index.js        |   1 -
 .../boards/mount_multiple_boards_switcher.js  |   1 -
 .../boards/components/boards_selector.vue     |   3 +-
 .../boards/components/boards_selector_spec.js | 147 +++++---------
 ee/spec/frontend/boards/mock_data.js          |  21 ++
 .../boards/components/boards_selector_spec.js | 188 +++++++++---------
 spec/frontend/boards/mock_data.js             |  78 ++++++++
 10 files changed, 287 insertions(+), 234 deletions(-)
 create mode 100644 app/assets/javascripts/boards/graphql/group_recent_boards.query.graphql
 create mode 100644 app/assets/javascripts/boards/graphql/project_recent_boards.query.graphql

diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 69343cd78d8d3..6dbb1ea0050d2 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -14,8 +14,6 @@ import { mapActions, mapGetters, mapState } from 'vuex';
 import BoardForm from 'ee_else_ce/boards/components/board_form.vue';
 
 import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import axios from '~/lib/utils/axios_utils';
-import httpStatusCodes from '~/lib/utils/http_status';
 import { s__ } from '~/locale';
 
 import eventHub from '../eventhub';
@@ -23,6 +21,8 @@ import groupBoardsQuery from '../graphql/group_boards.query.graphql';
 import projectBoardsQuery from '../graphql/project_boards.query.graphql';
 import groupBoardQuery from '../graphql/group_board.query.graphql';
 import projectBoardQuery from '../graphql/project_board.query.graphql';
+import groupRecentBoardsQuery from '../graphql/group_recent_boards.query.graphql';
+import projectRecentBoardsQuery from '../graphql/project_recent_boards.query.graphql';
 
 const MIN_BOARDS_TO_VIEW_RECENT = 10;
 
@@ -40,7 +40,7 @@ export default {
   directives: {
     GlModalDirective,
   },
-  inject: ['fullPath', 'recentBoardsEndpoint'],
+  inject: ['fullPath'],
   props: {
     throttleDuration: {
       type: Number,
@@ -158,6 +158,10 @@ export default {
       this.scrollFadeInitialized = false;
       this.$nextTick(this.setScrollFade);
     },
+    recentBoards() {
+      this.scrollFadeInitialized = false;
+      this.$nextTick(this.setScrollFade);
+    },
   },
   created() {
     eventHub.$on('showBoardModal', this.showPage);
@@ -173,11 +177,11 @@ export default {
     cancel() {
       this.showPage('');
     },
-    boardUpdate(data) {
+    boardUpdate(data, boardType) {
       if (!data?.[this.parentType]) {
         return [];
       }
-      return data[this.parentType].boards.edges.map(({ node }) => ({
+      return data[this.parentType][boardType].edges.map(({ node }) => ({
         id: getIdFromGraphQLId(node.id),
         name: node.name,
       }));
@@ -185,6 +189,9 @@ export default {
     boardQuery() {
       return this.isGroupBoard ? groupBoardsQuery : projectBoardsQuery;
     },
+    recentBoardsQuery() {
+      return this.isGroupBoard ? groupRecentBoardsQuery : projectRecentBoardsQuery;
+    },
     loadBoards(toggleDropdown = true) {
       if (toggleDropdown && this.boards.length > 0) {
         return;
@@ -196,39 +203,20 @@ export default {
         },
         query: this.boardQuery,
         loadingKey: 'loadingBoards',
-        update: this.boardUpdate,
+        update: (data) => this.boardUpdate(data, 'boards'),
       });
 
       this.loadRecentBoards();
     },
     loadRecentBoards() {
-      this.loadingRecentBoards = true;
-      // Follow up to fetch recent boards using GraphQL
-      // https://gitlab.com/gitlab-org/gitlab/-/issues/300985
-      axios
-        .get(this.recentBoardsEndpoint)
-        .then((res) => {
-          this.recentBoards = res.data;
-        })
-        .catch((err) => {
-          /**
-           *  If user is unauthorized we'd still want to resolve the
-           *  request to display all boards.
-           */
-          if (err?.response?.status === httpStatusCodes.UNAUTHORIZED) {
-            this.recentBoards = []; // recent boards are empty
-            return;
-          }
-          throw err;
-        })
-        .then(() => this.$nextTick()) // Wait for boards list in DOM
-        .then(() => {
-          this.setScrollFade();
-        })
-        .catch(() => {})
-        .finally(() => {
-          this.loadingRecentBoards = false;
-        });
+      this.$apollo.addSmartQuery('recentBoards', {
+        variables() {
+          return { fullPath: this.fullPath };
+        },
+        query: this.recentBoardsQuery,
+        loadingKey: 'loadingRecentBoards',
+        update: (data) => this.boardUpdate(data, 'recentIssueBoards'),
+      });
     },
     isScrolledUp() {
       const { content } = this.$refs;
diff --git a/app/assets/javascripts/boards/graphql/group_recent_boards.query.graphql b/app/assets/javascripts/boards/graphql/group_recent_boards.query.graphql
new file mode 100644
index 0000000000000..827c08486b19b
--- /dev/null
+++ b/app/assets/javascripts/boards/graphql/group_recent_boards.query.graphql
@@ -0,0 +1,14 @@
+#import "ee_else_ce/boards/graphql/board.fragment.graphql"
+
+query group_recent_boards($fullPath: ID!) {
+  group(fullPath: $fullPath) {
+    id
+    recentIssueBoards {
+      edges {
+        node {
+          ...BoardFragment
+        }
+      }
+    }
+  }
+}
diff --git a/app/assets/javascripts/boards/graphql/project_recent_boards.query.graphql b/app/assets/javascripts/boards/graphql/project_recent_boards.query.graphql
new file mode 100644
index 0000000000000..4d38e9b0498ee
--- /dev/null
+++ b/app/assets/javascripts/boards/graphql/project_recent_boards.query.graphql
@@ -0,0 +1,14 @@
+#import "ee_else_ce/boards/graphql/board.fragment.graphql"
+
+query project_recent_boards($fullPath: ID!) {
+  project(fullPath: $fullPath) {
+    id
+    recentIssueBoards {
+      edges {
+        node {
+          ...BoardFragment
+        }
+      }
+    }
+  }
+}
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index ded3bfded868e..9f44380781e17 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -144,7 +144,6 @@ export default () => {
   mountMultipleBoardsSwitcher({
     fullPath: $boardApp.dataset.fullPath,
     rootPath: $boardApp.dataset.boardsEndpoint,
-    recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint,
     allowScopedLabels: $boardApp.dataset.scopedLabels,
     labelsManagePath: $boardApp.dataset.labelsManagePath,
   });
diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
index 26dd8b99f980a..3838b4f2a83d2 100644
--- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
+++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
@@ -24,7 +24,6 @@ export default (params = {}) => {
     provide: {
       fullPath: params.fullPath,
       rootPath: params.rootPath,
-      recentBoardsEndpoint: params.recentBoardsEndpoint,
       allowScopedLabels: params.allowScopedLabels,
       labelsManagePath: params.labelsManagePath,
       allowLabelCreate: parseBoolean(dataset.canAdminBoard),
diff --git a/ee/app/assets/javascripts/boards/components/boards_selector.vue b/ee/app/assets/javascripts/boards/components/boards_selector.vue
index c37b087659e50..c8e0ebe5f324f 100644
--- a/ee/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/ee/app/assets/javascripts/boards/components/boards_selector.vue
@@ -52,7 +52,8 @@ export default {
         },
         query: this.isEpicBoard ? this.epicBoardQuery : this.boardQuery,
         loadingKey: 'loadingBoards',
-        update: this.isEpicBoard ? this.epicBoardUpdate : this.boardUpdate,
+        update: (data) =>
+          this.isEpicBoard ? this.epicBoardUpdate(data) : this.boardUpdate(data, 'boards'),
       });
 
       if (!this.isEpicBoard) {
diff --git a/ee/spec/frontend/boards/components/boards_selector_spec.js b/ee/spec/frontend/boards/components/boards_selector_spec.js
index 55c301a7a53a9..a89a96a045cd3 100644
--- a/ee/spec/frontend/boards/components/boards_selector_spec.js
+++ b/ee/spec/frontend/boards/components/boards_selector_spec.js
@@ -1,46 +1,35 @@
-import { GlDropdown, GlLoadingIcon, GlDropdownSectionHeader } from '@gitlab/ui';
+import { GlDropdown } from '@gitlab/ui';
 import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
 import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
 import Vuex from 'vuex';
 import BoardsSelector from 'ee/boards/components/boards_selector.vue';
 import { BoardType } from '~/boards/constants';
 import epicBoardQuery from 'ee/boards/graphql/epic_board.query.graphql';
+import epicBoardsQuery from 'ee/boards/graphql/epic_boards.query.graphql';
 import groupBoardQuery from '~/boards/graphql/group_board.query.graphql';
 import projectBoardQuery from '~/boards/graphql/project_board.query.graphql';
+import groupBoardsQuery from '~/boards/graphql/group_boards.query.graphql';
+import projectBoardsQuery from '~/boards/graphql/project_boards.query.graphql';
 import defaultStore from '~/boards/stores';
 import { TEST_HOST } from 'spec/test_constants';
-import axios from '~/lib/utils/axios_utils';
 import createMockApollo from 'helpers/mock_apollo_helper';
-import { mockGroupBoardResponse, mockProjectBoardResponse } from 'jest/boards/mock_data';
-import { mockEpicBoardResponse } from '../mock_data';
+import {
+  mockGroupBoardResponse,
+  mockProjectBoardResponse,
+  mockGroupAllBoardsResponse,
+  mockProjectAllBoardsResponse,
+} from 'jest/boards/mock_data';
+import { mockEpicBoardResponse, mockEpicBoardsResponse } from '../mock_data';
 
 const throttleDuration = 1;
 
 Vue.use(VueApollo);
 
-function boardGenerator(n) {
-  return new Array(n).fill().map((board, index) => {
-    const id = `${index}`;
-    const name = `board${id}`;
-
-    return {
-      id,
-      name,
-    };
-  });
-}
-
 describe('BoardsSelector', () => {
   let wrapper;
-  let allBoardsResponse;
-  let recentBoardsResponse;
-  let mock;
   let fakeApollo;
   let store;
-  const boards = boardGenerator(20);
-  const recentBoards = boardGenerator(5);
 
   const createStore = ({
     isGroupBoard = false,
@@ -63,20 +52,26 @@ describe('BoardsSelector', () => {
     });
   };
 
-  const getDropdownItems = () => wrapper.findAll('.js-dropdown-item');
-  const getDropdownHeaders = () => wrapper.findAllComponents(GlDropdownSectionHeader);
-  const getLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-  const findDropdown = () => wrapper.findComponent(GlDropdown);
+  const findDropdown = () => wrapper.find(GlDropdown);
 
   const projectBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockProjectBoardResponse);
   const groupBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockGroupBoardResponse);
   const epicBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockEpicBoardResponse);
 
+  const projectBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockProjectAllBoardsResponse);
+  const groupBoardsQueryHandlerSuccess = jest.fn().mockResolvedValue(mockGroupAllBoardsResponse);
+  const epicBoardsQueryHandlerSuccess = jest.fn().mockResolvedValue(mockEpicBoardsResponse);
+
   const createComponent = () => {
     fakeApollo = createMockApollo([
       [projectBoardQuery, projectBoardQueryHandlerSuccess],
       [groupBoardQuery, groupBoardQueryHandlerSuccess],
       [epicBoardQuery, epicBoardQueryHandlerSuccess],
+      [projectBoardsQuery, projectBoardsQueryHandlerSuccess],
+      [groupBoardsQuery, groupBoardsQueryHandlerSuccess],
+      [epicBoardsQuery, epicBoardsQueryHandlerSuccess],
     ]);
 
     wrapper = mount(BoardsSelector, {
@@ -94,92 +89,44 @@ describe('BoardsSelector', () => {
       attachTo: document.body,
       provide: {
         fullPath: '',
-        recentBoardsEndpoint: `${TEST_HOST}/recent`,
       },
     });
-
-    wrapper.vm.$apollo.addSmartQuery = jest.fn((_, options) => {
-      // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-      // eslint-disable-next-line no-restricted-syntax
-      wrapper.setData({
-        [options.loadingKey]: true,
-      });
-    });
   };
 
   afterEach(() => {
     wrapper.destroy();
-    wrapper = null;
     fakeApollo = null;
     store = null;
-    mock.restore();
   });
 
-  describe('fetching all board', () => {
+  describe('fetching all boards', () => {
     beforeEach(() => {
-      mock = new MockAdapter(axios);
-
-      allBoardsResponse = Promise.resolve({
-        data: {
-          group: {
-            boards: {
-              edges: boards.map((board) => ({ node: board })),
-            },
-          },
+      it.each`
+        boardType            | isEpicBoard | queryHandler                        | notCalledHandler
+        ${BoardType.group}   | ${false}    | ${groupBoardsQueryHandlerSuccess}   | ${projectBoardsQueryHandlerSuccess}
+        ${BoardType.project} | ${false}    | ${projectBoardsQueryHandlerSuccess} | ${groupBoardsQueryHandlerSuccess}
+        ${BoardType.group}   | ${true}     | ${epicBoardsQueryHandlerSuccess}    | ${groupBoardsQueryHandlerSuccess}
+      `(
+        'fetches $boardType boards when isEpicBoard is $isEpicBoard',
+        async ({ boardType, isEpicBoard, queryHandler, notCalledHandler }) => {
+          createStore({
+            isProjectBoard: boardType === BoardType.project,
+            isGroupBoard: boardType === BoardType.group,
+            isEpicBoard,
+          });
+          createComponent();
+
+          await nextTick();
+
+          // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
+          findDropdown().vm.$emit('show');
+
+          await nextTick();
+
+          expect(queryHandler).toHaveBeenCalled();
+          expect(notCalledHandler).not.toHaveBeenCalled();
         },
-      });
-      recentBoardsResponse = Promise.resolve({
-        data: recentBoards,
-      });
-
-      createStore();
-      createComponent();
-
-      mock.onGet(`${TEST_HOST}/recent`).replyOnce(200, recentBoards);
-    });
-
-    describe('loading', () => {
-      beforeEach(async () => {
-        // Wait for current board to be loaded
-        await nextTick();
-
-        // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
-        findDropdown().vm.$emit('show');
-      });
-
-      // we are testing loading state, so don't resolve responses until after the tests
-      afterEach(async () => {
-        await Promise.all([allBoardsResponse, recentBoardsResponse]);
-        await nextTick();
-      });
-
-      it('shows loading spinner', () => {
-        expect(getDropdownHeaders()).toHaveLength(0);
-        expect(getDropdownItems()).toHaveLength(0);
-        expect(getLoadingIcon().exists()).toBe(true);
-      });
-    });
-
-    describe('loaded', () => {
-      beforeEach(async () => {
-        // Wait for current board to be loaded
-        await nextTick();
-
-        // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
-        findDropdown().vm.$emit('show');
-
-        // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-        // eslint-disable-next-line no-restricted-syntax
-        await wrapper.setData({
-          loadingBoards: false,
-          loadingRecentBoards: false,
-        });
-      });
-
-      it('hides loading spinner', async () => {
-        await nextTick();
-        expect(getLoadingIcon().exists()).toBe(false);
-      });
+      );
     });
   });
 
diff --git a/ee/spec/frontend/boards/mock_data.js b/ee/spec/frontend/boards/mock_data.js
index b5d9a197bc454..83034e638159b 100644
--- a/ee/spec/frontend/boards/mock_data.js
+++ b/ee/spec/frontend/boards/mock_data.js
@@ -21,6 +21,27 @@ export const mockEpicBoardResponse = {
   },
 };
 
+export const mockEpicBoardsResponse = {
+  data: {
+    group: {
+      id: 'gid://gitlab/Group/114',
+      epicBoards: {
+        nodes: [
+          {
+            id: 'gid://gitlab/Boards::EpicBoard/1',
+            name: 'Development',
+          },
+          {
+            id: 'gid://gitlab/Boards::EpicBoard/2',
+            name: 'Marketing',
+          },
+        ],
+      },
+      __typename: 'Group',
+    },
+  },
+};
+
 export const mockLabel = {
   id: 'gid://gitlab/GroupLabel/121',
   title: 'To Do',
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index 9cf7c5774bf95..1ee318cbe279e 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -1,43 +1,40 @@
 import { GlDropdown, GlLoadingIcon, GlDropdownSectionHeader } from '@gitlab/ui';
 import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
 import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
 import Vuex from 'vuex';
 import { TEST_HOST } from 'spec/test_constants';
 import BoardsSelector from '~/boards/components/boards_selector.vue';
+import { BoardType } from '~/boards/constants';
 import groupBoardQuery from '~/boards/graphql/group_board.query.graphql';
 import projectBoardQuery from '~/boards/graphql/project_board.query.graphql';
+import groupBoardsQuery from '~/boards/graphql/group_boards.query.graphql';
+import projectBoardsQuery from '~/boards/graphql/project_boards.query.graphql';
+import groupRecentBoardsQuery from '~/boards/graphql/group_recent_boards.query.graphql';
+import projectRecentBoardsQuery from '~/boards/graphql/project_recent_boards.query.graphql';
 import defaultStore from '~/boards/stores';
-import axios from '~/lib/utils/axios_utils';
 import createMockApollo from 'helpers/mock_apollo_helper';
-import { mockGroupBoardResponse, mockProjectBoardResponse } from '../mock_data';
+import {
+  mockGroupBoardResponse,
+  mockProjectBoardResponse,
+  mockGroupAllBoardsResponse,
+  mockProjectAllBoardsResponse,
+  mockGroupRecentBoardsResponse,
+  mockProjectRecentBoardsResponse,
+  mockSmallGroupAllBoardsResponse,
+  mockEmptyGroupRecentBoardsResponse,
+  boards,
+  recentIssueBoards,
+} from '../mock_data';
 
 const throttleDuration = 1;
 
 Vue.use(VueApollo);
 
-function boardGenerator(n) {
-  return new Array(n).fill().map((board, index) => {
-    const id = `${index}`;
-    const name = `board${id}`;
-
-    return {
-      id,
-      name,
-    };
-  });
-}
-
 describe('BoardsSelector', () => {
   let wrapper;
-  let allBoardsResponse;
-  let recentBoardsResponse;
-  let mock;
   let fakeApollo;
   let store;
-  const boards = boardGenerator(20);
-  const recentBoards = boardGenerator(5);
 
   const createStore = ({ isGroupBoard = false, isProjectBoard = false } = {}) => {
     store = new Vuex.Store({
@@ -70,10 +67,36 @@ describe('BoardsSelector', () => {
   const projectBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockProjectBoardResponse);
   const groupBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockGroupBoardResponse);
 
-  const createComponent = () => {
+  const projectBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockProjectAllBoardsResponse);
+  const groupBoardsQueryHandlerSuccess = jest.fn().mockResolvedValue(mockGroupAllBoardsResponse);
+
+  const projectRecentBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockProjectRecentBoardsResponse);
+  const groupRecentBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockGroupRecentBoardsResponse);
+
+  const smallBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockSmallGroupAllBoardsResponse);
+  const emptyRecentBoardsQueryHandlerSuccess = jest
+    .fn()
+    .mockResolvedValue(mockEmptyGroupRecentBoardsResponse);
+
+  const createComponent = ({
+    groupBoardsQueryHandler = groupBoardsQueryHandlerSuccess,
+    groupRecentBoardsQueryHandler = groupRecentBoardsQueryHandlerSuccess,
+  } = {}) => {
     fakeApollo = createMockApollo([
       [projectBoardQuery, projectBoardQueryHandlerSuccess],
       [groupBoardQuery, groupBoardQueryHandlerSuccess],
+      [projectBoardsQuery, projectBoardsQueryHandlerSuccess],
+      [groupBoardsQuery, groupBoardsQueryHandler],
+      [projectRecentBoardsQuery, projectRecentBoardsQueryHandlerSuccess],
+      [groupRecentBoardsQuery, groupRecentBoardsQueryHandler],
     ]);
 
     wrapper = mount(BoardsSelector, {
@@ -91,67 +114,33 @@ describe('BoardsSelector', () => {
       attachTo: document.body,
       provide: {
         fullPath: '',
-        recentBoardsEndpoint: `${TEST_HOST}/recent`,
       },
     });
-
-    wrapper.vm.$apollo.addSmartQuery = jest.fn((_, options) => {
-      // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-      // eslint-disable-next-line no-restricted-syntax
-      wrapper.setData({
-        [options.loadingKey]: true,
-      });
-    });
   };
 
   afterEach(() => {
     wrapper.destroy();
-    wrapper = null;
-    mock.restore();
   });
 
-  describe('fetching all boards', () => {
+  describe('template', () => {
     beforeEach(() => {
-      mock = new MockAdapter(axios);
-
-      allBoardsResponse = Promise.resolve({
-        data: {
-          group: {
-            boards: {
-              edges: boards.map((board) => ({ node: board })),
-            },
-          },
-        },
-      });
-      recentBoardsResponse = Promise.resolve({
-        data: recentBoards,
-      });
-
-      createStore();
+      createStore({ isGroupBoard: true });
       createComponent();
-
-      mock.onGet(`${TEST_HOST}/recent`).replyOnce(200, recentBoards);
     });
 
     describe('loading', () => {
-      beforeEach(async () => {
-        // Wait for current board to be loaded
-        await nextTick();
-
-        // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
-        findDropdown().vm.$emit('show');
-      });
-
       // we are testing loading state, so don't resolve responses until after the tests
       afterEach(async () => {
-        await Promise.all([allBoardsResponse, recentBoardsResponse]);
         await nextTick();
       });
 
       it('shows loading spinner', () => {
+        // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
+        findDropdown().vm.$emit('show');
+
+        expect(getLoadingIcon().exists()).toBe(true);
         expect(getDropdownHeaders()).toHaveLength(0);
         expect(getDropdownItems()).toHaveLength(0);
-        expect(getLoadingIcon().exists()).toBe(true);
       });
     });
 
@@ -163,16 +152,13 @@ describe('BoardsSelector', () => {
         // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
         findDropdown().vm.$emit('show');
 
-        // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-        // eslint-disable-next-line no-restricted-syntax
-        await wrapper.setData({
-          loadingBoards: false,
-          loadingRecentBoards: false,
-        });
-        await Promise.all([allBoardsResponse, recentBoardsResponse]);
         await nextTick();
       });
 
+      it('fetches all issue boards', () => {
+        expect(groupBoardsQueryHandlerSuccess).toHaveBeenCalled();
+      });
+
       it('hides loading spinner', async () => {
         await nextTick();
         expect(getLoadingIcon().exists()).toBe(false);
@@ -180,22 +166,17 @@ describe('BoardsSelector', () => {
 
       describe('filtering', () => {
         beforeEach(async () => {
-          // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-          // eslint-disable-next-line no-restricted-syntax
-          wrapper.setData({
-            boards,
-          });
-
           await nextTick();
         });
 
         it('shows all boards without filtering', () => {
-          expect(getDropdownItems()).toHaveLength(boards.length + recentBoards.length);
+          expect(getDropdownItems()).toHaveLength(boards.length + recentIssueBoards.length);
         });
 
         it('shows only matching boards when filtering', async () => {
           const filterTerm = 'board1';
-          const expectedCount = boards.filter((board) => board.name.includes(filterTerm)).length;
+          const expectedCount = boards.filter((board) => board.node.name.includes(filterTerm))
+            .length;
 
           fillSearchBox(filterTerm);
 
@@ -214,33 +195,20 @@ describe('BoardsSelector', () => {
 
       describe('recent boards section', () => {
         it('shows only when boards are greater than 10', async () => {
-          // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-          // eslint-disable-next-line no-restricted-syntax
-          wrapper.setData({
-            boards,
-          });
-
           await nextTick();
+          expect(groupRecentBoardsQueryHandlerSuccess).toHaveBeenCalled();
           expect(getDropdownHeaders()).toHaveLength(2);
         });
 
         it('does not show when boards are less than 10', async () => {
-          // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-          // eslint-disable-next-line no-restricted-syntax
-          wrapper.setData({
-            boards: boards.slice(0, 5),
-          });
+          createComponent({ groupBoardsQueryHandler: smallBoardsQueryHandlerSuccess });
 
           await nextTick();
           expect(getDropdownHeaders()).toHaveLength(0);
         });
 
-        it('does not show when recentBoards api returns empty array', async () => {
-          // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
-          // eslint-disable-next-line no-restricted-syntax
-          wrapper.setData({
-            recentBoards: [],
-          });
+        it('does not show when recentIssueBoards api returns empty array', async () => {
+          createComponent({ groupRecentBoardsQueryHandler: emptyRecentBoardsQueryHandlerSuccess });
 
           await nextTick();
           expect(getDropdownHeaders()).toHaveLength(0);
@@ -256,15 +224,39 @@ describe('BoardsSelector', () => {
     });
   });
 
+  describe('fetching all boards', () => {
+    it.each`
+      boardType            | queryHandler                        | notCalledHandler
+      ${BoardType.group}   | ${groupBoardsQueryHandlerSuccess}   | ${projectBoardsQueryHandlerSuccess}
+      ${BoardType.project} | ${projectBoardsQueryHandlerSuccess} | ${groupBoardsQueryHandlerSuccess}
+    `('fetches $boardType boards', async ({ boardType, queryHandler, notCalledHandler }) => {
+      createStore({
+        isProjectBoard: boardType === BoardType.project,
+        isGroupBoard: boardType === BoardType.group,
+      });
+      createComponent();
+
+      await nextTick();
+
+      // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
+      findDropdown().vm.$emit('show');
+
+      await nextTick();
+
+      expect(queryHandler).toHaveBeenCalled();
+      expect(notCalledHandler).not.toHaveBeenCalled();
+    });
+  });
+
   describe('fetching current board', () => {
     it.each`
-      boardType    | queryHandler                       | notCalledHandler
-      ${'group'}   | ${groupBoardQueryHandlerSuccess}   | ${projectBoardQueryHandlerSuccess}
-      ${'project'} | ${projectBoardQueryHandlerSuccess} | ${groupBoardQueryHandlerSuccess}
+      boardType            | queryHandler                       | notCalledHandler
+      ${BoardType.group}   | ${groupBoardQueryHandlerSuccess}   | ${projectBoardQueryHandlerSuccess}
+      ${BoardType.project} | ${projectBoardQueryHandlerSuccess} | ${groupBoardQueryHandlerSuccess}
     `('fetches $boardType board', async ({ boardType, queryHandler, notCalledHandler }) => {
       createStore({
-        isProjectBoard: boardType === 'project',
-        isGroupBoard: boardType === 'group',
+        isProjectBoard: boardType === BoardType.project,
+        isGroupBoard: boardType === BoardType.group,
       });
       createComponent();
 
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 254965827072e..ec6c567ded488 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -29,6 +29,84 @@ export const listObj = {
   },
 };
 
+function boardGenerator(n) {
+  return new Array(n).fill().map((board, index) => {
+    const id = `${index}`;
+    const name = `board${id}`;
+
+    return {
+      node: {
+        id,
+        name,
+        weight: 0,
+      },
+    };
+  });
+}
+
+export const boards = boardGenerator(20);
+export const recentIssueBoards = boardGenerator(5);
+
+export const mockSmallGroupAllBoardsResponse = {
+  data: {
+    group: {
+      id: 'gid://gitlab/Group/114',
+      boards: { edges: boardGenerator(3) },
+      __typename: 'Group',
+    },
+  },
+};
+
+export const mockEmptyGroupRecentBoardsResponse = {
+  data: {
+    group: {
+      id: 'gid://gitlab/Group/114',
+      recentIssueBoards: { edges: [] },
+      __typename: 'Group',
+    },
+  },
+};
+
+export const mockGroupAllBoardsResponse = {
+  data: {
+    group: {
+      id: 'gid://gitlab/Group/114',
+      boards: { edges: boards },
+      __typename: 'Group',
+    },
+  },
+};
+
+export const mockProjectAllBoardsResponse = {
+  data: {
+    project: {
+      id: 'gid://gitlab/Project/1',
+      boards: { edges: boards },
+      __typename: 'Project',
+    },
+  },
+};
+
+export const mockGroupRecentBoardsResponse = {
+  data: {
+    group: {
+      id: 'gid://gitlab/Group/114',
+      recentIssueBoards: { edges: recentIssueBoards },
+      __typename: 'Group',
+    },
+  },
+};
+
+export const mockProjectRecentBoardsResponse = {
+  data: {
+    project: {
+      id: 'gid://gitlab/Project/1',
+      recentIssueBoards: { edges: recentIssueBoards },
+      __typename: 'Project',
+    },
+  },
+};
+
 export const mockGroupBoardResponse = {
   data: {
     workspace: {
-- 
GitLab