summaryrefslogtreecommitdiff
path: root/spec/frontend/boards
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 09:55:51 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 09:55:51 +0000
commite8d2c2579383897a1dd7f9debd359abe8ae8373d (patch)
treec42be41678c2586d49a75cabce89322082698334 /spec/frontend/boards
parentfc845b37ec3a90aaa719975f607740c22ba6a113 (diff)
downloadgitlab-ce-e8d2c2579383897a1dd7f9debd359abe8ae8373d.tar.gz
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'spec/frontend/boards')
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js126
-rw-r--r--spec/frontend/boards/board_list_helper.js95
-rw-r--r--spec/frontend/boards/board_list_spec.js96
-rw-r--r--spec/frontend/boards/boards_util_spec.js33
-rw-r--r--spec/frontend/boards/components/board_column_spec.js37
-rw-r--r--spec/frontend/boards/components/board_content_sidebar_spec.js20
-rw-r--r--spec/frontend/boards/components/board_content_spec.js7
-rw-r--r--spec/frontend/boards/components/board_form_spec.js2
-rw-r--r--spec/frontend/boards/components/board_settings_sidebar_spec.js11
-rw-r--r--spec/frontend/boards/components/issue_board_filtered_search_spec.js44
-rw-r--r--spec/frontend/boards/mock_data.js47
-rw-r--r--spec/frontend/boards/stores/actions_spec.js88
-rw-r--r--spec/frontend/boards/stores/getters_spec.js2
-rw-r--r--spec/frontend/boards/stores/mutations_spec.js3
14 files changed, 449 insertions, 162 deletions
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index 15ea5d4eec4..87f9a68f5dd 100644
--- a/spec/frontend/boards/board_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -1,7 +1,7 @@
-import { GlLabel, GlLoadingIcon } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
+import { GlLabel, GlLoadingIcon, GlTooltip } from '@gitlab/ui';
import { range } from 'lodash';
import Vuex from 'vuex';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue';
import { issuableTypes } from '~/boards/constants';
@@ -35,8 +35,16 @@ describe('Board card component', () => {
let store;
const findBoardBlockedIcon = () => wrapper.find(BoardBlockedIcon);
-
- const createStore = () => {
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findEpicCountablesTotalTooltip = () => wrapper.findComponent(GlTooltip);
+ const findEpicCountables = () => wrapper.findByTestId('epic-countables');
+ const findEpicCountablesBadgeIssues = () => wrapper.findByTestId('epic-countables-counts-issues');
+ const findEpicCountablesBadgeWeight = () => wrapper.findByTestId('epic-countables-weight-issues');
+ const findEpicBadgeProgress = () => wrapper.findByTestId('epic-progress');
+ const findEpicCountablesTotalWeight = () => wrapper.findByTestId('epic-countables-total-weight');
+ const findEpicProgressTooltip = () => wrapper.findByTestId('epic-progress-tooltip-content');
+
+ const createStore = ({ isEpicBoard = false } = {}) => {
store = new Vuex.Store({
...defaultStore,
state: {
@@ -45,16 +53,14 @@ describe('Board card component', () => {
},
getters: {
isGroupBoard: () => true,
- isEpicBoard: () => false,
+ isEpicBoard: () => isEpicBoard,
isProjectBoard: () => false,
},
});
};
const createWrapper = (props = {}) => {
- createStore();
-
- wrapper = mount(BoardCardInner, {
+ wrapper = mountExtended(BoardCardInner, {
store,
propsData: {
list,
@@ -88,6 +94,7 @@ describe('Board card component', () => {
weight: 1,
};
+ createStore();
createWrapper({ item: issue, list });
});
@@ -414,7 +421,108 @@ describe('Board card component', () => {
},
});
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('is an epic board', () => {
+ const descendantCounts = {
+ closedEpics: 0,
+ closedIssues: 0,
+ openedEpics: 0,
+ openedIssues: 0,
+ };
+
+ const descendantWeightSum = {
+ closedIssues: 0,
+ openedIssues: 0,
+ };
+
+ beforeEach(() => {
+ createStore({ isEpicBoard: true });
+ });
+
+ it('should render if the item has issues', () => {
+ createWrapper({
+ item: {
+ ...issue,
+ descendantCounts,
+ descendantWeightSum,
+ hasIssues: true,
+ },
+ });
+
+ expect(findEpicCountables().exists()).toBe(true);
+ });
+
+ it('should not render if the item does not have issues', () => {
+ createWrapper({
+ item: {
+ ...issue,
+ descendantCounts,
+ descendantWeightSum,
+ hasIssues: false,
+ },
+ });
+
+ expect(findEpicCountablesBadgeIssues().exists()).toBe(false);
+ });
+
+ it('shows render item countBadge, weights, and progress correctly', () => {
+ createWrapper({
+ item: {
+ ...issue,
+ descendantCounts: {
+ ...descendantCounts,
+ openedIssues: 1,
+ },
+ descendantWeightSum: {
+ closedIssues: 10,
+ openedIssues: 5,
+ },
+ hasIssues: true,
+ },
+ });
+
+ expect(findEpicCountablesBadgeIssues().text()).toBe('1');
+ expect(findEpicCountablesBadgeWeight().text()).toBe('15');
+ expect(findEpicBadgeProgress().text()).toBe('67%');
+ });
+
+ it('does not render progress when weight is zero', () => {
+ createWrapper({
+ item: {
+ ...issue,
+ descendantCounts: {
+ ...descendantCounts,
+ openedIssues: 1,
+ },
+ descendantWeightSum,
+ hasIssues: true,
+ },
+ });
+
+ expect(findEpicBadgeProgress().exists()).toBe(false);
+ });
+
+ it('renders the tooltip with the correct data', () => {
+ createWrapper({
+ item: {
+ ...issue,
+ descendantCounts,
+ descendantWeightSum: {
+ closedIssues: 10,
+ openedIssues: 5,
+ },
+ hasIssues: true,
+ },
+ });
+
+ const tooltip = findEpicCountablesTotalTooltip();
+ expect(tooltip).toBeDefined();
+
+ expect(findEpicCountablesTotalWeight().text()).toBe('15');
+ expect(findEpicProgressTooltip().text()).toBe('10 of 15 weight completed');
});
});
});
diff --git a/spec/frontend/boards/board_list_helper.js b/spec/frontend/boards/board_list_helper.js
index 915b470df8d..c440c110094 100644
--- a/spec/frontend/boards/board_list_helper.js
+++ b/spec/frontend/boards/board_list_helper.js
@@ -1,34 +1,57 @@
-/* global List */
-/* global ListIssue */
-import MockAdapter from 'axios-mock-adapter';
-import Sortable from 'sortablejs';
-import Vue from 'vue';
-import BoardList from '~/boards/components/board_list_deprecated.vue';
-import '~/boards/models/issue';
-import '~/boards/models/list';
-import store from '~/boards/stores';
-import boardsStore from '~/boards/stores/boards_store';
-import axios from '~/lib/utils/axios_utils';
-import { listObj, boardsMockInterceptor } from './mock_data';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
-window.Sortable = Sortable;
+import BoardCard from '~/boards/components/board_card.vue';
+import BoardList from '~/boards/components/board_list.vue';
+import BoardNewIssue from '~/boards/components/board_new_issue.vue';
+import defaultState from '~/boards/stores/state';
+import { mockList, mockIssuesByListId, issues } from './mock_data';
export default function createComponent({
- done,
listIssueProps = {},
componentProps = {},
listProps = {},
-}) {
- const el = document.createElement('div');
+ actions = {},
+ getters = {},
+ provide = {},
+ state = defaultState,
+ stubs = {
+ BoardNewIssue,
+ BoardCard,
+ },
+} = {}) {
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
- document.body.appendChild(el);
- const mock = new MockAdapter(axios);
- mock.onAny().reply(boardsMockInterceptor);
- boardsStore.create();
+ const store = new Vuex.Store({
+ state: {
+ boardItemsByListId: mockIssuesByListId,
+ boardItems: issues,
+ pageInfoByListId: {
+ 'gid://gitlab/List/1': { hasNextPage: true },
+ 'gid://gitlab/List/2': {},
+ },
+ listsFlags: {
+ 'gid://gitlab/List/1': {},
+ 'gid://gitlab/List/2': {},
+ },
+ selectedBoardItems: [],
+ ...state,
+ },
+ getters: {
+ isGroupBoard: () => false,
+ isProjectBoard: () => true,
+ isEpicBoard: () => false,
+ ...getters,
+ },
+ actions,
+ });
- const BoardListComp = Vue.extend(BoardList);
- const list = new List({ ...listObj, ...listProps });
- const issue = new ListIssue({
+ const list = {
+ ...mockList,
+ ...listProps,
+ };
+ const issue = {
title: 'Testing',
id: 1,
iid: 1,
@@ -36,31 +59,31 @@ export default function createComponent({
labels: [],
assignees: [],
...listIssueProps,
- });
- if (!Object.prototype.hasOwnProperty.call(listProps, 'issuesSize')) {
- list.issuesSize = 1;
+ };
+ if (!Object.prototype.hasOwnProperty.call(listProps, 'issuesCount')) {
+ list.issuesCount = 1;
}
- list.issues.push(issue);
- const component = new BoardListComp({
- el,
+ const component = shallowMount(BoardList, {
+ localVue,
store,
propsData: {
disabled: false,
list,
- issues: list.issues,
- loading: false,
+ boardItems: [issue],
+ canAdminList: true,
...componentProps,
},
provide: {
groupId: null,
rootPath: '/',
+ weightFeatureAvailable: false,
+ boardWeight: null,
+ canAdminList: true,
+ ...provide,
},
- }).$mount();
-
- Vue.nextTick(() => {
- done();
+ stubs,
});
- return { component, mock };
+ return component;
}
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 76629c96f22..a3b1810ab80 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -1,95 +1,9 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import Vuex from 'vuex';
import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
+import createComponent from 'jest/boards/board_list_helper';
import BoardCard from '~/boards/components/board_card.vue';
-import BoardList from '~/boards/components/board_list.vue';
-import BoardNewIssue from '~/boards/components/board_new_issue.vue';
import eventHub from '~/boards/eventhub';
-import defaultState from '~/boards/stores/state';
-import { mockList, mockIssuesByListId, issues, mockIssues } from './mock_data';
-
-const localVue = createLocalVue();
-localVue.use(Vuex);
-
-const actions = {
- fetchItemsForList: jest.fn(),
-};
-
-const createStore = (state = defaultState) => {
- return new Vuex.Store({
- state,
- actions,
- getters: {
- isGroupBoard: () => false,
- isProjectBoard: () => true,
- isEpicBoard: () => false,
- },
- });
-};
-
-const createComponent = ({
- listIssueProps = {},
- componentProps = {},
- listProps = {},
- state = {},
-} = {}) => {
- const store = createStore({
- boardItemsByListId: mockIssuesByListId,
- boardItems: issues,
- pageInfoByListId: {
- 'gid://gitlab/List/1': { hasNextPage: true },
- 'gid://gitlab/List/2': {},
- },
- listsFlags: {
- 'gid://gitlab/List/1': {},
- 'gid://gitlab/List/2': {},
- },
- selectedBoardItems: [],
- ...state,
- });
- const list = {
- ...mockList,
- ...listProps,
- };
- const issue = {
- title: 'Testing',
- id: 1,
- iid: 1,
- confidential: false,
- labels: [],
- assignees: [],
- ...listIssueProps,
- };
- if (!Object.prototype.hasOwnProperty.call(listProps, 'issuesCount')) {
- list.issuesCount = 1;
- }
-
- const component = shallowMount(BoardList, {
- localVue,
- propsData: {
- disabled: false,
- list,
- boardItems: [issue],
- canAdminList: true,
- ...componentProps,
- },
- store,
- provide: {
- groupId: null,
- rootPath: '/',
- weightFeatureAvailable: false,
- boardWeight: null,
- canAdminList: true,
- },
- stubs: {
- BoardCard,
- BoardNewIssue,
- },
- });
-
- return component;
-};
+import { mockIssues } from './mock_data';
describe('Board list component', () => {
let wrapper;
@@ -101,7 +15,6 @@ describe('Board list component', () => {
afterEach(() => {
wrapper.destroy();
- wrapper = null;
});
describe('When Expanded', () => {
@@ -176,6 +89,10 @@ describe('Board list component', () => {
});
describe('load more issues', () => {
+ const actions = {
+ fetchItemsForList: jest.fn(),
+ };
+
beforeEach(() => {
wrapper = createComponent({
listProps: { issuesCount: 25 },
@@ -184,6 +101,7 @@ describe('Board list component', () => {
it('does not load issues if already loading', () => {
wrapper = createComponent({
+ actions,
state: { listsFlags: { 'gid://gitlab/List/1': { isLoadingMore: true } } },
});
wrapper.vm.listRef.dispatchEvent(new Event('scroll'));
diff --git a/spec/frontend/boards/boards_util_spec.js b/spec/frontend/boards/boards_util_spec.js
index 289905a1948..d45b6e35a45 100644
--- a/spec/frontend/boards/boards_util_spec.js
+++ b/spec/frontend/boards/boards_util_spec.js
@@ -1,4 +1,35 @@
-import { filterVariables } from '~/boards/boards_util';
+import { formatIssueInput, filterVariables } from '~/boards/boards_util';
+
+describe('formatIssueInput', () => {
+ it('correctly merges boardConfig into the issue', () => {
+ const boardConfig = {
+ labels: [
+ {
+ type: 'GroupLabel',
+ id: 44,
+ },
+ ],
+ assigneeId: '55',
+ milestoneId: 66,
+ weight: 1,
+ };
+
+ const issueInput = {
+ labelIds: ['gid://gitlab/GroupLabel/5'],
+ projectPath: 'gitlab-org/gitlab-test',
+ id: 'gid://gitlab/Issue/11',
+ };
+
+ const result = formatIssueInput(issueInput, boardConfig);
+ expect(result).toEqual({
+ projectPath: 'gitlab-org/gitlab-test',
+ id: 'gid://gitlab/Issue/11',
+ labelIds: ['gid://gitlab/GroupLabel/5', 'gid://gitlab/GroupLabel/44'],
+ assigneeIds: ['gid://gitlab/User/55'],
+ milestoneId: 'gid://gitlab/Milestone/66',
+ });
+ });
+});
describe('filterVariables', () => {
it.each([
diff --git a/spec/frontend/boards/components/board_column_spec.js b/spec/frontend/boards/components/board_column_spec.js
index 4e523d636cd..f1964daa8b2 100644
--- a/spec/frontend/boards/components/board_column_spec.js
+++ b/spec/frontend/boards/components/board_column_spec.js
@@ -15,6 +15,10 @@ describe('Board Column Component', () => {
wrapper = null;
});
+ const initStore = () => {
+ store = createStore();
+ };
+
const createComponent = ({ listType = ListType.backlog, collapsed = false } = {}) => {
const boardId = '1';
@@ -29,8 +33,6 @@ describe('Board Column Component', () => {
listMock.assignee = {};
}
- store = createStore();
-
wrapper = shallowMount(BoardColumn, {
store,
propsData: {
@@ -47,6 +49,10 @@ describe('Board Column Component', () => {
const isCollapsed = () => wrapper.classes('is-collapsed');
describe('Given different list types', () => {
+ beforeEach(() => {
+ initStore();
+ });
+
it('is expandable when List Type is `backlog`', () => {
createComponent({ listType: ListType.backlog });
@@ -79,4 +85,31 @@ describe('Board Column Component', () => {
expect(wrapper.element.scrollIntoView).toHaveBeenCalled();
});
});
+
+ describe('on mount', () => {
+ beforeEach(async () => {
+ initStore();
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ });
+
+ describe('when list is collapsed', () => {
+ it('does not call fetchItemsForList when', async () => {
+ createComponent({ collapsed: true });
+
+ await nextTick();
+
+ expect(store.dispatch).toHaveBeenCalledTimes(0);
+ });
+ });
+
+ describe('when the list is not collapsed', () => {
+ it('calls fetchItemsForList when', async () => {
+ createComponent({ collapsed: false });
+
+ await nextTick();
+
+ expect(store.dispatch).toHaveBeenCalledWith('fetchItemsForList', { listId: 300 });
+ });
+ });
+ });
});
diff --git a/spec/frontend/boards/components/board_content_sidebar_spec.js b/spec/frontend/boards/components/board_content_sidebar_spec.js
index 10d739c65f5..8a8250205d0 100644
--- a/spec/frontend/boards/components/board_content_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_content_sidebar_spec.js
@@ -1,5 +1,6 @@
import { GlDrawer } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { MountingPortal } from 'portal-vue';
import Vuex from 'vuex';
import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdown_widget.vue';
import { stubComponent } from 'helpers/stub_component';
@@ -9,7 +10,8 @@ import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.v
import { ISSUABLE } from '~/boards/constants';
import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue';
-import { mockIssue, mockIssueGroupPath, mockIssueProjectPath } from '../mock_data';
+import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
+import { mockActiveIssue, mockIssue, mockIssueGroupPath, mockIssueProjectPath } from '../mock_data';
describe('BoardContentSidebar', () => {
let wrapper;
@@ -25,7 +27,7 @@ describe('BoardContentSidebar', () => {
},
getters: {
activeBoardItem: () => {
- return { ...mockIssue, epic: null };
+ return { ...mockActiveIssue, epic: null };
},
groupPathForActiveIssue: () => mockIssueGroupPath,
projectPathForActiveIssue: () => mockIssueProjectPath,
@@ -90,6 +92,14 @@ describe('BoardContentSidebar', () => {
expect(wrapper.findComponent(GlDrawer).exists()).toBe(true);
});
+ it('confirms we render MountingPortal', () => {
+ expect(wrapper.find(MountingPortal).props()).toMatchObject({
+ mountTo: '#js-right-sidebar-portal',
+ append: true,
+ name: 'board-content-sidebar',
+ });
+ });
+
it('does not render GlDrawer when isSidebarOpen is false', () => {
createStore({ mockGetters: { isSidebarOpen: () => false } });
createComponent();
@@ -101,6 +111,10 @@ describe('BoardContentSidebar', () => {
expect(wrapper.findComponent(GlDrawer).props('open')).toBe(true);
});
+ it('renders SidebarTodoWidget', () => {
+ expect(wrapper.findComponent(SidebarTodoWidget).exists()).toBe(true);
+ });
+
it('renders BoardSidebarLabelsSelect', () => {
expect(wrapper.findComponent(BoardSidebarLabelsSelect).exists()).toBe(true);
});
@@ -138,7 +152,7 @@ describe('BoardContentSidebar', () => {
expect(toggleBoardItem).toHaveBeenCalledTimes(1);
expect(toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), {
- boardItem: { ...mockIssue, epic: null },
+ boardItem: { ...mockActiveIssue, epic: null },
sidebarType: ISSUABLE,
});
});
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
index 8c1a7bd3947..5a799b6388e 100644
--- a/spec/frontend/boards/components/board_content_spec.js
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -1,5 +1,6 @@
import { GlAlert } from '@gitlab/ui';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
import Draggable from 'vuedraggable';
import Vuex from 'vuex';
import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
@@ -8,8 +9,7 @@ import BoardColumnDeprecated from '~/boards/components/board_column_deprecated.v
import BoardContent from '~/boards/components/board_content.vue';
import { mockLists, mockListsWithModel } from '../mock_data';
-const localVue = createLocalVue();
-localVue.use(Vuex);
+Vue.use(Vuex);
const actions = {
moveList: jest.fn(),
@@ -44,7 +44,6 @@ describe('BoardContent', () => {
...state,
});
wrapper = shallowMount(BoardContent, {
- localVue,
propsData: {
lists: mockListsWithModel,
disabled: false,
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index 80d740458dc..3966c3e6b87 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -12,8 +12,8 @@ import { createStore } from '~/boards/stores';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
visitUrl: jest.fn().mockName('visitUrlMock'),
- stripFinalUrlSegment: jest.requireActual('~/lib/utils/url_utility').stripFinalUrlSegment,
}));
const currentBoard = {
diff --git a/spec/frontend/boards/components/board_settings_sidebar_spec.js b/spec/frontend/boards/components/board_settings_sidebar_spec.js
index 464331b6e30..20a08be6c19 100644
--- a/spec/frontend/boards/components/board_settings_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_settings_sidebar_spec.js
@@ -3,6 +3,7 @@ import { GlDrawer, GlLabel } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
+import { MountingPortal } from 'portal-vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue';
@@ -51,6 +52,16 @@ describe('BoardSettingsSidebar', () => {
wrapper.destroy();
});
+ it('finds a MountingPortal component', () => {
+ createComponent();
+
+ expect(wrapper.find(MountingPortal).props()).toMatchObject({
+ mountTo: '#js-right-sidebar-portal',
+ append: true,
+ name: 'board-settings-sidebar',
+ });
+ });
+
describe('when sidebarType is "list"', () => {
it('finds a GlDrawer component', () => {
createComponent();
diff --git a/spec/frontend/boards/components/issue_board_filtered_search_spec.js b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
new file mode 100644
index 00000000000..0e3cf59901e
--- /dev/null
+++ b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
@@ -0,0 +1,44 @@
+import { shallowMount } from '@vue/test-utils';
+import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue';
+import IssueBoardFilteredSpec from '~/boards/components/issue_board_filtered_search.vue';
+import { BoardType } from '~/boards/constants';
+import issueBoardFilters from '~/boards/issue_board_filters';
+import { mockTokens } from '../mock_data';
+
+describe('IssueBoardFilter', () => {
+ let wrapper;
+
+ const createComponent = ({ initialFilterParams = {} } = {}) => {
+ wrapper = shallowMount(IssueBoardFilteredSpec, {
+ provide: { initialFilterParams },
+ props: { fullPath: '', boardType: '' },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('finds BoardFilteredSearch', () => {
+ expect(wrapper.find(BoardFilteredSearch).exists()).toBe(true);
+ });
+
+ it.each([[BoardType.group], [BoardType.project]])(
+ 'when boardType is %s we pass the correct tokens to BoardFilteredSearch',
+ (boardType) => {
+ const { fetchAuthors, fetchLabels } = issueBoardFilters({}, '', boardType);
+
+ const tokens = mockTokens(fetchLabels, fetchAuthors);
+
+ expect(wrapper.find(BoardFilteredSearch).props('tokens').toString()).toBe(
+ tokens.toString(),
+ );
+ },
+ );
+ });
+});
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index bcaca9522e4..6ac4db8cdaa 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -5,6 +5,9 @@ import Vue from 'vue';
import '~/boards/models/list';
import { ListType } from '~/boards/constants';
import boardsStore from '~/boards/stores/boards_store';
+import { __ } from '~/locale';
+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';
export const boardObj = {
id: 1,
@@ -179,6 +182,7 @@ export const mockIssue = {
export const mockActiveIssue = {
...mockIssue,
+ fullId: 'gid://gitlab/Issue/436',
id: 436,
iid: '27',
subscribed: false,
@@ -287,7 +291,7 @@ export const setMockEndpoints = (opts = {}) => {
export const mockList = {
id: 'gid://gitlab/List/1',
- title: 'Backlog',
+ title: 'Open',
position: -Infinity,
listType: 'backlog',
collapsed: false,
@@ -526,3 +530,44 @@ export const mockMoveData = {
originalIssue: { foo: 'bar' },
...mockMoveIssueParams,
};
+
+export const mockTokens = (fetchLabels, fetchAuthors) => [
+ {
+ icon: 'labels',
+ title: __('Label'),
+ type: 'label_name',
+ operators: [
+ { value: '=', description: 'is' },
+ { value: '!=', description: 'is not' },
+ ],
+ token: LabelToken,
+ unique: false,
+ symbol: '~',
+ fetchLabels,
+ },
+ {
+ icon: 'pencil',
+ title: __('Author'),
+ type: 'author_username',
+ operators: [
+ { value: '=', description: 'is' },
+ { value: '!=', description: 'is not' },
+ ],
+ symbol: '@',
+ token: AuthorToken,
+ unique: true,
+ fetchAuthors,
+ },
+ {
+ icon: 'user',
+ title: __('Assignee'),
+ type: 'assignee_username',
+ operators: [
+ { value: '=', description: 'is' },
+ { value: '!=', description: 'is not' },
+ ],
+ token: AuthorToken,
+ unique: true,
+ fetchAuthors,
+ },
+];
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index b28412f2127..5e16e389ddc 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -492,6 +492,63 @@ describe('moveList', () => {
});
describe('updateList', () => {
+ const listId = 'gid://gitlab/List/1';
+ const createState = (boardItemsByListId = {}) => ({
+ fullPath: 'gitlab-org',
+ fullBoardId: 'gid://gitlab/Board/1',
+ boardType: 'group',
+ disabled: false,
+ boardLists: [{ type: 'closed' }],
+ issuableType: issuableTypes.issue,
+ boardItemsByListId,
+ });
+
+ describe('when state doesnt have list items', () => {
+ it('calls fetchItemsByList', async () => {
+ const dispatch = jest.fn();
+
+ jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
+ data: {
+ updateBoardList: {
+ errors: [],
+ list: {
+ id: listId,
+ },
+ },
+ },
+ });
+
+ await actions.updateList({ commit: () => {}, state: createState(), dispatch }, { listId });
+
+ expect(dispatch.mock.calls).toEqual([['fetchItemsForList', { listId }]]);
+ });
+ });
+
+ describe('when state has list items', () => {
+ it('doesnt call fetchItemsByList', async () => {
+ const commit = jest.fn();
+ const dispatch = jest.fn();
+
+ jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
+ data: {
+ updateBoardList: {
+ errors: [],
+ list: {
+ id: listId,
+ },
+ },
+ },
+ });
+
+ await actions.updateList(
+ { commit, state: createState({ [listId]: [] }), dispatch },
+ { listId },
+ );
+
+ expect(dispatch.mock.calls).toEqual([]);
+ });
+ });
+
it('should commit UPDATE_LIST_FAILURE mutation when API returns an error', (done) => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
@@ -502,19 +559,10 @@ describe('updateList', () => {
},
});
- const state = {
- fullPath: 'gitlab-org',
- fullBoardId: 'gid://gitlab/Board/1',
- boardType: 'group',
- disabled: false,
- boardLists: [{ type: 'closed' }],
- issuableType: issuableTypes.issue,
- };
-
testAction(
actions.updateList,
{ listId: 'gid://gitlab/List/1', position: 1 },
- state,
+ createState(),
[{ type: types.UPDATE_LIST_FAILURE }],
[],
done,
@@ -667,6 +715,19 @@ describe('fetchItemsForList', () => {
[listId]: pageInfo,
};
+ describe('when list id is undefined', () => {
+ it('does not call the query', async () => {
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
+
+ await actions.fetchItemsForList(
+ { state, getters: () => {}, commit: () => {} },
+ { listId: undefined },
+ );
+
+ expect(gqlClient.query).toHaveBeenCalledTimes(0);
+ });
+ });
+
it('should commit mutations REQUEST_ITEMS_FOR_LIST and RECEIVE_ITEMS_FOR_LIST_SUCCESS on success', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
@@ -1111,16 +1172,13 @@ describe('updateIssueOrder', () => {
describe('setAssignees', () => {
const node = { username: 'name' };
- const projectPath = 'h/h';
- const refPath = `${projectPath}#3`;
- const iid = '1';
describe('when succeeds', () => {
it('calls the correct mutation with the correct values', (done) => {
testAction(
actions.setAssignees,
- [node],
- { activeBoardItem: { iid, referencePath: refPath }, commit: () => {} },
+ { assignees: [node], iid: '1' },
+ { commit: () => {} },
[
{
type: 'UPDATE_BOARD_ITEM_BY_ID',
diff --git a/spec/frontend/boards/stores/getters_spec.js b/spec/frontend/boards/stores/getters_spec.js
index e7efb21bee5..c0774dd3ae1 100644
--- a/spec/frontend/boards/stores/getters_spec.js
+++ b/spec/frontend/boards/stores/getters_spec.js
@@ -92,7 +92,7 @@ describe('Boards - Getters', () => {
it.each`
id | expected
${'1'} | ${'issue'}
- ${''} | ${{}}
+ ${''} | ${{ id: '', iid: '', fullId: '' }}
`('returns $expected when $id is passed to state', ({ id, expected }) => {
const state = { boardItems: { 1: 'issue' }, activeId: id };
diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js
index 5b38f04e77b..37f0969a39a 100644
--- a/spec/frontend/boards/stores/mutations_spec.js
+++ b/spec/frontend/boards/stores/mutations_spec.js
@@ -35,6 +35,7 @@ describe('Board Store Mutations', () => {
describe('SET_INITIAL_BOARD_DATA', () => {
it('Should set initial Boards data to state', () => {
+ const allowSubEpics = true;
const boardId = 1;
const fullPath = 'gitlab-org';
const boardType = 'group';
@@ -45,6 +46,7 @@ describe('Board Store Mutations', () => {
const issuableType = issuableTypes.issue;
mutations[types.SET_INITIAL_BOARD_DATA](state, {
+ allowSubEpics,
boardId,
fullPath,
boardType,
@@ -53,6 +55,7 @@ describe('Board Store Mutations', () => {
issuableType,
});
+ expect(state.allowSubEpics).toBe(allowSubEpics);
expect(state.boardId).toEqual(boardId);
expect(state.fullPath).toEqual(fullPath);
expect(state.boardType).toEqual(boardType);