summaryrefslogtreecommitdiff
path: root/spec/frontend/boards
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 18:18:33 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 18:18:33 +0000
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /spec/frontend/boards
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
downloadgitlab-ce-f64a639bcfa1fc2bc89ca7db268f594306edfd7c.tar.gz
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'spec/frontend/boards')
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js (renamed from spec/frontend/boards/issue_card_inner_spec.js)51
-rw-r--r--spec/frontend/boards/board_list_spec.js43
-rw-r--r--spec/frontend/boards/board_new_issue_deprecated_spec.js8
-rw-r--r--spec/frontend/boards/components/board_add_new_column_form_spec.js166
-rw-r--r--spec/frontend/boards/components/board_add_new_column_spec.js115
-rw-r--r--spec/frontend/boards/components/board_card_deprecated_spec.js219
-rw-r--r--spec/frontend/boards/components/board_card_layout_deprecated_spec.js2
-rw-r--r--spec/frontend/boards/components/board_card_layout_spec.js116
-rw-r--r--spec/frontend/boards/components/board_card_spec.js265
-rw-r--r--spec/frontend/boards/components/board_form_spec.js9
-rw-r--r--spec/frontend/boards/components/board_list_header_spec.js76
-rw-r--r--spec/frontend/boards/components/board_new_issue_spec.js3
-rw-r--r--spec/frontend/boards/components/filtered_search_spec.js65
-rw-r--r--spec/frontend/boards/components/item_count_spec.js (renamed from spec/frontend/boards/components/issue_count_spec.js)26
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_due_date_spec.js8
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_issue_title_spec.js6
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js4
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js6
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js8
-rw-r--r--spec/frontend/boards/components/sidebar/remove_issue_spec.js28
-rw-r--r--spec/frontend/boards/mock_data.js44
-rw-r--r--spec/frontend/boards/project_select_deprecated_spec.js1
-rw-r--r--spec/frontend/boards/project_select_spec.js64
-rw-r--r--spec/frontend/boards/stores/actions_spec.js206
-rw-r--r--spec/frontend/boards/stores/getters_spec.js71
-rw-r--r--spec/frontend/boards/stores/mutations_spec.js135
26 files changed, 1184 insertions, 561 deletions
diff --git a/spec/frontend/boards/issue_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index b9f84fed6b3..4487fc15de6 100644
--- a/spec/frontend/boards/issue_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -1,7 +1,7 @@
import { GlLabel } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { range } from 'lodash';
-import IssueCardInner from '~/boards/components/issue_card_inner.vue';
+import BoardCardInner from '~/boards/components/board_card_inner.vue';
import eventHub from '~/boards/eventhub';
import defaultStore from '~/boards/stores';
import { updateHistory } from '~/lib/utils/url_utility';
@@ -10,7 +10,7 @@ import { mockLabelList } from './mock_data';
jest.mock('~/lib/utils/url_utility');
jest.mock('~/boards/eventhub');
-describe('Issue card component', () => {
+describe('Board card component', () => {
const user = {
id: 1,
name: 'testing 123',
@@ -31,18 +31,17 @@ describe('Issue card component', () => {
let list;
const createWrapper = (props = {}, store = defaultStore) => {
- wrapper = mount(IssueCardInner, {
+ wrapper = mount(BoardCardInner, {
store,
propsData: {
list,
- issue,
+ item: issue,
...props,
},
stubs: {
GlLabel: true,
},
provide: {
- groupId: null,
rootPath: '/',
scopedLabelsAvailable: false,
},
@@ -63,7 +62,7 @@ describe('Issue card component', () => {
weight: 1,
};
- createWrapper({ issue, list });
+ createWrapper({ item: issue, list });
});
afterEach(() => {
@@ -103,8 +102,8 @@ describe('Issue card component', () => {
describe('confidential issue', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
confidential: true,
},
});
@@ -119,8 +118,8 @@ describe('Issue card component', () => {
describe('with avatar', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [user],
updateData(newData) {
Object.assign(this, newData);
@@ -146,8 +145,8 @@ describe('Issue card component', () => {
});
it('renders the avatar using avatarUrl property', async () => {
- wrapper.props('issue').updateData({
- ...wrapper.props('issue'),
+ wrapper.props('item').updateData({
+ ...wrapper.props('item'),
assignees: [
{
id: '1',
@@ -172,8 +171,8 @@ describe('Issue card component', () => {
global.gon.default_avatar_url = 'default_avatar';
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [
{
id: 1,
@@ -201,8 +200,8 @@ describe('Issue card component', () => {
describe('multiple assignees', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [
{
id: 2,
@@ -233,7 +232,7 @@ describe('Issue card component', () => {
describe('more than three assignees', () => {
beforeEach(() => {
- const { assignees } = wrapper.props('issue');
+ const { assignees } = wrapper.props('item');
assignees.push({
id: 5,
name: 'user5',
@@ -242,8 +241,8 @@ describe('Issue card component', () => {
});
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees,
},
});
@@ -259,7 +258,7 @@ describe('Issue card component', () => {
it('renders 99+ avatar counter', async () => {
const assignees = [
- ...wrapper.props('issue').assignees,
+ ...wrapper.props('item').assignees,
...range(5, 103).map((i) => ({
id: i,
name: 'name',
@@ -268,8 +267,8 @@ describe('Issue card component', () => {
})),
];
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees,
},
});
@@ -283,7 +282,7 @@ describe('Issue card component', () => {
describe('labels', () => {
beforeEach(() => {
- wrapper.setProps({ issue: { ...issue, labels: [list.label, label1] } });
+ wrapper.setProps({ item: { ...issue, labels: [list.label, label1] } });
});
it('does not render list label but renders all other labels', () => {
@@ -295,7 +294,7 @@ describe('Issue card component', () => {
});
it('does not render label if label does not have an ID', async () => {
- wrapper.setProps({ issue: { ...issue, labels: [label1, { title: 'closed' }] } });
+ wrapper.setProps({ item: { ...issue, labels: [label1, { title: 'closed' }] } });
await wrapper.vm.$nextTick();
@@ -307,8 +306,8 @@ describe('Issue card component', () => {
describe('blocked', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
blocked: true,
},
});
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 7ed20f20882..bf39c3f3e42 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -1,8 +1,9 @@
-import { createLocalVue, mount } from '@vue/test-utils';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
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';
@@ -11,13 +12,18 @@ const localVue = createLocalVue();
localVue.use(Vuex);
const actions = {
- fetchIssuesForList: jest.fn(),
+ fetchItemsForList: jest.fn(),
};
const createStore = (state = defaultState) => {
return new Vuex.Store({
state,
actions,
+ getters: {
+ isGroupBoard: () => false,
+ isProjectBoard: () => true,
+ isEpicBoard: () => false,
+ },
});
};
@@ -28,8 +34,8 @@ const createComponent = ({
state = {},
} = {}) => {
const store = createStore({
- issuesByListId: mockIssuesByListId,
- issues,
+ boardItemsByListId: mockIssuesByListId,
+ boardItems: issues,
pageInfoByListId: {
'gid://gitlab/List/1': { hasNextPage: true },
'gid://gitlab/List/2': {},
@@ -38,6 +44,7 @@ const createComponent = ({
'gid://gitlab/List/1': {},
'gid://gitlab/List/2': {},
},
+ selectedBoardItems: [],
...state,
});
@@ -58,12 +65,12 @@ const createComponent = ({
list.issuesCount = 1;
}
- const component = mount(BoardList, {
+ const component = shallowMount(BoardList, {
localVue,
propsData: {
disabled: false,
list,
- issues: [issue],
+ boardItems: [issue],
canAdminList: true,
...componentProps,
},
@@ -74,6 +81,10 @@ const createComponent = ({
weightFeatureAvailable: false,
boardWeight: null,
},
+ stubs: {
+ BoardCard,
+ BoardNewIssue,
+ },
});
return component;
@@ -81,7 +92,10 @@ const createComponent = ({
describe('Board list component', () => {
let wrapper;
+
const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
+ const findIssueCountLoadingIcon = () => wrapper.find('[data-testid="count-loading-icon"]');
+
useFakeRequestAnimationFrame();
afterEach(() => {
@@ -111,7 +125,7 @@ describe('Board list component', () => {
});
it('sets data attribute with issue id', () => {
- expect(wrapper.find('.board-card').attributes('data-issue-id')).toBe('1');
+ expect(wrapper.find('.board-card').attributes('data-item-id')).toBe('1');
});
it('shows new issue form', async () => {
@@ -170,7 +184,7 @@ describe('Board list component', () => {
it('loads more issues after scrolling', () => {
wrapper.vm.listRef.dispatchEvent(new Event('scroll'));
- expect(actions.fetchIssuesForList).toHaveBeenCalled();
+ expect(actions.fetchItemsForList).toHaveBeenCalled();
});
it('does not load issues if already loading', () => {
@@ -179,7 +193,7 @@ describe('Board list component', () => {
});
wrapper.vm.listRef.dispatchEvent(new Event('scroll'));
- expect(actions.fetchIssuesForList).not.toHaveBeenCalled();
+ expect(actions.fetchItemsForList).not.toHaveBeenCalled();
});
it('shows loading more spinner', async () => {
@@ -189,7 +203,8 @@ describe('Board list component', () => {
wrapper.vm.showCount = true;
await wrapper.vm.$nextTick();
- expect(wrapper.find('.board-list-count .gl-spinner').exists()).toBe(true);
+
+ expect(findIssueCountLoadingIcon().exists()).toBe(true);
});
});
@@ -243,7 +258,7 @@ describe('Board list component', () => {
describe('handleDragOnEnd', () => {
it('removes class `is-dragging` from document body', () => {
- jest.spyOn(wrapper.vm, 'moveIssue').mockImplementation(() => {});
+ jest.spyOn(wrapper.vm, 'moveItem').mockImplementation(() => {});
document.body.classList.add('is-dragging');
findByTestId('tree-root-wrapper').vm.$emit('end', {
@@ -251,9 +266,9 @@ describe('Board list component', () => {
newIndex: 0,
item: {
dataset: {
- issueId: mockIssues[0].id,
- issueIid: mockIssues[0].iid,
- issuePath: mockIssues[0].referencePath,
+ itemId: mockIssues[0].id,
+ itemIid: mockIssues[0].iid,
+ itemPath: mockIssues[0].referencePath,
},
},
to: { children: [], dataset: { listId: 'gid://gitlab/List/1' } },
diff --git a/spec/frontend/boards/board_new_issue_deprecated_spec.js b/spec/frontend/boards/board_new_issue_deprecated_spec.js
index 1a29f680166..3903ad201b2 100644
--- a/spec/frontend/boards/board_new_issue_deprecated_spec.js
+++ b/spec/frontend/boards/board_new_issue_deprecated_spec.js
@@ -3,6 +3,7 @@
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue';
+import Vuex from 'vuex';
import boardNewIssue from '~/boards/components/board_new_issue_deprecated.vue';
import boardsStore from '~/boards/stores/boards_store';
import axios from '~/lib/utils/axios_utils';
@@ -10,6 +11,8 @@ import axios from '~/lib/utils/axios_utils';
import '~/boards/models/list';
import { listObj, boardsMockInterceptor } from './mock_data';
+Vue.use(Vuex);
+
describe('Issue boards new issue form', () => {
let wrapper;
let vm;
@@ -43,11 +46,16 @@ describe('Issue boards new issue form', () => {
newIssueMock = Promise.resolve(promiseReturn);
jest.spyOn(list, 'newIssue').mockImplementation(() => newIssueMock);
+ const store = new Vuex.Store({
+ getters: { isGroupBoard: () => false },
+ });
+
wrapper = mount(BoardNewIssueComp, {
propsData: {
disabled: false,
list,
},
+ store,
provide: {
groupId: null,
},
diff --git a/spec/frontend/boards/components/board_add_new_column_form_spec.js b/spec/frontend/boards/components/board_add_new_column_form_spec.js
new file mode 100644
index 00000000000..3702f55f17b
--- /dev/null
+++ b/spec/frontend/boards/components/board_add_new_column_form_spec.js
@@ -0,0 +1,166 @@
+import { GlFormGroup, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
+import defaultState from '~/boards/stores/state';
+import { mockLabelList } from '../mock_data';
+
+Vue.use(Vuex);
+
+describe('Board card layout', () => {
+ let wrapper;
+
+ const createStore = ({ actions = {}, getters = {}, state = {} } = {}) => {
+ return new Vuex.Store({
+ state: {
+ ...defaultState,
+ ...state,
+ },
+ actions,
+ getters,
+ });
+ };
+
+ const mountComponent = ({
+ loading = false,
+ formDescription = '',
+ searchLabel = '',
+ searchPlaceholder = '',
+ selectedId,
+ actions,
+ slots,
+ } = {}) => {
+ wrapper = extendedWrapper(
+ shallowMount(BoardAddNewColumnForm, {
+ stubs: {
+ GlFormGroup: true,
+ },
+ propsData: {
+ loading,
+ formDescription,
+ searchLabel,
+ searchPlaceholder,
+ selectedId,
+ },
+ slots,
+ store: createStore({
+ actions: {
+ setAddColumnFormVisibility: jest.fn(),
+ ...actions,
+ },
+ }),
+ }),
+ );
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const formTitle = () => wrapper.findByTestId('board-add-column-form-title').text();
+ const findSearchInput = () => wrapper.find(GlSearchBoxByType);
+ const findSearchLabel = () => wrapper.find(GlFormGroup);
+ const cancelButton = () => wrapper.findByTestId('cancelAddNewColumn');
+ const submitButton = () => wrapper.findByTestId('addNewColumnButton');
+
+ it('shows form title & search input', () => {
+ mountComponent();
+
+ expect(formTitle()).toEqual(BoardAddNewColumnForm.i18n.newList);
+ expect(findSearchInput().exists()).toBe(true);
+ });
+
+ it('clicking cancel hides the form', () => {
+ const setAddColumnFormVisibility = jest.fn();
+ mountComponent({
+ actions: {
+ setAddColumnFormVisibility,
+ },
+ });
+
+ cancelButton().vm.$emit('click');
+
+ expect(setAddColumnFormVisibility).toHaveBeenCalledWith(expect.anything(), false);
+ });
+
+ it('sets placeholder and description from props', () => {
+ const props = {
+ formDescription: 'Some description of a list',
+ };
+
+ mountComponent(props);
+
+ expect(wrapper.html()).toHaveText(props.formDescription);
+ });
+
+ describe('items', () => {
+ const mountWithItems = (loading) =>
+ mountComponent({
+ loading,
+ slots: {
+ items: '<div class="item-slot">Some kind of list</div>',
+ },
+ });
+
+ it('hides items slot and shows skeleton while loading', () => {
+ mountWithItems(true);
+
+ expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
+ expect(wrapper.find('.item-slot').exists()).toBe(false);
+ });
+
+ it('shows items slot and hides skeleton while not loading', () => {
+ mountWithItems(false);
+
+ expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false);
+ expect(wrapper.find('.item-slot').exists()).toBe(true);
+ });
+ });
+
+ describe('search box', () => {
+ it('sets label and placeholder text from props', () => {
+ const props = {
+ searchLabel: 'Some items',
+ searchPlaceholder: 'Search for an item',
+ };
+
+ mountComponent(props);
+
+ expect(findSearchLabel().attributes('label')).toEqual(props.searchLabel);
+ expect(findSearchInput().attributes('placeholder')).toEqual(props.searchPlaceholder);
+ });
+
+ it('emits filter event on input', () => {
+ mountComponent();
+
+ const searchText = 'some text';
+
+ findSearchInput().vm.$emit('input', searchText);
+
+ expect(wrapper.emitted('filter-items')).toEqual([[searchText]]);
+ });
+ });
+
+ describe('Add list button', () => {
+ it('is disabled if no item is selected', () => {
+ mountComponent();
+
+ expect(submitButton().props('disabled')).toBe(true);
+ });
+
+ it('emits add-list event on click', async () => {
+ mountComponent({
+ selectedId: mockLabelList.label.id,
+ });
+
+ await nextTick();
+
+ submitButton().vm.$emit('click');
+
+ expect(wrapper.emitted('add-list')).toEqual([[]]);
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_add_new_column_spec.js b/spec/frontend/boards/components/board_add_new_column_spec.js
new file mode 100644
index 00000000000..60584eaf6cf
--- /dev/null
+++ b/spec/frontend/boards/components/board_add_new_column_spec.js
@@ -0,0 +1,115 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import BoardAddNewColumn from '~/boards/components/board_add_new_column.vue';
+import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
+import defaultState from '~/boards/stores/state';
+import { mockLabelList } from '../mock_data';
+
+Vue.use(Vuex);
+
+describe('Board card layout', () => {
+ let wrapper;
+
+ const createStore = ({ actions = {}, getters = {}, state = {} } = {}) => {
+ return new Vuex.Store({
+ state: {
+ ...defaultState,
+ ...state,
+ },
+ actions,
+ getters,
+ });
+ };
+
+ const mountComponent = ({
+ selectedId,
+ labels = [],
+ getListByLabelId = jest.fn(),
+ actions = {},
+ } = {}) => {
+ wrapper = extendedWrapper(
+ shallowMount(BoardAddNewColumn, {
+ data() {
+ return {
+ selectedId,
+ };
+ },
+ store: createStore({
+ actions: {
+ fetchLabels: jest.fn(),
+ setAddColumnFormVisibility: jest.fn(),
+ ...actions,
+ },
+ getters: {
+ shouldUseGraphQL: () => true,
+ getListByLabelId: () => getListByLabelId,
+ },
+ state: {
+ labels,
+ labelsLoading: false,
+ isEpicBoard: false,
+ },
+ }),
+ provide: {
+ scopedLabelsAvailable: true,
+ },
+ }),
+ );
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Add list button', () => {
+ it('calls addList', async () => {
+ const getListByLabelId = jest.fn().mockReturnValue(null);
+ const highlightList = jest.fn();
+ const createList = jest.fn();
+
+ mountComponent({
+ labels: [mockLabelList.label],
+ selectedId: mockLabelList.label.id,
+ getListByLabelId,
+ actions: {
+ createList,
+ highlightList,
+ },
+ });
+
+ wrapper.findComponent(BoardAddNewColumnForm).vm.$emit('add-list');
+
+ await nextTick();
+
+ expect(highlightList).not.toHaveBeenCalled();
+ expect(createList).toHaveBeenCalledWith(expect.anything(), {
+ labelId: mockLabelList.label.id,
+ });
+ });
+
+ it('highlights existing list if trying to re-add', async () => {
+ const getListByLabelId = jest.fn().mockReturnValue(mockLabelList);
+ const highlightList = jest.fn();
+ const createList = jest.fn();
+
+ mountComponent({
+ labels: [mockLabelList.label],
+ selectedId: mockLabelList.label.id,
+ getListByLabelId,
+ actions: {
+ createList,
+ highlightList,
+ },
+ });
+
+ wrapper.findComponent(BoardAddNewColumnForm).vm.$emit('add-list');
+
+ await nextTick();
+
+ expect(highlightList).toHaveBeenCalledWith(expect.anything(), mockLabelList.id);
+ expect(createList).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_card_deprecated_spec.js b/spec/frontend/boards/components/board_card_deprecated_spec.js
new file mode 100644
index 00000000000..266cbc7106d
--- /dev/null
+++ b/spec/frontend/boards/components/board_card_deprecated_spec.js
@@ -0,0 +1,219 @@
+/* global List */
+/* global ListAssignee */
+/* global ListLabel */
+
+import { mount } from '@vue/test-utils';
+
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import BoardCardDeprecated from '~/boards/components/board_card_deprecated.vue';
+import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue';
+import eventHub from '~/boards/eventhub';
+import store from '~/boards/stores';
+import boardsStore from '~/boards/stores/boards_store';
+import axios from '~/lib/utils/axios_utils';
+
+import sidebarEventHub from '~/sidebar/event_hub';
+import '~/boards/models/label';
+import '~/boards/models/assignee';
+import '~/boards/models/list';
+import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data';
+
+describe('BoardCard', () => {
+ let wrapper;
+ let mock;
+ let list;
+
+ const findIssueCardInner = () => wrapper.find(issueCardInner);
+ const findUserAvatarLink = () => wrapper.find(userAvatarLink);
+
+ // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
+ const mountComponent = (propsData) => {
+ wrapper = mount(BoardCardDeprecated, {
+ stubs: {
+ issueCardInner,
+ },
+ store,
+ propsData: {
+ list,
+ issue: list.issues[0],
+ disabled: false,
+ index: 0,
+ ...propsData,
+ },
+ provide: {
+ groupId: null,
+ rootPath: '/',
+ scopedLabelsAvailable: false,
+ },
+ });
+ };
+
+ const setupData = async () => {
+ list = new List(listObj);
+ boardsStore.create();
+ boardsStore.detail.issue = {};
+ const label1 = new ListLabel({
+ id: 3,
+ title: 'testing 123',
+ color: '#000cff',
+ text_color: 'white',
+ description: 'test',
+ });
+ await waitForPromises();
+
+ list.issues[0].labels.push(label1);
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onAny().reply(boardsMockInterceptor);
+ setMockEndpoints();
+ return setupData();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ list = null;
+ mock.restore();
+ });
+
+ it('when details issue is empty does not show the element', () => {
+ mountComponent();
+ expect(wrapper.find('[data-testid="board_card"').classes()).not.toContain('is-active');
+ });
+
+ it('when detailIssue is equal to card issue shows the element', () => {
+ [boardsStore.detail.issue] = list.issues;
+ mountComponent();
+
+ expect(wrapper.classes()).toContain('is-active');
+ });
+
+ it('when multiSelect does not contain issue removes multi select class', () => {
+ mountComponent();
+ expect(wrapper.classes()).not.toContain('multi-select');
+ });
+
+ it('when multiSelect contain issue add multi select class', () => {
+ boardsStore.multiSelect.list = [list.issues[0]];
+ mountComponent();
+
+ expect(wrapper.classes()).toContain('multi-select');
+ });
+
+ it('adds user-can-drag class if not disabled', () => {
+ mountComponent();
+ expect(wrapper.classes()).toContain('user-can-drag');
+ });
+
+ it('does not add user-can-drag class disabled', () => {
+ mountComponent({ disabled: true });
+
+ expect(wrapper.classes()).not.toContain('user-can-drag');
+ });
+
+ it('does not add disabled class', () => {
+ mountComponent();
+ expect(wrapper.classes()).not.toContain('is-disabled');
+ });
+
+ it('adds disabled class is disabled is true', () => {
+ mountComponent({ disabled: true });
+
+ expect(wrapper.classes()).toContain('is-disabled');
+ });
+
+ describe('mouse events', () => {
+ it('does not set detail issue if showDetail is false', () => {
+ mountComponent();
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if link is clicked', () => {
+ mountComponent();
+ findIssueCardInner().find('a').trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if img is clicked', () => {
+ mountComponent({
+ issue: {
+ ...list.issues[0],
+ assignees: [
+ new ListAssignee({
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ avatar: 'test_image',
+ }),
+ ],
+ },
+ });
+
+ findUserAvatarLink().trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if showDetail is false after mouseup', () => {
+ mountComponent();
+ wrapper.trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('sets detail issue to card issue on mouse up', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+ wrapper.trigger('mouseup');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', wrapper.vm.issue, false);
+ expect(boardsStore.detail.list).toEqual(wrapper.vm.list);
+ });
+
+ it('resets detail issue to empty if already set', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+ const [issue] = list.issues;
+ boardsStore.detail.issue = issue;
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+ wrapper.trigger('mouseup');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('clearDetailIssue', false);
+ });
+ });
+
+ describe('sidebarHub events', () => {
+ it('closes all sidebars before showing an issue if no issues are opened', () => {
+ jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
+ boardsStore.detail.issue = {};
+ mountComponent();
+
+ // sets conditional so that event is emitted.
+ wrapper.trigger('mousedown');
+
+ wrapper.trigger('mouseup');
+
+ expect(sidebarEventHub.$emit).toHaveBeenCalledWith('sidebar.closeAll');
+ });
+
+ it('it does not closes all sidebars before showing an issue if an issue is opened', () => {
+ jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
+ const [issue] = list.issues;
+ boardsStore.detail.issue = issue;
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+
+ expect(sidebarEventHub.$emit).not.toHaveBeenCalledWith('sidebar.closeAll');
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js b/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
index 426c5289ba6..9853c9f434f 100644
--- a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
+++ b/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
@@ -11,7 +11,7 @@ import '~/boards/models/label';
import '~/boards/models/assignee';
import '~/boards/models/list';
import BoardCardLayout from '~/boards/components/board_card_layout_deprecated.vue';
-import issueCardInner from '~/boards/components/issue_card_inner.vue';
+import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue';
import { ISSUABLE } from '~/boards/constants';
import boardsVuexStore from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store';
diff --git a/spec/frontend/boards/components/board_card_layout_spec.js b/spec/frontend/boards/components/board_card_layout_spec.js
deleted file mode 100644
index 3fa8714807c..00000000000
--- a/spec/frontend/boards/components/board_card_layout_spec.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import Vuex from 'vuex';
-
-import BoardCardLayout from '~/boards/components/board_card_layout.vue';
-import IssueCardInner from '~/boards/components/issue_card_inner.vue';
-import { ISSUABLE } from '~/boards/constants';
-import defaultState from '~/boards/stores/state';
-import { mockLabelList, mockIssue } from '../mock_data';
-
-describe('Board card layout', () => {
- let wrapper;
- let store;
-
- const localVue = createLocalVue();
- localVue.use(Vuex);
-
- const createStore = ({ getters = {}, actions = {} } = {}) => {
- store = new Vuex.Store({
- state: defaultState,
- actions,
- getters,
- });
- };
-
- // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
- const mountComponent = ({ propsData = {}, provide = {} } = {}) => {
- wrapper = shallowMount(BoardCardLayout, {
- localVue,
- stubs: {
- IssueCardInner,
- },
- store,
- propsData: {
- list: mockLabelList,
- issue: mockIssue,
- disabled: false,
- index: 0,
- ...propsData,
- },
- provide: {
- groupId: null,
- rootPath: '/',
- scopedLabelsAvailable: false,
- ...provide,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('mouse events', () => {
- it('sets showDetail to true on mousedown', async () => {
- createStore();
- mountComponent();
-
- wrapper.trigger('mousedown');
- await wrapper.vm.$nextTick();
-
- expect(wrapper.vm.showDetail).toBe(true);
- });
-
- it('sets showDetail to false on mousemove', async () => {
- createStore();
- mountComponent();
- wrapper.trigger('mousedown');
- await wrapper.vm.$nextTick();
- expect(wrapper.vm.showDetail).toBe(true);
- wrapper.trigger('mousemove');
- await wrapper.vm.$nextTick();
- expect(wrapper.vm.showDetail).toBe(false);
- });
-
- it("calls 'setActiveId'", async () => {
- const setActiveId = jest.fn();
- createStore({
- actions: {
- setActiveId,
- },
- });
- mountComponent();
-
- wrapper.trigger('mouseup');
- await wrapper.vm.$nextTick();
-
- expect(setActiveId).toHaveBeenCalledTimes(1);
- expect(setActiveId).toHaveBeenCalledWith(expect.any(Object), {
- id: mockIssue.id,
- sidebarType: ISSUABLE,
- });
- });
-
- it("calls 'setActiveId' when epic swimlanes is active", async () => {
- const setActiveId = jest.fn();
- const isSwimlanesOn = () => true;
- createStore({
- getters: { isSwimlanesOn },
- actions: {
- setActiveId,
- },
- });
- mountComponent();
-
- wrapper.trigger('mouseup');
- await wrapper.vm.$nextTick();
-
- expect(setActiveId).toHaveBeenCalledTimes(1);
- expect(setActiveId).toHaveBeenCalledWith(expect.any(Object), {
- id: mockIssue.id,
- sidebarType: ISSUABLE,
- });
- });
- });
-});
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index 5f26ae1bb3b..022f8c05e1e 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -1,43 +1,50 @@
-/* global List */
-/* global ListAssignee */
-/* global ListLabel */
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
-import { mount } from '@vue/test-utils';
-
-import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
import BoardCard from '~/boards/components/board_card.vue';
-import issueCardInner from '~/boards/components/issue_card_inner.vue';
-import eventHub from '~/boards/eventhub';
-import store from '~/boards/stores';
-import boardsStore from '~/boards/stores/boards_store';
-import axios from '~/lib/utils/axios_utils';
-
-import sidebarEventHub from '~/sidebar/event_hub';
-import '~/boards/models/label';
-import '~/boards/models/assignee';
-import '~/boards/models/list';
-import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data';
-
-describe('BoardCard', () => {
- let wrapper;
- let mock;
- let list;
+import BoardCardInner from '~/boards/components/board_card_inner.vue';
+import { inactiveId } from '~/boards/constants';
+import { mockLabelList, mockIssue } from '../mock_data';
- const findIssueCardInner = () => wrapper.find(issueCardInner);
- const findUserAvatarLink = () => wrapper.find(userAvatarLink);
+describe('Board card', () => {
+ let wrapper;
+ let store;
+ let mockActions;
+
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
+
+ const createStore = ({ initialState = {}, isSwimlanesOn = false } = {}) => {
+ mockActions = {
+ toggleBoardItem: jest.fn(),
+ toggleBoardItemMultiSelection: jest.fn(),
+ };
+
+ store = new Vuex.Store({
+ state: {
+ activeId: inactiveId,
+ selectedBoardItems: [],
+ ...initialState,
+ },
+ actions: mockActions,
+ getters: {
+ isSwimlanesOn: () => isSwimlanesOn,
+ isEpicBoard: () => false,
+ },
+ });
+ };
// this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
- const mountComponent = (propsData) => {
- wrapper = mount(BoardCard, {
+ const mountComponent = ({ propsData = {}, provide = {} } = {}) => {
+ wrapper = shallowMount(BoardCard, {
+ localVue,
stubs: {
- issueCardInner,
+ BoardCardInner,
},
store,
propsData: {
- list,
- issue: list.issues[0],
+ list: mockLabelList,
+ item: mockIssue,
disabled: false,
index: 0,
...propsData,
@@ -46,174 +53,94 @@ describe('BoardCard', () => {
groupId: null,
rootPath: '/',
scopedLabelsAvailable: false,
+ ...provide,
},
});
};
- const setupData = async () => {
- list = new List(listObj);
- boardsStore.create();
- boardsStore.detail.issue = {};
- const label1 = new ListLabel({
- id: 3,
- title: 'testing 123',
- color: '#000cff',
- text_color: 'white',
- description: 'test',
- });
- await waitForPromises();
-
- list.issues[0].labels.push(label1);
+ const selectCard = async () => {
+ wrapper.trigger('mouseup');
+ await wrapper.vm.$nextTick();
};
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onAny().reply(boardsMockInterceptor);
- setMockEndpoints();
- return setupData();
- });
+ const multiSelectCard = async () => {
+ wrapper.trigger('mouseup', { ctrlKey: true });
+ await wrapper.vm.$nextTick();
+ };
afterEach(() => {
wrapper.destroy();
wrapper = null;
- list = null;
- mock.restore();
- });
-
- it('when details issue is empty does not show the element', () => {
- mountComponent();
- expect(wrapper.find('[data-testid="board_card"').classes()).not.toContain('is-active');
- });
-
- it('when detailIssue is equal to card issue shows the element', () => {
- [boardsStore.detail.issue] = list.issues;
- mountComponent();
-
- expect(wrapper.classes()).toContain('is-active');
- });
-
- it('when multiSelect does not contain issue removes multi select class', () => {
- mountComponent();
- expect(wrapper.classes()).not.toContain('multi-select');
- });
-
- it('when multiSelect contain issue add multi select class', () => {
- boardsStore.multiSelect.list = [list.issues[0]];
- mountComponent();
-
- expect(wrapper.classes()).toContain('multi-select');
- });
-
- it('adds user-can-drag class if not disabled', () => {
- mountComponent();
- expect(wrapper.classes()).toContain('user-can-drag');
- });
-
- it('does not add user-can-drag class disabled', () => {
- mountComponent({ disabled: true });
-
- expect(wrapper.classes()).not.toContain('user-can-drag');
- });
-
- it('does not add disabled class', () => {
- mountComponent();
- expect(wrapper.classes()).not.toContain('is-disabled');
+ store = null;
});
- it('adds disabled class is disabled is true', () => {
- mountComponent({ disabled: true });
-
- expect(wrapper.classes()).toContain('is-disabled');
- });
-
- describe('mouse events', () => {
- it('does not set detail issue if showDetail is false', () => {
+ describe.each`
+ isSwimlanesOn
+ ${true} | ${false}
+ `('when isSwimlanesOn is $isSwimlanesOn', ({ isSwimlanesOn }) => {
+ it('should not highlight the card by default', async () => {
+ createStore({ isSwimlanesOn });
mountComponent();
- expect(boardsStore.detail.issue).toEqual({});
- });
- it('does not set detail issue if link is clicked', () => {
- mountComponent();
- findIssueCardInner().find('a').trigger('mouseup');
-
- expect(boardsStore.detail.issue).toEqual({});
+ expect(wrapper.classes()).not.toContain('is-active');
+ expect(wrapper.classes()).not.toContain('multi-select');
});
- it('does not set detail issue if img is clicked', () => {
- mountComponent({
- issue: {
- ...list.issues[0],
- assignees: [
- new ListAssignee({
- id: 1,
- name: 'testing 123',
- username: 'test',
- avatar: 'test_image',
- }),
- ],
+ it('should highlight the card with a correct style when selected', async () => {
+ createStore({
+ initialState: {
+ activeId: mockIssue.id,
},
+ isSwimlanesOn,
});
-
- findUserAvatarLink().trigger('mouseup');
-
- expect(boardsStore.detail.issue).toEqual({});
- });
-
- it('does not set detail issue if showDetail is false after mouseup', () => {
- mountComponent();
- wrapper.trigger('mouseup');
-
- expect(boardsStore.detail.issue).toEqual({});
- });
-
- it('sets detail issue to card issue on mouse up', () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
mountComponent();
- wrapper.trigger('mousedown');
- wrapper.trigger('mouseup');
-
- expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', wrapper.vm.issue, false);
- expect(boardsStore.detail.list).toEqual(wrapper.vm.list);
+ expect(wrapper.classes()).toContain('is-active');
+ expect(wrapper.classes()).not.toContain('multi-select');
});
- it('resets detail issue to empty if already set', () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- const [issue] = list.issues;
- boardsStore.detail.issue = issue;
+ it('should highlight the card with a correct style when multi-selected', async () => {
+ createStore({
+ initialState: {
+ activeId: inactiveId,
+ selectedBoardItems: [mockIssue],
+ },
+ isSwimlanesOn,
+ });
mountComponent();
- wrapper.trigger('mousedown');
- wrapper.trigger('mouseup');
-
- expect(eventHub.$emit).toHaveBeenCalledWith('clearDetailIssue', false);
+ expect(wrapper.classes()).toContain('multi-select');
+ expect(wrapper.classes()).not.toContain('is-active');
});
- });
-
- describe('sidebarHub events', () => {
- it('closes all sidebars before showing an issue if no issues are opened', () => {
- jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
- boardsStore.detail.issue = {};
- mountComponent();
-
- // sets conditional so that event is emitted.
- wrapper.trigger('mousedown');
- wrapper.trigger('mouseup');
+ describe('when mouseup event is called on the card', () => {
+ beforeEach(() => {
+ createStore({ isSwimlanesOn });
+ mountComponent();
+ });
- expect(sidebarEventHub.$emit).toHaveBeenCalledWith('sidebar.closeAll');
- });
+ describe('when not using multi-select', () => {
+ it('should call vuex action "toggleBoardItem" with correct parameters', async () => {
+ await selectCard();
- it('it does not closes all sidebars before showing an issue if an issue is opened', () => {
- jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
- const [issue] = list.issues;
- boardsStore.detail.issue = issue;
- mountComponent();
+ expect(mockActions.toggleBoardItem).toHaveBeenCalledTimes(1);
+ expect(mockActions.toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), {
+ boardItem: mockIssue,
+ });
+ });
+ });
- wrapper.trigger('mousedown');
+ describe('when using multi-select', () => {
+ it('should call vuex action "multiSelectBoardItem" with correct parameters', async () => {
+ await multiSelectCard();
- expect(sidebarEventHub.$emit).not.toHaveBeenCalledWith('sidebar.closeAll');
+ expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledTimes(1);
+ expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledWith(
+ expect.any(Object),
+ mockIssue,
+ );
+ });
+ });
});
});
});
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index 858efea99ad..32499bd5480 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -8,6 +8,7 @@ import { formType } from '~/boards/constants';
import createBoardMutation from '~/boards/graphql/board_create.mutation.graphql';
import destroyBoardMutation from '~/boards/graphql/board_destroy.mutation.graphql';
import updateBoardMutation from '~/boards/graphql/board_update.mutation.graphql';
+import { createStore } from '~/boards/stores';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { visitUrl } from '~/lib/utils/url_utility';
@@ -48,6 +49,13 @@ describe('BoardForm', () => {
const findDeleteConfirmation = () => wrapper.find('[data-testid="delete-confirmation-message"]');
const findInput = () => wrapper.find('#board-new-name');
+ const store = createStore({
+ getters: {
+ isGroupBoard: () => true,
+ isProjectBoard: () => false,
+ },
+ });
+
const createComponent = (props, data) => {
wrapper = shallowMount(BoardForm, {
propsData: { ...defaultProps, ...props },
@@ -64,6 +72,7 @@ describe('BoardForm', () => {
mutate,
},
},
+ store,
attachTo: document.body,
});
};
diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js
index f30e3792435..d2dfb4148b3 100644
--- a/spec/frontend/boards/components/board_list_header_spec.js
+++ b/spec/frontend/boards/components/board_list_header_spec.js
@@ -1,5 +1,6 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { mockLabelList } from 'jest/boards/mock_data';
import BoardListHeader from '~/boards/components/board_list_header.vue';
@@ -14,6 +15,7 @@ describe('Board List Header Component', () => {
let store;
const updateListSpy = jest.fn();
+ const toggleListCollapsedSpy = jest.fn();
afterEach(() => {
wrapper.destroy();
@@ -43,38 +45,39 @@ describe('Board List Header Component', () => {
if (withLocalStorage) {
localStorage.setItem(
- `boards.${boardId}.${listMock.listType}.${listMock.id}.expanded`,
- (!collapsed).toString(),
+ `boards.${boardId}.${listMock.listType}.${listMock.id}.collapsed`,
+ collapsed.toString(),
);
}
store = new Vuex.Store({
state: {},
- actions: { updateList: updateListSpy },
- getters: {},
+ actions: { updateList: updateListSpy, toggleListCollapsed: toggleListCollapsedSpy },
+ getters: { isEpicBoard: () => false },
});
- wrapper = shallowMount(BoardListHeader, {
- store,
- localVue,
- propsData: {
- disabled: false,
- list: listMock,
- },
- provide: {
- boardId,
- weightFeatureAvailable: false,
- currentUserId,
- },
- });
+ wrapper = extendedWrapper(
+ shallowMount(BoardListHeader, {
+ store,
+ localVue,
+ propsData: {
+ disabled: false,
+ list: listMock,
+ },
+ provide: {
+ boardId,
+ weightFeatureAvailable: false,
+ currentUserId,
+ },
+ }),
+ );
};
const isCollapsed = () => wrapper.vm.list.collapsed;
- const isExpanded = () => !isCollapsed;
const findAddIssueButton = () => wrapper.find({ ref: 'newIssueBtn' });
const findTitle = () => wrapper.find('.board-title');
- const findCaret = () => wrapper.find('.board-title-caret');
+ const findCaret = () => wrapper.findByTestId('board-title-caret');
describe('Add issue button', () => {
const hasNoAddButton = [ListType.closed];
@@ -114,40 +117,29 @@ describe('Board List Header Component', () => {
});
describe('expanding / collapsing the column', () => {
- it('does not collapse when clicking the header', async () => {
+ it('should display collapse icon when column is expanded', async () => {
createComponent();
- expect(isCollapsed()).toBe(false);
-
- wrapper.find('[data-testid="board-list-header"]').trigger('click');
+ const icon = findCaret();
- await wrapper.vm.$nextTick();
-
- expect(isCollapsed()).toBe(false);
+ expect(icon.props('icon')).toBe('chevron-right');
});
- it('collapses expanded Column when clicking the collapse icon', async () => {
- createComponent();
-
- expect(isCollapsed()).toBe(false);
-
- findCaret().vm.$emit('click');
+ it('should display expand icon when column is collapsed', async () => {
+ createComponent({ collapsed: true });
- await wrapper.vm.$nextTick();
+ const icon = findCaret();
- expect(isCollapsed()).toBe(true);
+ expect(icon.props('icon')).toBe('chevron-down');
});
- it('expands collapsed Column when clicking the expand icon', async () => {
- createComponent({ collapsed: true });
-
- expect(isCollapsed()).toBe(true);
+ it('should dispatch toggleListCollapse when clicking the collapse icon', async () => {
+ createComponent();
findCaret().vm.$emit('click');
await wrapper.vm.$nextTick();
-
- expect(isCollapsed()).toBe(false);
+ expect(toggleListCollapsedSpy).toHaveBeenCalledTimes(1);
});
it("when logged in it calls list update and doesn't set localStorage", async () => {
@@ -157,7 +149,7 @@ describe('Board List Header Component', () => {
await wrapper.vm.$nextTick();
expect(updateListSpy).toHaveBeenCalledTimes(1);
- expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.expanded`)).toBe(null);
+ expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.collapsed`)).toBe(null);
});
it("when logged out it doesn't call list update and sets localStorage", async () => {
@@ -167,7 +159,7 @@ describe('Board List Header Component', () => {
await wrapper.vm.$nextTick();
expect(updateListSpy).not.toHaveBeenCalled();
- expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.expanded`)).toBe(String(isExpanded()));
+ expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.collapsed`)).toBe(String(isCollapsed()));
});
});
diff --git a/spec/frontend/boards/components/board_new_issue_spec.js b/spec/frontend/boards/components/board_new_issue_spec.js
index ce8c95527e9..737a18294bc 100644
--- a/spec/frontend/boards/components/board_new_issue_spec.js
+++ b/spec/frontend/boards/components/board_new_issue_spec.js
@@ -2,7 +2,6 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import BoardNewIssue from '~/boards/components/board_new_issue.vue';
-import '~/boards/models/list';
import { mockList, mockGroupProjects } from '../mock_data';
const localVue = createLocalVue();
@@ -31,7 +30,7 @@ describe('Issue boards new issue form', () => {
const store = new Vuex.Store({
state: { selectedProject: mockGroupProjects[0] },
actions: { addListNewIssue: addListNewIssuesSpy },
- getters: {},
+ getters: { isGroupBoard: () => false, isProjectBoard: () => true },
});
wrapper = shallowMount(BoardNewIssue, {
diff --git a/spec/frontend/boards/components/filtered_search_spec.js b/spec/frontend/boards/components/filtered_search_spec.js
new file mode 100644
index 00000000000..7f238aa671f
--- /dev/null
+++ b/spec/frontend/boards/components/filtered_search_spec.js
@@ -0,0 +1,65 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
+import FilteredSearch from '~/boards/components/filtered_search.vue';
+import { createStore } from '~/boards/stores';
+import * as commonUtils from '~/lib/utils/common_utils';
+import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('FilteredSearch', () => {
+ let wrapper;
+ let store;
+
+ const createComponent = () => {
+ wrapper = shallowMount(FilteredSearch, {
+ localVue,
+ propsData: { search: '' },
+ store,
+ attachTo: document.body,
+ });
+ };
+
+ beforeEach(() => {
+ // this needed for actions call for performSearch
+ window.gon = { features: {} };
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ store = createStore();
+
+ jest.spyOn(store, 'dispatch');
+
+ createComponent();
+ });
+
+ it('finds FilteredSearch', () => {
+ expect(wrapper.find(FilteredSearchBarRoot).exists()).toBe(true);
+ });
+
+ describe('when onFilter is emitted', () => {
+ it('calls performSearch', () => {
+ wrapper.find(FilteredSearchBarRoot).vm.$emit('onFilter', [{ value: { data: '' } }]);
+
+ expect(store.dispatch).toHaveBeenCalledWith('performSearch');
+ });
+
+ it('calls historyPushState', () => {
+ commonUtils.historyPushState = jest.fn();
+ wrapper
+ .find(FilteredSearchBarRoot)
+ .vm.$emit('onFilter', [{ value: { data: 'searchQuery' } }]);
+
+ expect(commonUtils.historyPushState).toHaveBeenCalledWith(
+ 'http://test.host/?search=searchQuery',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/issue_count_spec.js b/spec/frontend/boards/components/item_count_spec.js
index f1870e9cc9e..45980c36f1c 100644
--- a/spec/frontend/boards/components/issue_count_spec.js
+++ b/spec/frontend/boards/components/item_count_spec.js
@@ -1,10 +1,10 @@
import { shallowMount } from '@vue/test-utils';
-import IssueCount from '~/boards/components/issue_count.vue';
+import IssueCount from '~/boards/components/item_count.vue';
describe('IssueCount', () => {
let vm;
let maxIssueCount;
- let issuesSize;
+ let itemsSize;
const createComponent = (props) => {
vm = shallowMount(IssueCount, { propsData: props });
@@ -12,20 +12,20 @@ describe('IssueCount', () => {
afterEach(() => {
maxIssueCount = 0;
- issuesSize = 0;
+ itemsSize = 0;
if (vm) vm.destroy();
});
describe('when maxIssueCount is zero', () => {
beforeEach(() => {
- issuesSize = 3;
+ itemsSize = 3;
- createComponent({ maxIssueCount: 0, issuesSize });
+ createComponent({ maxIssueCount: 0, itemsSize });
});
it('contains issueSize in the template', () => {
- expect(vm.find('.js-issue-size').text()).toEqual(String(issuesSize));
+ expect(vm.find('[data-testid="board-items-count"]').text()).toEqual(String(itemsSize));
});
it('does not contains maxIssueCount in the template', () => {
@@ -36,9 +36,9 @@ describe('IssueCount', () => {
describe('when maxIssueCount is greater than zero', () => {
beforeEach(() => {
maxIssueCount = 2;
- issuesSize = 1;
+ itemsSize = 1;
- createComponent({ maxIssueCount, issuesSize });
+ createComponent({ maxIssueCount, itemsSize });
});
afterEach(() => {
@@ -46,7 +46,7 @@ describe('IssueCount', () => {
});
it('contains issueSize in the template', () => {
- expect(vm.find('.js-issue-size').text()).toEqual(String(issuesSize));
+ expect(vm.find('[data-testid="board-items-count"]').text()).toEqual(String(itemsSize));
});
it('contains maxIssueCount in the template', () => {
@@ -60,10 +60,10 @@ describe('IssueCount', () => {
describe('when issueSize is greater than maxIssueCount', () => {
beforeEach(() => {
- issuesSize = 3;
+ itemsSize = 3;
maxIssueCount = 2;
- createComponent({ maxIssueCount, issuesSize });
+ createComponent({ maxIssueCount, itemsSize });
});
afterEach(() => {
@@ -71,7 +71,7 @@ describe('IssueCount', () => {
});
it('contains issueSize in the template', () => {
- expect(vm.find('.js-issue-size').text()).toEqual(String(issuesSize));
+ expect(vm.find('[data-testid="board-items-count"]').text()).toEqual(String(itemsSize));
});
it('contains maxIssueCount in the template', () => {
@@ -79,7 +79,7 @@ describe('IssueCount', () => {
});
it('has text-danger class', () => {
- expect(vm.find('.text-danger').text()).toEqual(String(issuesSize));
+ expect(vm.find('.text-danger').text()).toEqual(String(itemsSize));
});
});
});
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_due_date_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_due_date_spec.js
index 7838b5a0b2f..8fd178a0856 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_due_date_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_due_date_spec.js
@@ -24,7 +24,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
const createWrapper = ({ dueDate = null } = {}) => {
store = createStore();
- store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, dueDate } };
+ store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, dueDate } };
store.state.activeId = TEST_ISSUE.id;
wrapper = shallowMount(BoardSidebarDueDate, {
@@ -61,7 +61,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
- store.state.issues[TEST_ISSUE.id].dueDate = TEST_DUE_DATE;
+ store.state.boardItems[TEST_ISSUE.id].dueDate = TEST_DUE_DATE;
});
findDatePicker().vm.$emit('input', TEST_PARSED_DATE);
await wrapper.vm.$nextTick();
@@ -86,7 +86,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
- store.state.issues[TEST_ISSUE.id].dueDate = null;
+ store.state.boardItems[TEST_ISSUE.id].dueDate = null;
});
findDatePicker().vm.$emit('clear');
await wrapper.vm.$nextTick();
@@ -104,7 +104,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
createWrapper({ dueDate: TEST_DUE_DATE });
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
- store.state.issues[TEST_ISSUE.id].dueDate = null;
+ store.state.boardItems[TEST_ISSUE.id].dueDate = null;
});
findResetButton().vm.$emit('click');
await wrapper.vm.$nextTick();
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_issue_title_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_issue_title_spec.js
index bc7df1c76c6..723d0345f76 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_issue_title_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_issue_title_spec.js
@@ -34,7 +34,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
const createWrapper = (issue = TEST_ISSUE_A) => {
store = createStore();
- store.state.issues = { [issue.id]: { ...issue } };
+ store.state.boardItems = { [issue.id]: { ...issue } };
store.dispatch('setActiveId', { id: issue.id });
wrapper = shallowMount(BoardSidebarIssueTitle, {
@@ -74,7 +74,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => {
- store.state.issues[TEST_ISSUE_A.id].title = TEST_TITLE;
+ store.state.boardItems[TEST_ISSUE_A.id].title = TEST_TITLE;
});
findFormInput().vm.$emit('input', TEST_TITLE);
findForm().vm.$emit('submit', { preventDefault: () => {} });
@@ -147,7 +147,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
createWrapper(TEST_ISSUE_B);
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => {
- store.state.issues[TEST_ISSUE_B.id].title = TEST_TITLE;
+ store.state.boardItems[TEST_ISSUE_B.id].title = TEST_TITLE;
});
findFormInput().vm.$emit('input', TEST_TITLE);
findCancelButton().vm.$emit('click');
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 12b873ba7d8..98ac211238c 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
@@ -25,7 +25,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
const createWrapper = ({ labels = [] } = {}) => {
store = createStore();
- store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } };
+ store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } };
store.state.activeId = TEST_ISSUE.id;
wrapper = shallowMount(BoardSidebarLabelsSelect, {
@@ -66,7 +66,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => TEST_LABELS);
findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD);
- store.state.issues[TEST_ISSUE.id].labels = TEST_LABELS;
+ store.state.boardItems[TEST_ISSUE.id].labels = TEST_LABELS;
await wrapper.vm.$nextTick();
});
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
index 8820ec7ae63..8706424a296 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
@@ -22,7 +22,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
const createWrapper = ({ milestone = null, loading = false } = {}) => {
store = createStore();
- store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, milestone } };
+ store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, milestone } };
store.state.activeId = TEST_ISSUE.id;
wrapper = shallowMount(BoardSidebarMilestoneSelect, {
@@ -113,7 +113,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueMilestone').mockImplementation(() => {
- store.state.issues[TEST_ISSUE.id].milestone = TEST_MILESTONE;
+ store.state.boardItems[TEST_ISSUE.id].milestone = TEST_MILESTONE;
});
findDropdownItem().vm.$emit('click');
await wrapper.vm.$nextTick();
@@ -137,7 +137,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
createWrapper({ milestone: TEST_MILESTONE });
jest.spyOn(wrapper.vm, 'setActiveIssueMilestone').mockImplementation(() => {
- store.state.issues[TEST_ISSUE.id].milestone = null;
+ store.state.boardItems[TEST_ISSUE.id].milestone = null;
});
findUnsetMilestoneItem().vm.$emit('click');
await wrapper.vm.$nextTick();
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 3e6b0be0267..cfd7f32b2cc 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_subscription_spec.js
@@ -22,7 +22,7 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
const createComponent = (activeIssue = { ...mockActiveIssue }) => {
store = createStore();
- store.state.issues = { [activeIssue.id]: activeIssue };
+ store.state.boardItems = { [activeIssue.id]: activeIssue };
store.state.activeId = activeIssue.id;
wrapper = mount(BoardSidebarSubscription, {
@@ -45,6 +45,12 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
expect(findNotificationHeader().text()).toBe('Notifications');
});
+ it('renders toggle with label', () => {
+ createComponent();
+
+ expect(findToggle().props('label')).toBe(BoardSidebarSubscription.i18n.header.title);
+ });
+
it('renders toggle as "off" when currently not subscribed', () => {
createComponent();
diff --git a/spec/frontend/boards/components/sidebar/remove_issue_spec.js b/spec/frontend/boards/components/sidebar/remove_issue_spec.js
deleted file mode 100644
index 1f740c10106..00000000000
--- a/spec/frontend/boards/components/sidebar/remove_issue_spec.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-
-import RemoveIssue from '~/boards/components/sidebar/remove_issue.vue';
-
-describe('boards sidebar remove issue', () => {
- let wrapper;
-
- const findButton = () => wrapper.find(GlButton);
-
- const createComponent = (propsData) => {
- wrapper = shallowMount(RemoveIssue, {
- propsData: {
- issue: {},
- list: {},
- ...propsData,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('renders remove button', () => {
- expect(findButton().exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index e106b9235d6..500240d00fc 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -351,6 +351,7 @@ export const issues = {
[mockIssue4.id]: mockIssue4,
};
+// The response from group project REST API
export const mockRawGroupProjects = [
{
id: 0,
@@ -366,17 +367,34 @@ export const mockRawGroupProjects = [
},
];
-export const mockGroupProjects = [
- {
- id: 0,
- name: 'Example Project',
- nameWithNamespace: 'Awesome Group / Example Project',
- fullPath: 'awesome-group/example-project',
- },
- {
- id: 1,
- name: 'Foobar Project',
- nameWithNamespace: 'Awesome Group / Foobar Project',
- fullPath: 'awesome-group/foobar-project',
- },
+// The response from GraphQL endpoint
+export const mockGroupProject1 = {
+ id: 0,
+ name: 'Example Project',
+ nameWithNamespace: 'Awesome Group / Example Project',
+ fullPath: 'awesome-group/example-project',
+ archived: false,
+};
+
+export const mockGroupProject2 = {
+ id: 1,
+ name: 'Foobar Project',
+ nameWithNamespace: 'Awesome Group / Foobar Project',
+ fullPath: 'awesome-group/foobar-project',
+ archived: false,
+};
+
+export const mockArchivedGroupProject = {
+ id: 2,
+ name: 'Archived Project',
+ nameWithNamespace: 'Awesome Group / Archived Project',
+ fullPath: 'awesome-group/archived-project',
+ archived: true,
+};
+
+export const mockGroupProjects = [mockGroupProject1, mockGroupProject2];
+
+export const mockActiveGroupProjects = [
+ { ...mockGroupProject1, archived: false },
+ { ...mockGroupProject2, archived: false },
];
diff --git a/spec/frontend/boards/project_select_deprecated_spec.js b/spec/frontend/boards/project_select_deprecated_spec.js
index 9042c4bf9ba..37f519ef5b9 100644
--- a/spec/frontend/boards/project_select_deprecated_spec.js
+++ b/spec/frontend/boards/project_select_deprecated_spec.js
@@ -27,6 +27,7 @@ const mockDefaultFetchOptions = {
with_shared: false,
include_subgroups: true,
order_by: 'similarity',
+ archived: false,
};
const itemsPerPage = 20;
diff --git a/spec/frontend/boards/project_select_spec.js b/spec/frontend/boards/project_select_spec.js
index aa71952c42b..de823094630 100644
--- a/spec/frontend/boards/project_select_spec.js
+++ b/spec/frontend/boards/project_select_spec.js
@@ -1,30 +1,17 @@
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui';
-import { createLocalVue, mount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
+import Vue from 'vue';
import Vuex from 'vuex';
import ProjectSelect from '~/boards/components/project_select.vue';
import defaultState from '~/boards/stores/state';
-import { mockList, mockGroupProjects } from './mock_data';
+import { mockList, mockActiveGroupProjects } from './mock_data';
-const localVue = createLocalVue();
-localVue.use(Vuex);
-
-const actions = {
- fetchGroupProjects: jest.fn(),
- setSelectedProject: jest.fn(),
-};
-
-const createStore = (state = defaultState) => {
- return new Vuex.Store({
- state,
- actions,
- });
-};
-
-const mockProjectsList1 = mockGroupProjects.slice(0, 1);
+const mockProjectsList1 = mockActiveGroupProjects.slice(0, 1);
describe('ProjectSelect component', () => {
let wrapper;
+ let store;
const findLabel = () => wrapper.find("[data-testid='header-label']");
const findGlDropdown = () => wrapper.find(GlDropdown);
@@ -36,20 +23,37 @@ describe('ProjectSelect component', () => {
const findInMenuLoadingIcon = () => wrapper.find("[data-testid='dropdown-text-loading-icon']");
const findEmptySearchMessage = () => wrapper.find("[data-testid='empty-result-message']");
- const createWrapper = (state = {}) => {
- const store = createStore({
- groupProjects: [],
- groupProjectsFlags: {
- isLoading: false,
- pageInfo: {
- hasNextPage: false,
+ const createStore = ({ state, activeGroupProjects }) => {
+ Vue.use(Vuex);
+
+ store = new Vuex.Store({
+ state: {
+ defaultState,
+ groupProjectsFlags: {
+ isLoading: false,
+ pageInfo: {
+ hasNextPage: false,
+ },
},
+ ...state,
+ },
+ actions: {
+ fetchGroupProjects: jest.fn(),
+ setSelectedProject: jest.fn(),
},
- ...state,
+ getters: {
+ activeGroupProjects: () => activeGroupProjects,
+ },
+ });
+ };
+
+ const createWrapper = ({ state = {}, activeGroupProjects = [] } = {}) => {
+ createStore({
+ state,
+ activeGroupProjects,
});
wrapper = mount(ProjectSelect, {
- localVue,
propsData: {
list: mockList,
},
@@ -93,7 +97,7 @@ describe('ProjectSelect component', () => {
describe('when dropdown menu is open', () => {
describe('by default', () => {
beforeEach(() => {
- createWrapper({ groupProjects: mockGroupProjects });
+ createWrapper({ activeGroupProjects: mockActiveGroupProjects });
});
it('shows GlSearchBoxByType with default attributes', () => {
@@ -128,7 +132,7 @@ describe('ProjectSelect component', () => {
describe('when a project is selected', () => {
beforeEach(() => {
- createWrapper({ groupProjects: mockProjectsList1 });
+ createWrapper({ activeGroupProjects: mockProjectsList1 });
findFirstGlDropdownItem().find('button').trigger('click');
});
@@ -142,7 +146,7 @@ describe('ProjectSelect component', () => {
describe('when projects are loading', () => {
beforeEach(() => {
- createWrapper({ groupProjectsFlags: { isLoading: true } });
+ createWrapper({ state: { groupProjectsFlags: { isLoading: true } } });
});
it('displays and hides gl-loading-icon while and after fetching data', () => {
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index 32d0e7ae886..69d2c8977fb 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -5,7 +5,7 @@ import {
formatBoardLists,
formatIssueInput,
} from '~/boards/boards_util';
-import { inactiveId } from '~/boards/constants';
+import { inactiveId, ISSUABLE } from '~/boards/constants';
import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutation.graphql';
import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql';
import issueMoveListMutation from '~/boards/graphql/issue_move_list.mutation.graphql';
@@ -112,6 +112,15 @@ describe('setActiveId', () => {
});
describe('fetchLists', () => {
+ it('should dispatch fetchIssueLists action', () => {
+ testAction({
+ action: actions.fetchLists,
+ expectedActions: [{ type: 'fetchIssueLists' }],
+ });
+ });
+});
+
+describe('fetchIssueLists', () => {
const state = {
fullPath: 'gitlab-org',
boardId: '1',
@@ -138,7 +147,7 @@ describe('fetchLists', () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
- actions.fetchLists,
+ actions.fetchIssueLists,
{},
state,
[
@@ -152,6 +161,23 @@ describe('fetchLists', () => {
);
});
+ it('should commit mutations RECEIVE_BOARD_LISTS_FAILURE on failure', (done) => {
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
+
+ testAction(
+ actions.fetchIssueLists,
+ {},
+ state,
+ [
+ {
+ type: types.RECEIVE_BOARD_LISTS_FAILURE,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+
it('dispatch createList action when backlog list does not exist and is not hidden', (done) => {
queryResponse = {
data: {
@@ -168,7 +194,7 @@ describe('fetchLists', () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
- actions.fetchLists,
+ actions.fetchIssueLists,
{},
state,
[
@@ -184,6 +210,16 @@ describe('fetchLists', () => {
});
describe('createList', () => {
+ it('should dispatch createIssueList action', () => {
+ testAction({
+ action: actions.createList,
+ payload: { backlog: true },
+ expectedActions: [{ type: 'createIssueList', payload: { backlog: true } }],
+ });
+ });
+});
+
+describe('createIssueList', () => {
let commit;
let dispatch;
let getters;
@@ -223,7 +259,7 @@ describe('createList', () => {
}),
);
- await actions.createList({ getters, state, commit, dispatch }, { backlog: true });
+ await actions.createIssueList({ getters, state, commit, dispatch }, { backlog: true });
expect(dispatch).toHaveBeenCalledWith('addList', backlogList);
});
@@ -245,7 +281,7 @@ describe('createList', () => {
},
});
- await actions.createList({ getters, state, commit, dispatch }, { labelId: '4' });
+ await actions.createIssueList({ getters, state, commit, dispatch }, { labelId: '4' });
expect(dispatch).toHaveBeenCalledWith('addList', list);
expect(dispatch).toHaveBeenCalledWith('highlightList', list.id);
@@ -257,15 +293,15 @@ describe('createList', () => {
data: {
boardListCreate: {
list: {},
- errors: [{ foo: 'bar' }],
+ errors: ['foo'],
},
},
}),
);
- await actions.createList({ getters, state, commit, dispatch }, { backlog: true });
+ await actions.createIssueList({ getters, state, commit, dispatch }, { backlog: true });
- expect(commit).toHaveBeenCalledWith(types.CREATE_LIST_FAILURE);
+ expect(commit).toHaveBeenCalledWith(types.CREATE_LIST_FAILURE, 'foo');
});
it('highlights list and does not re-query if it already exists', async () => {
@@ -280,7 +316,7 @@ describe('createList', () => {
getListByLabelId: jest.fn().mockReturnValue(existingList),
};
- await actions.createList({ getters, state, commit, dispatch }, { backlog: true });
+ await actions.createIssueList({ getters, state, commit, dispatch }, { backlog: true });
expect(dispatch).toHaveBeenCalledWith('highlightList', existingList.id);
expect(dispatch).toHaveBeenCalledTimes(1);
@@ -301,11 +337,15 @@ describe('fetchLabels', () => {
};
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
- await testAction({
- action: actions.fetchLabels,
- state: { boardType: 'group' },
- expectedMutations: [{ type: types.RECEIVE_LABELS_SUCCESS, payload: labels }],
- });
+ const commit = jest.fn();
+ const getters = {
+ shouldUseGraphQL: () => true,
+ };
+ const state = { boardType: 'group' };
+
+ await actions.fetchLabels({ getters, state, commit });
+
+ expect(commit).toHaveBeenCalledWith(types.RECEIVE_LABELS_SUCCESS, labels);
});
});
@@ -412,6 +452,22 @@ describe('updateList', () => {
});
});
+describe('toggleListCollapsed', () => {
+ it('should commit TOGGLE_LIST_COLLAPSED mutation', async () => {
+ const payload = { listId: 'gid://gitlab/List/1', collapsed: true };
+ await testAction({
+ action: actions.toggleListCollapsed,
+ payload,
+ expectedMutations: [
+ {
+ type: types.TOGGLE_LIST_COLLAPSED,
+ payload,
+ },
+ ],
+ });
+ });
+});
+
describe('removeList', () => {
let state;
const list = mockLists[0];
@@ -490,7 +546,7 @@ describe('removeList', () => {
});
});
-describe('fetchIssuesForList', () => {
+describe('fetchItemsForList', () => {
const listId = mockLists[0].id;
const state = {
@@ -533,21 +589,21 @@ describe('fetchIssuesForList', () => {
[listId]: pageInfo,
};
- it('should commit mutations REQUEST_ISSUES_FOR_LIST and RECEIVE_ISSUES_FOR_LIST_SUCCESS on success', (done) => {
+ it('should commit mutations REQUEST_ITEMS_FOR_LIST and RECEIVE_ITEMS_FOR_LIST_SUCCESS on success', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
- actions.fetchIssuesForList,
+ actions.fetchItemsForList,
{ listId },
state,
[
{
- type: types.REQUEST_ISSUES_FOR_LIST,
+ type: types.REQUEST_ITEMS_FOR_LIST,
payload: { listId, fetchNext: false },
},
{
- type: types.RECEIVE_ISSUES_FOR_LIST_SUCCESS,
- payload: { listIssues: formattedIssues, listPageInfo, listId },
+ type: types.RECEIVE_ITEMS_FOR_LIST_SUCCESS,
+ payload: { listItems: formattedIssues, listPageInfo, listId },
},
],
[],
@@ -555,19 +611,19 @@ describe('fetchIssuesForList', () => {
);
});
- it('should commit mutations REQUEST_ISSUES_FOR_LIST and RECEIVE_ISSUES_FOR_LIST_FAILURE on failure', (done) => {
+ it('should commit mutations REQUEST_ITEMS_FOR_LIST and RECEIVE_ITEMS_FOR_LIST_FAILURE on failure', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
testAction(
- actions.fetchIssuesForList,
+ actions.fetchItemsForList,
{ listId },
state,
[
{
- type: types.REQUEST_ISSUES_FOR_LIST,
+ type: types.REQUEST_ITEMS_FOR_LIST,
payload: { listId, fetchNext: false },
},
- { type: types.RECEIVE_ISSUES_FOR_LIST_FAILURE, payload: listId },
+ { type: types.RECEIVE_ITEMS_FOR_LIST_FAILURE, payload: listId },
],
[],
done,
@@ -581,6 +637,15 @@ describe('resetIssues', () => {
});
});
+describe('moveItem', () => {
+ it('should dispatch moveIssue action', () => {
+ testAction({
+ action: actions.moveItem,
+ expectedActions: [{ type: 'moveIssue' }],
+ });
+ });
+});
+
describe('moveIssue', () => {
const listIssues = {
'gid://gitlab/List/1': [436, 437],
@@ -598,8 +663,8 @@ describe('moveIssue', () => {
boardType: 'group',
disabled: false,
boardLists: mockLists,
- issuesByListId: listIssues,
- issues,
+ boardItemsByListId: listIssues,
+ boardItems: issues,
};
it('should commit MOVE_ISSUE mutation and MOVE_ISSUE_SUCCESS mutation when successful', (done) => {
@@ -615,9 +680,9 @@ describe('moveIssue', () => {
testAction(
actions.moveIssue,
{
- issueId: '436',
- issueIid: mockIssue.iid,
- issuePath: mockIssue.referencePath,
+ itemId: '436',
+ itemIid: mockIssue.iid,
+ itemPath: mockIssue.referencePath,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
@@ -666,9 +731,9 @@ describe('moveIssue', () => {
actions.moveIssue(
{ state, commit: () => {} },
{
- issueId: mockIssue.id,
- issueIid: mockIssue.iid,
- issuePath: mockIssue.referencePath,
+ itemId: mockIssue.id,
+ itemIid: mockIssue.iid,
+ itemPath: mockIssue.referencePath,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
@@ -690,9 +755,9 @@ describe('moveIssue', () => {
testAction(
actions.moveIssue,
{
- issueId: '436',
- issueIid: mockIssue.iid,
- issuePath: mockIssue.referencePath,
+ itemId: '436',
+ itemIid: mockIssue.iid,
+ itemPath: mockIssue.referencePath,
fromListId: 'gid://gitlab/List/1',
toListId: 'gid://gitlab/List/2',
},
@@ -879,7 +944,7 @@ describe('addListIssue', () => {
});
describe('setActiveIssueLabels', () => {
- const state = { issues: { [mockIssue.id]: mockIssue } };
+ const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const testLabelIds = labels.map((label) => label.id);
const input = {
@@ -924,7 +989,7 @@ describe('setActiveIssueLabels', () => {
});
describe('setActiveIssueDueDate', () => {
- const state = { issues: { [mockIssue.id]: mockIssue } };
+ const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const testDueDate = '2020-02-20';
const input = {
@@ -975,7 +1040,7 @@ describe('setActiveIssueDueDate', () => {
});
describe('setActiveIssueSubscribed', () => {
- const state = { issues: { [mockActiveIssue.id]: mockActiveIssue } };
+ const state = { boardItems: { [mockActiveIssue.id]: mockActiveIssue } };
const getters = { activeIssue: mockActiveIssue };
const subscribedState = true;
const input = {
@@ -1026,7 +1091,7 @@ describe('setActiveIssueSubscribed', () => {
});
describe('setActiveIssueMilestone', () => {
- const state = { issues: { [mockIssue.id]: mockIssue } };
+ const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const testMilestone = {
...mockMilestone,
@@ -1080,7 +1145,7 @@ describe('setActiveIssueMilestone', () => {
});
describe('setActiveIssueTitle', () => {
- const state = { issues: { [mockIssue.id]: mockIssue } };
+ const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const testTitle = 'Test Title';
const input = {
@@ -1220,6 +1285,7 @@ describe('setSelectedProject', () => {
describe('toggleBoardItemMultiSelection', () => {
const boardItem = mockIssue;
+ const boardItem2 = mockIssue2;
it('should commit mutation ADD_BOARD_ITEM_TO_SELECTION if item is not on selection state', () => {
testAction(
@@ -1250,6 +1316,66 @@ describe('toggleBoardItemMultiSelection', () => {
[],
);
});
+
+ it('should additionally commit mutation ADD_BOARD_ITEM_TO_SELECTION for active issue and dispatch unsetActiveId', () => {
+ testAction(
+ actions.toggleBoardItemMultiSelection,
+ boardItem2,
+ { activeId: mockActiveIssue.id, activeIssue: mockActiveIssue, selectedBoardItems: [] },
+ [
+ {
+ type: types.ADD_BOARD_ITEM_TO_SELECTION,
+ payload: mockActiveIssue,
+ },
+ {
+ type: types.ADD_BOARD_ITEM_TO_SELECTION,
+ payload: boardItem2,
+ },
+ ],
+ [{ type: 'unsetActiveId' }],
+ );
+ });
+});
+
+describe('resetBoardItemMultiSelection', () => {
+ it('should commit mutation RESET_BOARD_ITEM_SELECTION', () => {
+ testAction({
+ action: actions.resetBoardItemMultiSelection,
+ state: { selectedBoardItems: [mockIssue] },
+ expectedMutations: [
+ {
+ type: types.RESET_BOARD_ITEM_SELECTION,
+ },
+ ],
+ });
+ });
+});
+
+describe('toggleBoardItem', () => {
+ it('should dispatch resetBoardItemMultiSelection and unsetActiveId when boardItem is the active item', () => {
+ testAction({
+ action: actions.toggleBoardItem,
+ payload: { boardItem: mockIssue },
+ state: {
+ activeId: mockIssue.id,
+ },
+ expectedActions: [{ type: 'resetBoardItemMultiSelection' }, { type: 'unsetActiveId' }],
+ });
+ });
+
+ it('should dispatch resetBoardItemMultiSelection and setActiveId when boardItem is not the active item', () => {
+ testAction({
+ action: actions.toggleBoardItem,
+ payload: { boardItem: mockIssue },
+ state: {
+ activeId: inactiveId,
+ },
+ expectedActions: [
+ { type: 'resetBoardItemMultiSelection' },
+ { type: 'setActiveId', payload: { id: mockIssue.id, sidebarType: ISSUABLE } },
+ ],
+ });
+ });
});
describe('fetchBacklog', () => {
diff --git a/spec/frontend/boards/stores/getters_spec.js b/spec/frontend/boards/stores/getters_spec.js
index d5a19bf613f..32d73d861bc 100644
--- a/spec/frontend/boards/stores/getters_spec.js
+++ b/spec/frontend/boards/stores/getters_spec.js
@@ -7,9 +7,47 @@ import {
mockIssuesByListId,
issues,
mockLists,
+ mockGroupProject1,
+ mockArchivedGroupProject,
} from '../mock_data';
describe('Boards - Getters', () => {
+ describe('isGroupBoard', () => {
+ it('returns true when boardType on state is group', () => {
+ const state = {
+ boardType: 'group',
+ };
+
+ expect(getters.isGroupBoard(state)).toBe(true);
+ });
+
+ it('returns false when boardType on state is not group', () => {
+ const state = {
+ boardType: 'project',
+ };
+
+ expect(getters.isGroupBoard(state)).toBe(false);
+ });
+ });
+
+ describe('isProjectBoard', () => {
+ it('returns true when boardType on state is project', () => {
+ const state = {
+ boardType: 'project',
+ };
+
+ expect(getters.isProjectBoard(state)).toBe(true);
+ });
+
+ it('returns false when boardType on state is not project', () => {
+ const state = {
+ boardType: 'group',
+ };
+
+ expect(getters.isProjectBoard(state)).toBe(false);
+ });
+ });
+
describe('isSidebarOpen', () => {
it('returns true when activeId is not equal to 0', () => {
const state = {
@@ -38,15 +76,15 @@ describe('Boards - Getters', () => {
});
});
- describe('getIssueById', () => {
- const state = { issues: { 1: 'issue' } };
+ describe('getBoardItemById', () => {
+ const state = { boardItems: { 1: 'issue' } };
it.each`
id | expected
${'1'} | ${'issue'}
${''} | ${{}}
`('returns $expected when $id is passed to state', ({ id, expected }) => {
- expect(getters.getIssueById(state)(id)).toEqual(expected);
+ expect(getters.getBoardItemById(state)(id)).toEqual(expected);
});
});
@@ -56,7 +94,7 @@ describe('Boards - Getters', () => {
${'1'} | ${'issue'}
${''} | ${{}}
`('returns $expected when $id is passed to state', ({ id, expected }) => {
- const state = { issues: { 1: 'issue' }, activeId: id };
+ const state = { boardItems: { 1: 'issue' }, activeId: id };
expect(getters.activeIssue(state)).toEqual(expected);
});
@@ -94,17 +132,18 @@ describe('Boards - Getters', () => {
});
});
- describe('getIssuesByList', () => {
+ describe('getBoardItemsByList', () => {
const boardsState = {
- issuesByListId: mockIssuesByListId,
- issues,
+ boardItemsByListId: mockIssuesByListId,
+ boardItems: issues,
};
it('returns issues for a given listId', () => {
- const getIssueById = (issueId) => [mockIssue, mockIssue2].find(({ id }) => id === issueId);
+ const getBoardItemById = (issueId) =>
+ [mockIssue, mockIssue2].find(({ id }) => id === issueId);
- expect(getters.getIssuesByList(boardsState, { getIssueById })('gid://gitlab/List/2')).toEqual(
- mockIssues,
- );
+ expect(
+ getters.getBoardItemsByList(boardsState, { getBoardItemById })('gid://gitlab/List/2'),
+ ).toEqual(mockIssues);
});
});
@@ -128,4 +167,14 @@ describe('Boards - Getters', () => {
expect(getters.getListByTitle(boardsState)('To Do')).toEqual(mockLists[1]);
});
});
+
+ describe('activeGroupProjects', () => {
+ const state = {
+ groupProjects: [mockGroupProject1, mockArchivedGroupProject],
+ };
+
+ it('returns only returns non-archived group projects', () => {
+ expect(getters.activeGroupProjects(state)).toEqual([mockGroupProject1]);
+ });
+ });
});
diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js
index 9423f2ed583..33897cc0250 100644
--- a/spec/frontend/boards/stores/mutations_spec.js
+++ b/spec/frontend/boards/stores/mutations_spec.js
@@ -1,3 +1,4 @@
+import { issuableTypes } from '~/boards/constants';
import * as types from '~/boards/stores/mutation_types';
import mutations from '~/boards/stores/mutations';
import defaultState from '~/boards/stores/state';
@@ -37,6 +38,7 @@ describe('Board Store Mutations', () => {
const boardConfig = {
milestoneTitle: 'Milestone 1',
};
+ const issuableType = issuableTypes.issue;
mutations[types.SET_INITIAL_BOARD_DATA](state, {
boardId,
@@ -44,6 +46,7 @@ describe('Board Store Mutations', () => {
boardType,
disabled,
boardConfig,
+ issuableType,
});
expect(state.boardId).toEqual(boardId);
@@ -51,6 +54,7 @@ describe('Board Store Mutations', () => {
expect(state.boardType).toEqual(boardType);
expect(state.disabled).toEqual(disabled);
expect(state.boardConfig).toEqual(boardConfig);
+ expect(state.issuableType).toEqual(issuableType);
});
});
@@ -106,11 +110,31 @@ describe('Board Store Mutations', () => {
});
});
+ describe('RECEIVE_LABELS_REQUEST', () => {
+ it('sets labelsLoading on state', () => {
+ mutations.RECEIVE_LABELS_REQUEST(state);
+
+ expect(state.labelsLoading).toEqual(true);
+ });
+ });
+
describe('RECEIVE_LABELS_SUCCESS', () => {
it('sets labels on state', () => {
mutations.RECEIVE_LABELS_SUCCESS(state, labels);
expect(state.labels).toEqual(labels);
+ expect(state.labelsLoading).toEqual(false);
+ });
+ });
+
+ describe('RECEIVE_LABELS_FAILURE', () => {
+ it('sets error message', () => {
+ mutations.RECEIVE_LABELS_FAILURE(state);
+
+ expect(state.error).toEqual(
+ 'An error occurred while fetching labels. Please reload the page.',
+ );
+ expect(state.labelsLoading).toEqual(false);
});
});
@@ -179,6 +203,24 @@ describe('Board Store Mutations', () => {
});
});
+ describe('TOGGLE_LIST_COLLAPSED', () => {
+ it('updates collapsed attribute of list in boardLists state', () => {
+ const listId = 'gid://gitlab/List/1';
+ state = {
+ ...state,
+ boardLists: {
+ [listId]: mockLists[0],
+ },
+ };
+
+ expect(state.boardLists[listId].collapsed).toEqual(false);
+
+ mutations.TOGGLE_LIST_COLLAPSED(state, { listId, collapsed: true });
+
+ expect(state.boardLists[listId].collapsed).toEqual(true);
+ });
+ });
+
describe('REMOVE_LIST', () => {
it('removes list from boardLists', () => {
const [list, secondList] = mockLists;
@@ -219,24 +261,24 @@ describe('Board Store Mutations', () => {
});
describe('RESET_ISSUES', () => {
- it('should remove issues from issuesByListId state', () => {
- const issuesByListId = {
+ it('should remove issues from boardItemsByListId state', () => {
+ const boardItemsByListId = {
'gid://gitlab/List/1': [mockIssue.id],
};
state = {
...state,
- issuesByListId,
+ boardItemsByListId,
};
mutations[types.RESET_ISSUES](state);
- expect(state.issuesByListId).toEqual({ 'gid://gitlab/List/1': [] });
+ expect(state.boardItemsByListId).toEqual({ 'gid://gitlab/List/1': [] });
});
});
- describe('RECEIVE_ISSUES_FOR_LIST_SUCCESS', () => {
- it('updates issuesByListId and issues on state', () => {
+ describe('RECEIVE_ITEMS_FOR_LIST_SUCCESS', () => {
+ it('updates boardItemsByListId and issues on state', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id],
};
@@ -246,10 +288,10 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: {
+ boardItemsByListId: {
'gid://gitlab/List/1': [],
},
- issues: {},
+ boardItems: {},
boardLists: initialBoardListsState,
};
@@ -260,18 +302,18 @@ describe('Board Store Mutations', () => {
},
};
- mutations.RECEIVE_ISSUES_FOR_LIST_SUCCESS(state, {
- listIssues: { listData: listIssues, issues },
+ mutations.RECEIVE_ITEMS_FOR_LIST_SUCCESS(state, {
+ listItems: { listData: listIssues, boardItems: issues },
listPageInfo,
listId: 'gid://gitlab/List/1',
});
- expect(state.issuesByListId).toEqual(listIssues);
- expect(state.issues).toEqual(issues);
+ expect(state.boardItemsByListId).toEqual(listIssues);
+ expect(state.boardItems).toEqual(issues);
});
});
- describe('RECEIVE_ISSUES_FOR_LIST_FAILURE', () => {
+ describe('RECEIVE_ITEMS_FOR_LIST_FAILURE', () => {
it('sets error message', () => {
state = {
...state,
@@ -281,7 +323,7 @@ describe('Board Store Mutations', () => {
const listId = 'gid://gitlab/List/1';
- mutations.RECEIVE_ISSUES_FOR_LIST_FAILURE(state, listId);
+ mutations.RECEIVE_ITEMS_FOR_LIST_FAILURE(state, listId);
expect(state.error).toEqual(
'An error occurred while fetching the board issues. Please reload the page.',
@@ -303,7 +345,7 @@ describe('Board Store Mutations', () => {
state = {
...state,
error: undefined,
- issues: {
+ boardItems: {
...issue,
},
};
@@ -317,7 +359,7 @@ describe('Board Store Mutations', () => {
value,
});
- expect(state.issues[issueId]).toEqual({ ...issue[issueId], id: '2' });
+ expect(state.boardItems[issueId]).toEqual({ ...issue[issueId], id: '2' });
});
});
@@ -343,7 +385,7 @@ describe('Board Store Mutations', () => {
});
describe('MOVE_ISSUE', () => {
- it('updates issuesByListId, moving issue between lists', () => {
+ it('updates boardItemsByListId, moving issue between lists', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
'gid://gitlab/List/2': [],
@@ -356,9 +398,9 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: listIssues,
+ boardItemsByListId: listIssues,
boardLists: initialBoardListsState,
- issues,
+ boardItems: issues,
};
mutations.MOVE_ISSUE(state, {
@@ -372,7 +414,7 @@ describe('Board Store Mutations', () => {
'gid://gitlab/List/2': [mockIssue2.id],
};
- expect(state.issuesByListId).toEqual(updatedListIssues);
+ expect(state.boardItemsByListId).toEqual(updatedListIssues);
});
});
@@ -384,19 +426,19 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issues,
+ boardItems: issues,
};
mutations.MOVE_ISSUE_SUCCESS(state, {
issue: rawIssue,
});
- expect(state.issues).toEqual({ 436: { ...mockIssue, id: 436 } });
+ expect(state.boardItems).toEqual({ 436: { ...mockIssue, id: 436 } });
});
});
describe('MOVE_ISSUE_FAILURE', () => {
- it('updates issuesByListId, reverting moving issue between lists, and sets error message', () => {
+ it('updates boardItemsByListId, reverting moving issue between lists, and sets error message', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id],
'gid://gitlab/List/2': [mockIssue2.id],
@@ -404,7 +446,7 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: listIssues,
+ boardItemsByListId: listIssues,
boardLists: initialBoardListsState,
};
@@ -420,7 +462,7 @@ describe('Board Store Mutations', () => {
'gid://gitlab/List/2': [],
};
- expect(state.issuesByListId).toEqual(updatedListIssues);
+ expect(state.boardItemsByListId).toEqual(updatedListIssues);
expect(state.error).toEqual('An error occurred while moving the issue. Please try again.');
});
});
@@ -446,7 +488,7 @@ describe('Board Store Mutations', () => {
});
describe('ADD_ISSUE_TO_LIST', () => {
- it('adds issue to issues state and issue id in list in issuesByListId', () => {
+ it('adds issue to issues state and issue id in list in boardItemsByListId', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id],
};
@@ -456,8 +498,8 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: listIssues,
- issues,
+ boardItemsByListId: listIssues,
+ boardItems: issues,
boardLists: initialBoardListsState,
};
@@ -465,14 +507,14 @@ describe('Board Store Mutations', () => {
mutations.ADD_ISSUE_TO_LIST(state, { list: mockLists[0], issue: mockIssue2 });
- expect(state.issuesByListId['gid://gitlab/List/1']).toContain(mockIssue2.id);
- expect(state.issues[mockIssue2.id]).toEqual(mockIssue2);
+ expect(state.boardItemsByListId['gid://gitlab/List/1']).toContain(mockIssue2.id);
+ expect(state.boardItems[mockIssue2.id]).toEqual(mockIssue2);
expect(state.boardLists['gid://gitlab/List/1'].issuesCount).toBe(2);
});
});
describe('ADD_ISSUE_TO_LIST_FAILURE', () => {
- it('removes issue id from list in issuesByListId and sets error message', () => {
+ it('removes issue id from list in boardItemsByListId and sets error message', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
};
@@ -483,20 +525,20 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: listIssues,
- issues,
+ boardItemsByListId: listIssues,
+ boardItems: issues,
boardLists: initialBoardListsState,
};
mutations.ADD_ISSUE_TO_LIST_FAILURE(state, { list: mockLists[0], issueId: mockIssue2.id });
- expect(state.issuesByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
+ expect(state.boardItemsByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
expect(state.error).toBe('An error occurred while creating the issue. Please try again.');
});
});
describe('REMOVE_ISSUE_FROM_LIST', () => {
- it('removes issue id from list in issuesByListId and deletes issue from state', () => {
+ it('removes issue id from list in boardItemsByListId and deletes issue from state', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
};
@@ -507,15 +549,15 @@ describe('Board Store Mutations', () => {
state = {
...state,
- issuesByListId: listIssues,
- issues,
+ boardItemsByListId: listIssues,
+ boardItems: issues,
boardLists: initialBoardListsState,
};
mutations.ADD_ISSUE_TO_LIST_FAILURE(state, { list: mockLists[0], issueId: mockIssue2.id });
- expect(state.issuesByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
- expect(state.issues).not.toContain(mockIssue2);
+ expect(state.boardItemsByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
+ expect(state.boardItems).not.toContain(mockIssue2);
});
});
@@ -607,14 +649,21 @@ describe('Board Store Mutations', () => {
describe('REMOVE_BOARD_ITEM_FROM_SELECTION', () => {
it('Should remove boardItem to selectedBoardItems state', () => {
- state = {
- ...state,
- selectedBoardItems: [mockIssue],
- };
+ state.selectedBoardItems = [mockIssue];
mutations[types.REMOVE_BOARD_ITEM_FROM_SELECTION](state, mockIssue);
expect(state.selectedBoardItems).toEqual([]);
});
});
+
+ describe('RESET_BOARD_ITEM_SELECTION', () => {
+ it('Should reset selectedBoardItems state', () => {
+ state.selectedBoardItems = [mockIssue];
+
+ mutations[types.RESET_BOARD_ITEM_SELECTION](state, mockIssue);
+
+ expect(state.selectedBoardItems).toEqual([]);
+ });
+ });
});