Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/boards')
-rw-r--r--spec/frontend/boards/components/board_card_spec.js4
-rw-r--r--spec/frontend/boards/components/board_filtered_search_spec.js33
-rw-r--r--spec/frontend/boards/components/board_form_spec.js18
-rw-r--r--spec/frontend/boards/components/boards_selector_spec.js251
-rw-r--r--spec/frontend/boards/components/issue_board_filtered_search_spec.js57
-rw-r--r--spec/frontend/boards/components/new_board_button_spec.js75
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js1
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js11
-rw-r--r--spec/frontend/boards/mock_data.js87
-rw-r--r--spec/frontend/boards/stores/actions_spec.js72
10 files changed, 437 insertions, 172 deletions
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index 25ec568e48d..5742dfdc5d2 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -64,12 +64,12 @@ describe('Board card', () => {
};
const selectCard = async () => {
- wrapper.trigger('mouseup');
+ wrapper.trigger('click');
await wrapper.vm.$nextTick();
};
const multiSelectCard = async () => {
- wrapper.trigger('mouseup', { ctrlKey: true });
+ wrapper.trigger('click', { ctrlKey: true });
await wrapper.vm.$nextTick();
};
diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js
index dc93890f27a..b858d6e95a0 100644
--- a/spec/frontend/boards/components/board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/board_filtered_search_spec.js
@@ -7,6 +7,7 @@ import { __ } from '~/locale';
import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
+import { createStore } from '~/boards/stores';
Vue.use(Vuex);
@@ -42,17 +43,13 @@ describe('BoardFilteredSearch', () => {
},
];
- const createComponent = ({ initialFilterParams = {} } = {}) => {
- store = new Vuex.Store({
- actions: {
- performSearch: jest.fn(),
- },
- });
-
+ const createComponent = ({ initialFilterParams = {}, props = {} } = {}) => {
+ store = createStore();
wrapper = shallowMount(BoardFilteredSearch, {
provide: { initialFilterParams, fullPath: '' },
store,
propsData: {
+ ...props,
tokens,
},
});
@@ -68,11 +65,7 @@ describe('BoardFilteredSearch', () => {
beforeEach(() => {
createComponent();
- jest.spyOn(store, 'dispatch');
- });
-
- it('renders FilteredSearch', () => {
- expect(findFilteredSearch().exists()).toBe(true);
+ jest.spyOn(store, 'dispatch').mockImplementation();
});
it('passes the correct tokens to FilteredSearch', () => {
@@ -99,6 +92,22 @@ describe('BoardFilteredSearch', () => {
});
});
+ describe('when eeFilters is not empty', () => {
+ it('passes the correct initialFilterValue to FitleredSearchBarRoot', () => {
+ createComponent({ props: { eeFilters: { labelName: ['label'] } } });
+
+ expect(findFilteredSearch().props('initialFilterValue')).toEqual([
+ { type: 'label_name', value: { data: 'label', operator: '=' } },
+ ]);
+ });
+ });
+
+ it('renders FilteredSearch', () => {
+ createComponent();
+
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
describe('when searching', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index 52f1907654a..692fd3ec555 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -1,7 +1,6 @@
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import BoardForm from '~/boards/components/board_form.vue';
@@ -18,21 +17,18 @@ jest.mock('~/lib/utils/url_utility', () => ({
}));
const currentBoard = {
- id: 1,
+ id: 'gid://gitlab/Board/1',
name: 'test',
labels: [],
- milestone_id: undefined,
+ milestone: {},
assignee: {},
- assignee_id: undefined,
weight: null,
- hide_backlog_list: false,
- hide_closed_list: false,
+ hideBacklogList: false,
+ hideClosedList: false,
};
const defaultProps = {
canAdminBoard: false,
- labelsPath: `${TEST_HOST}/labels/path`,
- labelsWebUrl: `${TEST_HOST}/-/labels`,
currentBoard,
currentPage: '',
};
@@ -252,7 +248,7 @@ describe('BoardForm', () => {
mutation: updateBoardMutation,
variables: {
input: expect.objectContaining({
- id: `gid://gitlab/Board/${currentBoard.id}`,
+ id: currentBoard.id,
}),
},
});
@@ -278,7 +274,7 @@ describe('BoardForm', () => {
mutation: updateBoardMutation,
variables: {
input: expect.objectContaining({
- id: `gid://gitlab/Board/${currentBoard.id}`,
+ id: currentBoard.id,
}),
},
});
@@ -326,7 +322,7 @@ describe('BoardForm', () => {
expect(mutate).toHaveBeenCalledWith({
mutation: destroyBoardMutation,
variables: {
- id: 'gid://gitlab/Board/1',
+ id: currentBoard.id,
},
});
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index bf317b51e83..c841c17a029 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -1,13 +1,22 @@
import { GlDropdown, GlLoadingIcon, GlDropdownSectionHeader } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+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 groupBoardQuery from '~/boards/graphql/group_board.query.graphql';
+import projectBoardQuery from '~/boards/graphql/project_board.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';
const throttleDuration = 1;
+Vue.use(VueApollo);
+
function boardGenerator(n) {
return new Array(n).fill().map((board, index) => {
const id = `${index}`;
@@ -25,9 +34,27 @@ describe('BoardsSelector', () => {
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({
+ ...defaultStore,
+ actions: {
+ setError: jest.fn(),
+ },
+ getters: {
+ isGroupBoard: () => isGroupBoard,
+ isProjectBoard: () => isProjectBoard,
+ },
+ state: {
+ boardType: isGroupBoard ? 'group' : 'project',
+ },
+ });
+ };
+
const fillSearchBox = (filterTerm) => {
const searchBox = wrapper.find({ ref: 'searchBox' });
const searchBoxInput = searchBox.find('input');
@@ -40,52 +67,27 @@ describe('BoardsSelector', () => {
const getLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findDropdown = () => wrapper.find(GlDropdown);
- beforeEach(() => {
- mock = new MockAdapter(axios);
- const $apollo = {
- queries: {
- boards: {
- loading: false,
- },
- },
- };
+ const projectBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockProjectBoardResponse);
+ const groupBoardQueryHandlerSuccess = jest.fn().mockResolvedValue(mockGroupBoardResponse);
- allBoardsResponse = Promise.resolve({
- data: {
- group: {
- boards: {
- edges: boards.map((board) => ({ node: board })),
- },
- },
- },
- });
- recentBoardsResponse = Promise.resolve({
- data: recentBoards,
- });
+ const createComponent = () => {
+ fakeApollo = createMockApollo([
+ [projectBoardQuery, projectBoardQueryHandlerSuccess],
+ [groupBoardQuery, groupBoardQueryHandlerSuccess],
+ ]);
wrapper = mount(BoardsSelector, {
+ store,
+ apolloProvider: fakeApollo,
propsData: {
throttleDuration,
- currentBoard: {
- id: 1,
- name: 'Development',
- milestone_id: null,
- weight: null,
- assignee_id: null,
- labels: [],
- },
boardBaseUrl: `${TEST_HOST}/board/base/url`,
hasMissingBoards: false,
canAdminBoard: true,
multipleIssueBoardsAvailable: true,
- labelsPath: `${TEST_HOST}/labels/path`,
- labelsWebUrl: `${TEST_HOST}/labels`,
- projectId: 42,
- groupId: 19,
scopedIssueBoardFeatureEnabled: true,
weights: [],
},
- mocks: { $apollo },
attachTo: document.body,
provide: {
fullPath: '',
@@ -98,12 +100,7 @@ describe('BoardsSelector', () => {
[options.loadingKey]: true,
});
});
-
- mock.onGet(`${TEST_HOST}/recent`).replyOnce(200, recentBoards);
-
- // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
- findDropdown().vm.$emit('show');
- });
+ };
afterEach(() => {
wrapper.destroy();
@@ -111,104 +108,158 @@ describe('BoardsSelector', () => {
mock.restore();
});
- describe('loading', () => {
- // we are testing loading state, so don't resolve responses until after the tests
- afterEach(() => {
- return Promise.all([allBoardsResponse, recentBoardsResponse]).then(() => nextTick());
- });
+ describe('fetching all boards', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
- it('shows loading spinner', () => {
- expect(getDropdownHeaders()).toHaveLength(0);
- expect(getDropdownItems()).toHaveLength(0);
- expect(getLoadingIcon().exists()).toBe(true);
+ allBoardsResponse = Promise.resolve({
+ data: {
+ group: {
+ boards: {
+ edges: boards.map((board) => ({ node: board })),
+ },
+ },
+ },
+ });
+ recentBoardsResponse = Promise.resolve({
+ data: recentBoards,
+ });
+
+ createStore();
+ createComponent();
+
+ mock.onGet(`${TEST_HOST}/recent`).replyOnce(200, recentBoards);
});
- });
- describe('loaded', () => {
- beforeEach(async () => {
- await wrapper.setData({
- loadingBoards: false,
+ 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();
});
- return Promise.all([allBoardsResponse, recentBoardsResponse]).then(() => nextTick());
- });
- it('hides loading spinner', async () => {
- await wrapper.vm.$nextTick();
- expect(getLoadingIcon().exists()).toBe(false);
+ it('shows loading spinner', () => {
+ expect(getDropdownHeaders()).toHaveLength(0);
+ expect(getDropdownItems()).toHaveLength(0);
+ expect(getLoadingIcon().exists()).toBe(true);
+ });
});
- describe('filtering', () => {
- beforeEach(() => {
- wrapper.setData({
- boards,
- });
+ 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');
- return nextTick();
+ await wrapper.setData({
+ loadingBoards: false,
+ loadingRecentBoards: false,
+ });
+ await Promise.all([allBoardsResponse, recentBoardsResponse]);
+ await nextTick();
});
- it('shows all boards without filtering', () => {
- expect(getDropdownItems()).toHaveLength(boards.length + recentBoards.length);
+ it('hides loading spinner', async () => {
+ await nextTick();
+ expect(getLoadingIcon().exists()).toBe(false);
});
- it('shows only matching boards when filtering', () => {
- const filterTerm = 'board1';
- const expectedCount = boards.filter((board) => board.name.includes(filterTerm)).length;
+ describe('filtering', () => {
+ beforeEach(async () => {
+ wrapper.setData({
+ boards,
+ });
+
+ await nextTick();
+ });
- fillSearchBox(filterTerm);
+ it('shows all boards without filtering', () => {
+ expect(getDropdownItems()).toHaveLength(boards.length + recentBoards.length);
+ });
- return nextTick().then(() => {
+ it('shows only matching boards when filtering', async () => {
+ const filterTerm = 'board1';
+ const expectedCount = boards.filter((board) => board.name.includes(filterTerm)).length;
+
+ fillSearchBox(filterTerm);
+
+ await nextTick();
expect(getDropdownItems()).toHaveLength(expectedCount);
});
- });
- it('shows message if there are no matching boards', () => {
- fillSearchBox('does not exist');
+ it('shows message if there are no matching boards', async () => {
+ fillSearchBox('does not exist');
- return nextTick().then(() => {
+ await nextTick();
expect(getDropdownItems()).toHaveLength(0);
expect(wrapper.text().includes('No matching boards found')).toBe(true);
});
});
- });
- describe('recent boards section', () => {
- it('shows only when boards are greater than 10', () => {
- wrapper.setData({
- boards,
- });
+ describe('recent boards section', () => {
+ it('shows only when boards are greater than 10', async () => {
+ wrapper.setData({
+ boards,
+ });
- return nextTick().then(() => {
+ await nextTick();
expect(getDropdownHeaders()).toHaveLength(2);
});
- });
- it('does not show when boards are less than 10', () => {
- wrapper.setData({
- boards: boards.slice(0, 5),
- });
+ it('does not show when boards are less than 10', async () => {
+ wrapper.setData({
+ boards: boards.slice(0, 5),
+ });
- return nextTick().then(() => {
+ await nextTick();
expect(getDropdownHeaders()).toHaveLength(0);
});
- });
- it('does not show when recentBoards api returns empty array', () => {
- wrapper.setData({
- recentBoards: [],
- });
+ it('does not show when recentBoards api returns empty array', async () => {
+ wrapper.setData({
+ recentBoards: [],
+ });
- return nextTick().then(() => {
+ await nextTick();
expect(getDropdownHeaders()).toHaveLength(0);
});
- });
- it('does not show when search is active', () => {
- fillSearchBox('Random string');
+ it('does not show when search is active', async () => {
+ fillSearchBox('Random string');
- return nextTick().then(() => {
+ await nextTick();
expect(getDropdownHeaders()).toHaveLength(0);
});
});
});
});
+
+ describe('fetching current board', () => {
+ it.each`
+ boardType | queryHandler | notCalledHandler
+ ${'group'} | ${groupBoardQueryHandlerSuccess} | ${projectBoardQueryHandlerSuccess}
+ ${'project'} | ${projectBoardQueryHandlerSuccess} | ${groupBoardQueryHandlerSuccess}
+ `('fetches $boardType board', async ({ boardType, queryHandler, notCalledHandler }) => {
+ createStore({
+ isProjectBoard: boardType === 'project',
+ isGroupBoard: boardType === 'group',
+ });
+ createComponent();
+
+ await nextTick();
+
+ expect(queryHandler).toHaveBeenCalled();
+ expect(notCalledHandler).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/boards/components/issue_board_filtered_search_spec.js b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
index b6de46f8db8..45c5c87d800 100644
--- a/spec/frontend/boards/components/issue_board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue';
+import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue';
import IssueBoardFilteredSpec from '~/boards/components/issue_board_filtered_search.vue';
import issueBoardFilters from '~/boards/issue_board_filters';
import { mockTokens } from '../mock_data';
@@ -9,39 +9,60 @@ jest.mock('~/boards/issue_board_filters');
describe('IssueBoardFilter', () => {
let wrapper;
- const createComponent = () => {
+ const findBoardsFilteredSearch = () => wrapper.findComponent(BoardFilteredSearch);
+
+ const createComponent = ({ isSignedIn = false } = {}) => {
wrapper = shallowMount(IssueBoardFilteredSpec, {
- props: { fullPath: '', boardType: '' },
+ propsData: { fullPath: 'gitlab-org', boardType: 'group' },
+ provide: {
+ isSignedIn,
+ },
});
};
+ let fetchAuthorsSpy;
+ let fetchLabelsSpy;
+ beforeEach(() => {
+ fetchAuthorsSpy = jest.fn();
+ fetchLabelsSpy = jest.fn();
+
+ issueBoardFilters.mockReturnValue({
+ fetchAuthors: fetchAuthorsSpy,
+ fetchLabels: fetchLabelsSpy,
+ });
+ });
+
afterEach(() => {
wrapper.destroy();
});
describe('default', () => {
- let fetchAuthorsSpy;
- let fetchLabelsSpy;
beforeEach(() => {
- fetchAuthorsSpy = jest.fn();
- fetchLabelsSpy = jest.fn();
-
- issueBoardFilters.mockReturnValue({
- fetchAuthors: fetchAuthorsSpy,
- fetchLabels: fetchLabelsSpy,
- });
-
createComponent();
});
it('finds BoardFilteredSearch', () => {
- expect(wrapper.find(BoardFilteredSearch).exists()).toBe(true);
+ expect(findBoardsFilteredSearch().exists()).toBe(true);
});
- it('passes the correct tokens to BoardFilteredSearch', () => {
- const tokens = mockTokens(fetchLabelsSpy, fetchAuthorsSpy, wrapper.vm.fetchMilestones);
+ it.each`
+ isSignedIn
+ ${true}
+ ${false}
+ `(
+ 'passes the correct tokens to BoardFilteredSearch when user sign in is $isSignedIn',
+ ({ isSignedIn }) => {
+ createComponent({ isSignedIn });
- expect(wrapper.find(BoardFilteredSearch).props('tokens')).toEqual(tokens);
- });
+ const tokens = mockTokens(
+ fetchLabelsSpy,
+ fetchAuthorsSpy,
+ wrapper.vm.fetchMilestones,
+ isSignedIn,
+ );
+
+ expect(findBoardsFilteredSearch().props('tokens')).toEqual(tokens);
+ },
+ );
});
});
diff --git a/spec/frontend/boards/components/new_board_button_spec.js b/spec/frontend/boards/components/new_board_button_spec.js
new file mode 100644
index 00000000000..075fe225ec2
--- /dev/null
+++ b/spec/frontend/boards/components/new_board_button_spec.js
@@ -0,0 +1,75 @@
+import { mount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import NewBoardButton from '~/boards/components/new_board_button.vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { stubExperiments } from 'helpers/experimentation_helper';
+import eventHub from '~/boards/eventhub';
+
+const FEATURE = 'prominent_create_board_btn';
+
+describe('NewBoardButton', () => {
+ let wrapper;
+
+ const createComponent = (args = {}) =>
+ extendedWrapper(
+ mount(NewBoardButton, {
+ provide: {
+ canAdminBoard: true,
+ multipleIssueBoardsAvailable: true,
+ ...args,
+ },
+ }),
+ );
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('control variant', () => {
+ beforeAll(() => {
+ stubExperiments({ [FEATURE]: 'control' });
+ });
+
+ it('renders nothing', () => {
+ wrapper = createComponent();
+
+ expect(wrapper.text()).toBe('');
+ });
+ });
+
+ describe('candidate variant', () => {
+ beforeAll(() => {
+ stubExperiments({ [FEATURE]: 'candidate' });
+ });
+
+ it('renders New board button when `candidate` variant', () => {
+ wrapper = createComponent();
+
+ expect(wrapper.text()).toBe('New board');
+ });
+
+ it('renders nothing when `canAdminBoard` is `false`', () => {
+ wrapper = createComponent({ canAdminBoard: false });
+
+ expect(wrapper.find(GlButton).exists()).toBe(false);
+ });
+
+ it('renders nothing when `multipleIssueBoardsAvailable` is `false`', () => {
+ wrapper = createComponent({ multipleIssueBoardsAvailable: false });
+
+ expect(wrapper.find(GlButton).exists()).toBe(false);
+ });
+
+ it('emits `showBoardModal` when button is clicked', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation();
+
+ wrapper = createComponent();
+
+ wrapper.find(GlButton).vm.$emit('click', { preventDefault: () => {} });
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('showBoardModal', 'new');
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js
index 60474767f2d..fb9d823107e 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js
@@ -105,6 +105,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
describe('when labels are updated over existing labels', () => {
const testLabelsPayload = [
{ id: 5, set: true },
+ { id: 6, set: false },
{ id: 7, set: true },
];
const expectedLabels = [{ id: 5 }, { id: 7 }];
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
index 8847f626c1f..6e1b528babc 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
@@ -14,8 +14,8 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
let store;
const findNotificationHeader = () => wrapper.find("[data-testid='notification-header-text']");
- const findToggle = () => wrapper.find(GlToggle);
- const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findToggle = () => wrapper.findComponent(GlToggle);
+ const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const createComponent = (activeBoardItem = { ...mockActiveIssue }) => {
store = createStore();
@@ -32,7 +32,6 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
afterEach(() => {
wrapper.destroy();
- wrapper = null;
store = null;
jest.clearAllMocks();
});
@@ -104,7 +103,7 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
expect(findGlLoadingIcon().exists()).toBe(false);
- findToggle().trigger('click');
+ findToggle().vm.$emit('change');
await wrapper.vm.$nextTick();
@@ -129,7 +128,7 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
expect(findGlLoadingIcon().exists()).toBe(false);
- findToggle().trigger('click');
+ findToggle().vm.$emit('change');
await wrapper.vm.$nextTick();
@@ -152,7 +151,7 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
});
jest.spyOn(wrapper.vm, 'setError').mockImplementation(() => {});
- findToggle().trigger('click');
+ findToggle().vm.$emit('change');
await wrapper.vm.$nextTick();
expect(wrapper.vm.setError).toHaveBeenCalled();
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 6a4f344bbfb..8fcad99f8a7 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -4,6 +4,7 @@ import { ListType } from '~/boards/constants';
import { __ } from '~/locale';
import { DEFAULT_MILESTONES_GRAPHQL } from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
+import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
@@ -12,6 +13,7 @@ export const boardObj = {
id: 1,
name: 'test',
milestone_id: null,
+ labels: [],
};
export const listObj = {
@@ -29,17 +31,27 @@ export const listObj = {
},
};
-export const listObjDuplicate = {
- id: listObj.id,
- position: 1,
- title: 'Test',
- list_type: 'label',
- weight: 3,
- label: {
- id: listObj.label.id,
- title: 'Test',
- color: '#ff0000',
- description: 'testing;',
+export const mockGroupBoardResponse = {
+ data: {
+ workspace: {
+ board: {
+ id: 'gid://gitlab/Board/1',
+ name: 'Development',
+ },
+ __typename: 'Group',
+ },
+ },
+};
+
+export const mockProjectBoardResponse = {
+ data: {
+ workspace: {
+ board: {
+ id: 'gid://gitlab/Board/2',
+ name: 'Development',
+ },
+ __typename: 'Project',
+ },
},
};
@@ -538,7 +550,16 @@ export const mockMoveData = {
...mockMoveIssueParams,
};
-export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
+export const mockEmojiToken = {
+ type: 'my_reaction_emoji',
+ icon: 'thumb-up',
+ title: 'My-Reaction',
+ unique: true,
+ token: EmojiToken,
+ fetchEmojis: expect.any(Function),
+};
+
+export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, hasEmoji) => [
{
icon: 'user',
title: __('Assignee'),
@@ -579,6 +600,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
symbol: '~',
fetchLabels,
},
+ ...(hasEmoji ? [mockEmojiToken] : []),
{
icon: 'clock',
title: __('Milestone'),
@@ -593,7 +615,6 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
icon: 'issues',
title: __('Type'),
type: 'types',
- operators: [{ value: '=', description: 'is' }],
token: GlFilteredSearchToken,
unique: true,
options: [
@@ -609,3 +630,43 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
unique: true,
},
];
+
+export const mockLabel1 = {
+ id: 'gid://gitlab/GroupLabel/121',
+ title: 'To Do',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabel2 = {
+ id: 'gid://gitlab/GroupLabel/122',
+ title: 'Doing',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockProjectLabelsResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Project/1',
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const mockGroupLabelsResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Group/1',
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ },
+ __typename: 'Group',
+ },
+ },
+};
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index 0b90912a584..e245325b956 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -27,6 +27,7 @@ import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql'
import actions from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import mutations from '~/boards/stores/mutations';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import {
mockLists,
@@ -1572,12 +1573,13 @@ describe('setActiveIssueLabels', () => {
const getters = { activeBoardItem: mockIssue };
const testLabelIds = labels.map((label) => label.id);
const input = {
- addLabelIds: testLabelIds,
+ labelIds: testLabelIds,
removeLabelIds: [],
projectPath: 'h/b',
+ labels,
};
- it('should assign labels on success, and sets loading state for labels', (done) => {
+ it('should assign labels on success', (done) => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } });
@@ -1594,14 +1596,6 @@ describe('setActiveIssueLabels', () => {
{ ...state, ...getters },
[
{
- type: types.SET_LABELS_LOADING,
- payload: true,
- },
- {
- type: types.SET_LABELS_LOADING,
- payload: false,
- },
- {
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
@@ -1618,6 +1612,64 @@ describe('setActiveIssueLabels', () => {
await expect(actions.setActiveIssueLabels({ getters }, input)).rejects.toThrow(Error);
});
+
+ describe('labels_widget FF on', () => {
+ beforeEach(() => {
+ window.gon = {
+ features: { labelsWidget: true },
+ };
+
+ getters.activeBoardItem = { ...mockIssue, labels };
+ });
+
+ afterEach(() => {
+ window.gon = {
+ features: {},
+ };
+ });
+
+ it('should assign labels', () => {
+ const payload = {
+ itemId: getters.activeBoardItem.id,
+ prop: 'labels',
+ value: labels,
+ };
+
+ testAction(
+ actions.setActiveIssueLabels,
+ input,
+ { ...state, ...getters },
+ [
+ {
+ type: types.UPDATE_BOARD_ITEM_BY_ID,
+ payload,
+ },
+ ],
+ [],
+ );
+ });
+
+ it('should remove label', () => {
+ const payload = {
+ itemId: getters.activeBoardItem.id,
+ prop: 'labels',
+ value: [labels[1]],
+ };
+
+ testAction(
+ actions.setActiveIssueLabels,
+ { ...input, removeLabelIds: [getIdFromGraphQLId(labels[0].id)] },
+ { ...state, ...getters },
+ [
+ {
+ type: types.UPDATE_BOARD_ITEM_BY_ID,
+ payload,
+ },
+ ],
+ [],
+ );
+ });
+ });
});
describe('setActiveItemSubscribed', () => {