diff options
Diffstat (limited to 'spec/frontend/boards/stores')
-rw-r--r-- | spec/frontend/boards/stores/actions_spec.js | 274 | ||||
-rw-r--r-- | spec/frontend/boards/stores/mutations_spec.js | 40 |
2 files changed, 221 insertions, 93 deletions
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js index 5e16e389ddc..1272a573d2f 100644 --- a/spec/frontend/boards/stores/actions_spec.js +++ b/spec/frontend/boards/stores/actions_spec.js @@ -1,4 +1,7 @@ import * as Sentry from '@sentry/browser'; +import { cloneDeep } from 'lodash'; +import Vue from 'vue'; +import Vuex from 'vuex'; import { inactiveId, ISSUABLE, @@ -6,6 +9,7 @@ import { issuableTypes, BoardType, listsQuery, + DraggableItemTypes, } from 'ee_else_ce/boards/constants'; import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql'; import testAction from 'helpers/vuex_action_helper'; @@ -21,6 +25,7 @@ import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutati import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql'; import actions, { gqlClient } from '~/boards/stores/actions'; import * as types from '~/boards/stores/mutation_types'; +import mutations from '~/boards/stores/mutations'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { @@ -37,6 +42,7 @@ import { mockMoveState, mockMoveData, mockList, + mockMilestones, } from '../mock_data'; jest.mock('~/flash'); @@ -45,6 +51,8 @@ jest.mock('~/flash'); // subgroups when the movIssue action is called. const getProjectPath = (path) => path.split('#')[0]; +Vue.use(Vuex); + beforeEach(() => { window.gon = { features: {} }; }); @@ -260,6 +268,87 @@ describe('fetchLists', () => { ); }); +describe('fetchMilestones', () => { + const queryResponse = { + data: { + project: { + milestones: { + nodes: mockMilestones, + }, + }, + }, + }; + + const queryErrors = { + data: { + project: { + errors: ['You cannot view these milestones'], + milestones: {}, + }, + }, + }; + + function createStore({ + state = { + boardType: 'project', + fullPath: 'gitlab-org/gitlab', + milestones: [], + milestonesLoading: false, + }, + } = {}) { + return new Vuex.Store({ + state, + mutations, + }); + } + + it('throws error if state.boardType is not group or project', () => { + const store = createStore({ + state: { + boardType: 'invalid', + }, + }); + + expect(() => actions.fetchMilestones(store)).toThrow(new Error('Unknown board type')); + }); + + it('sets milestonesLoading to true', async () => { + jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse); + + const store = createStore(); + + actions.fetchMilestones(store); + + expect(store.state.milestonesLoading).toBe(true); + }); + + describe('success', () => { + it('sets state.milestones from query result', async () => { + jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse); + + const store = createStore(); + + await actions.fetchMilestones(store); + + expect(store.state.milestonesLoading).toBe(false); + expect(store.state.milestones).toBe(mockMilestones); + }); + }); + + describe('failure', () => { + it('sets state.milestones from query result', async () => { + jest.spyOn(gqlClient, 'query').mockResolvedValue(queryErrors); + + const store = createStore(); + + await expect(actions.fetchMilestones(store)).rejects.toThrow(); + + expect(store.state.milestonesLoading).toBe(false); + expect(store.state.error).toBe('Failed to load milestones.'); + }); + }); +}); + describe('createList', () => { it('should dispatch createIssueList action', () => { testAction({ @@ -419,75 +508,114 @@ describe('fetchLabels', () => { }); describe('moveList', () => { - it('should commit MOVE_LIST mutation and dispatch updateList action', (done) => { - const initialBoardListsState = { - 'gid://gitlab/List/1': mockLists[0], - 'gid://gitlab/List/2': mockLists[1], - }; + const backlogListId = 'gid://1'; + const closedListId = 'gid://5'; - const state = { - fullPath: 'gitlab-org', - fullBoardId: 'gid://gitlab/Board/1', - boardType: 'group', - disabled: false, - boardLists: initialBoardListsState, - }; + const boardLists1 = { + 'gid://3': { listType: '', position: 0 }, + 'gid://4': { listType: '', position: 1 }, + 'gid://5': { listType: '', position: 2 }, + }; - testAction( - actions.moveList, - { - listId: 'gid://gitlab/List/1', - replacedListId: 'gid://gitlab/List/2', - newIndex: 1, - adjustmentValue: 1, - }, - state, - [ - { - type: types.MOVE_LIST, - payload: { movedList: mockLists[0], listAtNewIndex: mockLists[1] }, - }, - ], - [ - { - type: 'updateList', - payload: { - listId: 'gid://gitlab/List/1', - position: 0, - backupList: initialBoardListsState, - }, + const boardLists2 = { + [backlogListId]: { listType: ListType.backlog, position: -Infinity }, + [closedListId]: { listType: ListType.closed, position: Infinity }, + ...cloneDeep(boardLists1), + }; + + const movableListsOrder = ['gid://3', 'gid://4', 'gid://5']; + const allListsOrder = [backlogListId, ...movableListsOrder, closedListId]; + + it(`should not handle the event if the dragged item is not a "${DraggableItemTypes.list}"`, () => { + return testAction({ + action: actions.moveList, + payload: { + item: { dataset: { listId: '', draggableItemType: DraggableItemTypes.card } }, + to: { + children: [], }, - ], - done, - ); + }, + state: {}, + expectedMutations: [], + expectedActions: [], + }); }); - it('should not commit MOVE_LIST or dispatch updateList if listId and replacedListId are the same', () => { - const initialBoardListsState = { - 'gid://gitlab/List/1': mockLists[0], - 'gid://gitlab/List/2': mockLists[1], - }; + describe.each` + draggableFrom | draggableTo | boardLists | boardListsOrder | expectedMovableListsOrder + ${0} | ${2} | ${boardLists1} | ${movableListsOrder} | ${['gid://4', 'gid://5', 'gid://3']} + ${2} | ${0} | ${boardLists1} | ${movableListsOrder} | ${['gid://5', 'gid://3', 'gid://4']} + ${0} | ${1} | ${boardLists1} | ${movableListsOrder} | ${['gid://4', 'gid://3', 'gid://5']} + ${1} | ${2} | ${boardLists1} | ${movableListsOrder} | ${['gid://3', 'gid://5', 'gid://4']} + ${2} | ${1} | ${boardLists1} | ${movableListsOrder} | ${['gid://3', 'gid://5', 'gid://4']} + ${1} | ${3} | ${boardLists2} | ${allListsOrder} | ${['gid://4', 'gid://5', 'gid://3']} + ${3} | ${1} | ${boardLists2} | ${allListsOrder} | ${['gid://5', 'gid://3', 'gid://4']} + ${1} | ${2} | ${boardLists2} | ${allListsOrder} | ${['gid://4', 'gid://3', 'gid://5']} + ${2} | ${3} | ${boardLists2} | ${allListsOrder} | ${['gid://3', 'gid://5', 'gid://4']} + ${3} | ${2} | ${boardLists2} | ${allListsOrder} | ${['gid://3', 'gid://5', 'gid://4']} + `( + 'when moving a list from position $draggableFrom to $draggableTo with lists $boardListsOrder', + ({ draggableFrom, draggableTo, boardLists, boardListsOrder, expectedMovableListsOrder }) => { + const movedListId = boardListsOrder[draggableFrom]; + const displacedListId = boardListsOrder[draggableTo]; + const buildDraggablePayload = () => { + return { + item: { + dataset: { + listId: boardListsOrder[draggableFrom], + draggableItemType: DraggableItemTypes.list, + }, + }, + newIndex: draggableTo, + to: { + children: boardListsOrder.map((listId) => ({ dataset: { listId } })), + }, + }; + }; - const state = { - fullPath: 'gitlab-org', - fullBoardId: 'gid://gitlab/Board/1', - boardType: 'group', - disabled: false, - boardLists: initialBoardListsState, - }; + it('should commit MOVE_LIST mutations and dispatch updateList action with correct payloads', () => { + return testAction({ + action: actions.moveList, + payload: buildDraggablePayload(), + state: { boardLists }, + expectedMutations: [ + { + type: types.MOVE_LISTS, + payload: expectedMovableListsOrder.map((listId, i) => ({ listId, position: i })), + }, + ], + expectedActions: [ + { + type: 'updateList', + payload: { + listId: movedListId, + position: movableListsOrder.findIndex((i) => i === displacedListId), + }, + }, + ], + }); + }); + }, + ); - testAction( - actions.moveList, - { - listId: 'gid://gitlab/List/1', - replacedListId: 'gid://gitlab/List/1', - newIndex: 1, - adjustmentValue: 1, - }, - state, - [], - [], - ); + describe('when moving from and to the same position', () => { + it('should not commit MOVE_LIST and should not dispatch updateList', () => { + const listId = 'gid://1000'; + + return testAction({ + action: actions.moveList, + payload: { + item: { dataset: { listId, draggbaleItemType: DraggableItemTypes.list } }, + newIndex: 0, + to: { + children: [{ dataset: { listId } }], + }, + }, + state: { boardLists: { [listId]: { position: 0 } } }, + expectedMutations: [], + expectedActions: [], + }); + }); }); }); @@ -549,7 +677,7 @@ describe('updateList', () => { }); }); - it('should commit UPDATE_LIST_FAILURE mutation when API returns an error', (done) => { + it('should dispatch handleUpdateListFailure when API returns an error', () => { jest.spyOn(gqlClient, 'mutate').mockResolvedValue({ data: { updateBoardList: { @@ -559,17 +687,31 @@ describe('updateList', () => { }, }); - testAction( + return testAction( actions.updateList, { listId: 'gid://gitlab/List/1', position: 1 }, createState(), - [{ type: types.UPDATE_LIST_FAILURE }], [], - done, + [{ type: 'handleUpdateListFailure' }], ); }); }); +describe('handleUpdateListFailure', () => { + it('should dispatch fetchLists action and commit SET_ERROR mutation', async () => { + await testAction({ + action: actions.handleUpdateListFailure, + expectedMutations: [ + { + type: types.SET_ERROR, + payload: 'An error occurred while updating the board list. Please try again.', + }, + ], + expectedActions: [{ type: 'fetchLists' }], + }); + }); +}); + describe('toggleListCollapsed', () => { it('should commit TOGGLE_LIST_COLLAPSED mutation', async () => { const payload = { listId: 'gid://gitlab/List/1', collapsed: true }; diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js index 37f0969a39a..a2ba1e9eb5e 100644 --- a/spec/frontend/boards/stores/mutations_spec.js +++ b/spec/frontend/boards/stores/mutations_spec.js @@ -165,40 +165,26 @@ describe('Board Store Mutations', () => { }); }); - describe('MOVE_LIST', () => { - it('updates boardLists state with reordered lists', () => { + describe('MOVE_LISTS', () => { + it('updates the positions of board lists', () => { state = { ...state, boardLists: initialBoardListsState, }; - mutations.MOVE_LIST(state, { - movedList: mockLists[0], - listAtNewIndex: mockLists[1], - }); - - expect(state.boardLists).toEqual({ - 'gid://gitlab/List/2': mockLists[1], - 'gid://gitlab/List/1': mockLists[0], - }); - }); - }); - - describe('UPDATE_LIST_FAILURE', () => { - it('updates boardLists state with previous order and sets error message', () => { - state = { - ...state, - boardLists: { - 'gid://gitlab/List/2': mockLists[1], - 'gid://gitlab/List/1': mockLists[0], + mutations.MOVE_LISTS(state, [ + { + listId: mockLists[0].id, + position: 1, }, - error: undefined, - }; - - mutations.UPDATE_LIST_FAILURE(state, initialBoardListsState); + { + listId: mockLists[1].id, + position: 0, + }, + ]); - expect(state.boardLists).toEqual(initialBoardListsState); - expect(state.error).toEqual('An error occurred while updating the list. Please try again.'); + expect(state.boardLists[mockLists[0].id].position).toBe(1); + expect(state.boardLists[mockLists[1].id].position).toBe(0); }); }); |