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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/boards')
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js20
-rw-r--r--spec/frontend/boards/board_list_helper.js1
-rw-r--r--spec/frontend/boards/components/__snapshots__/board_blocked_icon_spec.js.snap2
-rw-r--r--spec/frontend/boards/components/board_blocked_icon_spec.js74
-rw-r--r--spec/frontend/boards/components/board_card_move_to_position_spec.js133
-rw-r--r--spec/frontend/boards/components/board_card_spec.js9
-rw-r--r--spec/frontend/boards/components/board_new_issue_spec.js2
-rw-r--r--spec/frontend/boards/components/issue_due_date_spec.js2
-rw-r--r--spec/frontend/boards/components/item_count_spec.js4
-rw-r--r--spec/frontend/boards/mock_data.js76
-rw-r--r--spec/frontend/boards/stores/actions_spec.js38
-rw-r--r--spec/frontend/boards/stores/mutations_spec.js25
12 files changed, 358 insertions, 28 deletions
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index 985902b4a3b..2c3ec69f9ae 100644
--- a/spec/frontend/boards/board_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -7,6 +7,8 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue';
+import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
+import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import { issuableTypes } from '~/boards/constants';
import eventHub from '~/boards/eventhub';
import defaultStore from '~/boards/stores';
@@ -47,6 +49,8 @@ describe('Board card component', () => {
const findEpicCountablesTotalWeight = () => wrapper.findByTestId('epic-countables-total-weight');
const findEpicProgressTooltip = () => wrapper.findByTestId('epic-progress-tooltip-content');
const findHiddenIssueIcon = () => wrapper.findByTestId('hidden-icon');
+ const findMoveToPositionComponent = () => wrapper.findComponent(BoardCardMoveToPosition);
+ const findWorkItemIcon = () => wrapper.findComponent(WorkItemTypeIcon);
const performSearchMock = jest.fn();
@@ -75,10 +79,12 @@ describe('Board card component', () => {
propsData: {
list,
item: issue,
+ index: 0,
...props,
},
stubs: {
GlLoadingIcon: true,
+ BoardCardMoveToPosition: true,
},
directives: {
GlTooltip: createMockDirective(),
@@ -137,6 +143,20 @@ describe('Board card component', () => {
expect(findHiddenIssueIcon().exists()).toBe(false);
});
+ it('renders the move to position icon', () => {
+ expect(findMoveToPositionComponent().exists()).toBe(true);
+ });
+
+ it('does not render the work type icon by default', () => {
+ expect(findWorkItemIcon().exists()).toBe(false);
+ });
+
+ it('renders the work type icon when props is passed', () => {
+ createWrapper({ item: issue, list, showWorkItemTypeIcon: true });
+ expect(findWorkItemIcon().exists()).toBe(true);
+ expect(findWorkItemIcon().props('workItemType')).toBe(issue.type);
+ });
+
it('renders issue ID with #', () => {
expect(wrapper.find('.board-card-number').text()).toContain(`#${issue.iid}`);
});
diff --git a/spec/frontend/boards/board_list_helper.js b/spec/frontend/boards/board_list_helper.js
index 04192489817..65a41c49e7f 100644
--- a/spec/frontend/boards/board_list_helper.js
+++ b/spec/frontend/boards/board_list_helper.js
@@ -75,6 +75,7 @@ export default function createComponent({
id: 1,
iid: 1,
confidential: false,
+ referencePath: 'gitlab-org/test-subgroup/gitlab-test#1',
labels: [],
assignees: [],
...listIssueProps,
diff --git a/spec/frontend/boards/components/__snapshots__/board_blocked_icon_spec.js.snap b/spec/frontend/boards/components/__snapshots__/board_blocked_icon_spec.js.snap
index 3fb0706fd10..34e4f996ff0 100644
--- a/spec/frontend/boards/components/__snapshots__/board_blocked_icon_spec.js.snap
+++ b/spec/frontend/boards/components/__snapshots__/board_blocked_icon_spec.js.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BoardBlockedIcon on mouseenter on blocked icon with more than three blocking issues matches the snapshot 1`] = `
-"<div class=\\"gl-display-inline\\"><svg data-testid=\\"issue-blocked-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"issue-blocked-icon gl-mr-2 gl-cursor-pointer gl-icon s16\\" id=\\"blocked-icon-uniqueId\\">
+"<div class=\\"gl-display-inline\\"><svg data-testid=\\"issue-blocked-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"issue-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500 gl-icon s16\\" id=\\"blocked-icon-uniqueId\\">
<use href=\\"#issue-block\\"></use>
</svg>
<div class=\\"gl-popover\\">
diff --git a/spec/frontend/boards/components/board_blocked_icon_spec.js b/spec/frontend/boards/components/board_blocked_icon_spec.js
index cf4ba07da16..ffdc0a7cecc 100644
--- a/spec/frontend/boards/components/board_blocked_icon_spec.js
+++ b/spec/frontend/boards/components/board_blocked_icon_spec.js
@@ -10,13 +10,17 @@ import { blockingIssuablesQueries, issuableTypes } from '~/boards/constants';
import { truncate } from '~/lib/utils/text_utility';
import {
mockIssue,
+ mockEpic,
mockBlockingIssue1,
mockBlockingIssue2,
+ mockBlockingEpic1,
mockBlockingIssuablesResponse1,
mockBlockingIssuablesResponse2,
mockBlockingIssuablesResponse3,
mockBlockedIssue1,
mockBlockedIssue2,
+ mockBlockedEpic1,
+ mockBlockingEpicIssuablesResponse1,
} from '../mock_data';
describe('BoardBlockedIcon', () => {
@@ -51,9 +55,11 @@ describe('BoardBlockedIcon', () => {
const createWrapperWithApollo = ({
item = mockBlockedIssue1,
blockingIssuablesSpy = jest.fn().mockResolvedValue(mockBlockingIssuablesResponse1),
+ issuableItem = mockIssue,
+ issuableType = issuableTypes.issue,
} = {}) => {
mockApollo = createMockApollo([
- [blockingIssuablesQueries[issuableTypes.issue].query, blockingIssuablesSpy],
+ [blockingIssuablesQueries[issuableType].query, blockingIssuablesSpy],
]);
Vue.use(VueApollo);
@@ -62,27 +68,34 @@ describe('BoardBlockedIcon', () => {
apolloProvider: mockApollo,
propsData: {
item: {
- ...mockIssue,
+ ...issuableItem,
...item,
},
uniqueId: 'uniqueId',
- issuableType: issuableTypes.issue,
+ issuableType,
},
attachTo: document.body,
}),
);
};
- const createWrapper = ({ item = {}, queries = {}, data = {}, loading = false } = {}) => {
+ const createWrapper = ({
+ item = {},
+ queries = {},
+ data = {},
+ loading = false,
+ mockIssuable = mockIssue,
+ issuableType = issuableTypes.issue,
+ } = {}) => {
wrapper = extendedWrapper(
shallowMount(BoardBlockedIcon, {
propsData: {
item: {
- ...mockIssue,
+ ...mockIssuable,
...item,
},
uniqueId: 'uniqueid',
- issuableType: issuableTypes.issue,
+ issuableType,
},
data() {
return {
@@ -105,11 +118,24 @@ describe('BoardBlockedIcon', () => {
);
};
- it('should render blocked icon', () => {
- createWrapper();
+ it.each`
+ mockIssuable | issuableType | expectedIcon
+ ${mockIssue} | ${issuableTypes.issue} | ${'issue-block'}
+ ${mockEpic} | ${issuableTypes.epic} | ${'entity-blocked'}
+ `(
+ 'should render blocked icon for $issuableType',
+ ({ mockIssuable, issuableType, expectedIcon }) => {
+ createWrapper({
+ mockIssuable,
+ issuableType,
+ });
- expect(findGlIcon().exists()).toBe(true);
- });
+ expect(findGlIcon().exists()).toBe(true);
+ const icon = findGlIcon();
+ expect(icon.exists()).toBe(true);
+ expect(icon.props('name')).toBe(expectedIcon);
+ },
+ );
it('should display a loading spinner while loading', () => {
createWrapper({ loading: true });
@@ -124,17 +150,29 @@ describe('BoardBlockedIcon', () => {
});
describe('on mouseenter on blocked icon', () => {
- it('should query for blocking issuables and render the result', async () => {
- createWrapperWithApollo();
+ it.each`
+ item | issuableType | mockBlockingIssuable | issuableItem | blockingIssuablesSpy
+ ${mockBlockedIssue1} | ${issuableTypes.issue} | ${mockBlockingIssue1} | ${mockIssue} | ${jest.fn().mockResolvedValue(mockBlockingIssuablesResponse1)}
+ ${mockBlockedEpic1} | ${issuableTypes.epic} | ${mockBlockingEpic1} | ${mockEpic} | ${jest.fn().mockResolvedValue(mockBlockingEpicIssuablesResponse1)}
+ `(
+ 'should query for blocking issuables and render the result for $issuableType',
+ async ({ item, issuableType, issuableItem, mockBlockingIssuable, blockingIssuablesSpy }) => {
+ createWrapperWithApollo({
+ item,
+ issuableType,
+ issuableItem,
+ blockingIssuablesSpy,
+ });
- expect(findGlPopover().text()).not.toContain(mockBlockingIssue1.title);
+ expect(findGlPopover().text()).not.toContain(mockBlockingIssuable.title);
- await mouseenter();
+ await mouseenter();
- expect(findGlPopover().exists()).toBe(true);
- expect(findIssuableTitle().text()).toContain(mockBlockingIssue1.title);
- expect(wrapper.vm.skip).toBe(true);
- });
+ expect(findGlPopover().exists()).toBe(true);
+ expect(findIssuableTitle().text()).toContain(mockBlockingIssuable.title);
+ expect(wrapper.vm.skip).toBe(true);
+ },
+ );
it('should emit "blocking-issuables-error" event on query error', async () => {
const mockError = new Error('mayday');
diff --git a/spec/frontend/boards/components/board_card_move_to_position_spec.js b/spec/frontend/boards/components/board_card_move_to_position_spec.js
new file mode 100644
index 00000000000..7254b9486ef
--- /dev/null
+++ b/spec/frontend/boards/components/board_card_move_to_position_spec.js
@@ -0,0 +1,133 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+
+import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
+import { mockList, mockIssue2, mockIssue, mockIssue3, mockIssue4 } from 'jest/boards/mock_data';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+
+Vue.use(Vuex);
+
+const dropdownOptions = [
+ BoardCardMoveToPosition.i18n.moveToStartText,
+ BoardCardMoveToPosition.i18n.moveToEndText,
+];
+
+describe('Board Card Move to position', () => {
+ let wrapper;
+ let trackingSpy;
+ let store;
+ let dispatch;
+ const itemIndex = 1;
+
+ const createStoreOptions = () => {
+ const state = {
+ pageInfoByListId: {
+ 'gid://gitlab/List/1': {},
+ 'gid://gitlab/List/2': { hasNextPage: true },
+ },
+ };
+ const getters = {
+ getBoardItemsByList: () => () => [mockIssue, mockIssue2, mockIssue3, mockIssue4],
+ };
+ const actions = {
+ moveItem: jest.fn(),
+ };
+
+ return {
+ state,
+ getters,
+ actions,
+ };
+ };
+
+ const createComponent = (propsData) => {
+ wrapper = shallowMount(BoardCardMoveToPosition, {
+ store,
+ propsData: {
+ item: mockIssue2,
+ list: mockList,
+ index: 0,
+ ...propsData,
+ },
+ stubs: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ store = new Vuex.Store(createStoreOptions());
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findMoveToPositionDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownItems = () => findMoveToPositionDropdown().findAllComponents(GlDropdownItem);
+ const findDropdownItemAtIndex = (index) => findDropdownItems().at(index);
+
+ describe('Dropdown', () => {
+ describe('Dropdown button', () => {
+ it('has an icon with vertical ellipsis', () => {
+ expect(findMoveToPositionDropdown().exists()).toBe(true);
+ expect(findMoveToPositionDropdown().props('icon')).toBe('ellipsis_v');
+ });
+
+ it('is opened on the click of vertical ellipsis and has 2 dropdown items when number of list items < 10', () => {
+ findMoveToPositionDropdown().vm.$emit('click');
+ expect(findDropdownItems()).toHaveLength(dropdownOptions.length);
+ });
+ });
+
+ describe('Dropdown options', () => {
+ beforeEach(() => {
+ createComponent({ index: itemIndex });
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ dispatch = jest.spyOn(store, 'dispatch').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it.each`
+ dropdownIndex | dropdownLabel | trackLabel | positionInList
+ ${0} | ${BoardCardMoveToPosition.i18n.moveToStartText} | ${'move_to_start'} | ${0}
+ ${1} | ${BoardCardMoveToPosition.i18n.moveToEndText} | ${'move_to_end'} | ${-1}
+ `(
+ 'on click of dropdown index $dropdownIndex with label $dropdownLabel should call moveItem action with tracking label $trackLabel',
+ async ({ dropdownIndex, dropdownLabel, trackLabel, positionInList }) => {
+ await findMoveToPositionDropdown().vm.$emit('click');
+
+ expect(findDropdownItemAtIndex(dropdownIndex).text()).toBe(dropdownLabel);
+ await findDropdownItemAtIndex(dropdownIndex).vm.$emit('click', {
+ stopPropagation: () => {},
+ });
+
+ await nextTick();
+
+ expect(trackingSpy).toHaveBeenCalledWith('boards:list', 'click_toggle_button', {
+ category: 'boards:list',
+ label: trackLabel,
+ property: 'type_card',
+ });
+ expect(dispatch).toHaveBeenCalledWith('moveItem', {
+ fromListId: mockList.id,
+ itemId: mockIssue2.id,
+ itemIid: mockIssue2.iid,
+ itemPath: mockIssue2.referencePath,
+ positionInList,
+ toListId: mockList.id,
+ allItemsLoadedInList: true,
+ atIndex: itemIndex,
+ });
+ },
+ );
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index bb1e63a581e..2feaa5dff8c 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -1,5 +1,5 @@
import { GlLabel } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
@@ -45,7 +45,10 @@ describe('Board card', () => {
item = mockIssue,
} = {}) => {
wrapper = mountFn(BoardCard, {
- stubs,
+ stubs: {
+ ...stubs,
+ BoardCardInner,
+ },
store,
propsData: {
list: mockLabelList,
@@ -86,7 +89,7 @@ describe('Board card', () => {
describe('when GlLabel is clicked in BoardCardInner', () => {
it('doesnt call toggleBoardItem', () => {
createStore({ initialState: { isShowingLabels: true } });
- mountComponent({ mountFn: mount, stubs: {} });
+ mountComponent();
wrapper.findComponent(GlLabel).trigger('mouseup');
diff --git a/spec/frontend/boards/components/board_new_issue_spec.js b/spec/frontend/boards/components/board_new_issue_spec.js
index 8b0100d069a..f097f42476a 100644
--- a/spec/frontend/boards/components/board_new_issue_spec.js
+++ b/spec/frontend/boards/components/board_new_issue_spec.js
@@ -90,7 +90,7 @@ describe('Issue boards new issue form', () => {
});
});
- it('it uses the first issue ID as moveAfterId', async () => {
+ it('uses the first issue ID as moveAfterId', async () => {
findBoardNewItem().vm.$emit('form-submit', { title: 'Foo' });
await nextTick();
diff --git a/spec/frontend/boards/components/issue_due_date_spec.js b/spec/frontend/boards/components/issue_due_date_spec.js
index 73340c1b96b..45fa10bf03a 100644
--- a/spec/frontend/boards/components/issue_due_date_spec.js
+++ b/spec/frontend/boards/components/issue_due_date_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import dateFormat from 'dateformat';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
+import dateFormat from '~/lib/dateformat';
const createComponent = (dueDate = new Date(), closed = false) =>
shallowMount(IssueDueDate, {
diff --git a/spec/frontend/boards/components/item_count_spec.js b/spec/frontend/boards/components/item_count_spec.js
index 06cd3910fc0..0c0c7f66933 100644
--- a/spec/frontend/boards/components/item_count_spec.js
+++ b/spec/frontend/boards/components/item_count_spec.js
@@ -50,7 +50,7 @@ describe('IssueCount', () => {
});
it('contains maxIssueCount in the template', () => {
- expect(vm.find('.max-issue-size').text()).toEqual(String(maxIssueCount));
+ expect(vm.find('.max-issue-size').text()).toContain(String(maxIssueCount));
});
it('does not have text-danger class when issueSize is less than maxIssueCount', () => {
@@ -75,7 +75,7 @@ describe('IssueCount', () => {
});
it('contains maxIssueCount in the template', () => {
- expect(vm.find('.max-issue-size').text()).toEqual(String(maxIssueCount));
+ expect(vm.find('.max-issue-size').text()).toContain(String(maxIssueCount));
});
it('has text-danger class', () => {
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 1ee05d81f37..dc1f3246be0 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -262,9 +262,11 @@ export const rawIssue = {
epic: {
id: 'gid://gitlab/Epic/41',
},
+ type: 'ISSUE',
};
export const mockIssueFullPath = 'gitlab-org/test-subgroup/gitlab-test';
+export const mockEpicFullPath = 'gitlab-org/test-subgroup';
export const mockIssue = {
id: 'gid://gitlab/Issue/436',
@@ -287,6 +289,48 @@ export const mockIssue = {
epic: {
id: 'gid://gitlab/Epic/41',
},
+ type: 'ISSUE',
+};
+
+export const mockEpic = {
+ id: 'gid://gitlab/Epic/26',
+ iid: '1',
+ group: {
+ id: 'gid://gitlab/Group/33',
+ fullPath: 'twitter',
+ __typename: 'Group',
+ },
+ title: 'Eum animi debitis occaecati ad non odio repellat voluptatem similique.',
+ state: 'opened',
+ reference: '&1',
+ referencePath: `${mockEpicFullPath}&1`,
+ webPath: `/groups/${mockEpicFullPath}/-/epics/1`,
+ webUrl: `${mockEpicFullPath}/-/epics/1`,
+ createdAt: '2022-01-18T05:15:15Z',
+ closedAt: null,
+ __typename: 'Epic',
+ relativePosition: null,
+ confidential: false,
+ subscribed: true,
+ blocked: true,
+ blockedByCount: 1,
+ labels: {
+ nodes: [],
+ __typename: 'LabelConnection',
+ },
+ hasIssues: true,
+ descendantCounts: {
+ closedEpics: 0,
+ closedIssues: 0,
+ openedEpics: 0,
+ openedIssues: 2,
+ __typename: 'EpicDescendantCount',
+ },
+ descendantWeightSum: {
+ closedIssues: 0,
+ openedIssues: 0,
+ __typename: 'EpicDescendantWeights',
+ },
};
export const mockActiveIssue = {
@@ -521,6 +565,15 @@ export const mockBlockingIssue1 = {
__typename: 'Issue',
};
+export const mockBlockingEpic1 = {
+ id: 'gid://gitlab/Epic/29',
+ iid: '4',
+ title: 'Sint nihil exercitationem aspernatur unde molestiae rem accusantium.',
+ reference: 'twitter&4',
+ webUrl: 'http://gdk.test:3000/groups/gitlab-org/test-subgroup/-/epics/4',
+ __typename: 'Epic',
+};
+
export const mockBlockingIssue2 = {
id: 'gid://gitlab/Issue/524',
iid: '5',
@@ -562,6 +615,23 @@ export const mockBlockingIssuablesResponse1 = {
},
};
+export const mockBlockingEpicIssuablesResponse1 = {
+ data: {
+ group: {
+ __typename: 'Group',
+ id: 'gid://gitlab/Group/33',
+ issuable: {
+ __typename: 'Epic',
+ id: 'gid://gitlab/Epic/26',
+ blockingIssuables: {
+ __typename: 'EpicConnection',
+ nodes: [mockBlockingEpic1],
+ },
+ },
+ },
+ },
+};
+
export const mockBlockingIssuablesResponse2 = {
data: {
issuable: {
@@ -599,6 +669,12 @@ export const mockBlockedIssue2 = {
webUrl: 'http://gdk.test:3000/gitlab-org/my-project-1/-/issues/0',
};
+export const mockBlockedEpic1 = {
+ id: '26',
+ blockedByCount: 1,
+ webUrl: 'http://gdk.test:3000/gitlab-org/test-subgroup/-/epics/1',
+};
+
export const mockMoveIssueParams = {
itemId: 1,
fromListId: 'gid://gitlab/List/1',
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index e48b946ff1b..e919300228a 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -1056,6 +1056,8 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
originalIndex = 0,
moveBeforeId = undefined,
moveAfterId = undefined,
+ allItemsLoadedInList = true,
+ listPosition = undefined,
} = {}) => {
state = {
boardLists: {
@@ -1065,12 +1067,28 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123] },
};
- params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
+ params = {
+ itemId,
+ fromListId,
+ toListId,
+ moveBeforeId,
+ moveAfterId,
+ listPosition,
+ allItemsLoadedInList,
+ };
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
- payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
+ payload: {
+ itemId,
+ listId: toListId,
+ moveBeforeId,
+ moveAfterId,
+ listPosition,
+ allItemsLoadedInList,
+ atIndex: originalIndex,
+ },
},
];
undoMutations = [
@@ -1366,9 +1384,17 @@ describe('updateIssueOrder', () => {
state,
[
{
+ type: types.MUTATE_ISSUE_IN_PROGRESS,
+ payload: true,
+ },
+ {
type: types.MUTATE_ISSUE_SUCCESS,
payload: { issue: rawIssue },
},
+ {
+ type: types.MUTATE_ISSUE_IN_PROGRESS,
+ payload: false,
+ },
],
[],
);
@@ -1390,6 +1416,14 @@ describe('updateIssueOrder', () => {
state,
[
{
+ type: types.MUTATE_ISSUE_IN_PROGRESS,
+ payload: true,
+ },
+ {
+ type: types.MUTATE_ISSUE_IN_PROGRESS,
+ payload: false,
+ },
+ {
type: types.SET_ERROR,
payload: 'An error occurred while moving the issue. Please try again.',
},
diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js
index 1606ca09d8f..87a183c0441 100644
--- a/spec/frontend/boards/stores/mutations_spec.js
+++ b/spec/frontend/boards/stores/mutations_spec.js
@@ -513,6 +513,31 @@ describe('Board Store Mutations', () => {
listState: [mockIssue2.id, mockIssue.id],
},
],
+ [
+ 'to the top of the list',
+ {
+ payload: {
+ itemId: mockIssue2.id,
+ listId: mockList.id,
+ positionInList: 0,
+ atIndex: 1,
+ },
+ listState: [mockIssue2.id, mockIssue.id],
+ },
+ ],
+ [
+ 'to the bottom of the list when the list is fully loaded',
+ {
+ payload: {
+ itemId: mockIssue2.id,
+ listId: mockList.id,
+ positionInList: -1,
+ atIndex: 0,
+ allItemsLoadedInList: true,
+ },
+ listState: [mockIssue.id, mockIssue2.id],
+ },
+ ],
])(`inserts an item into a list %s`, (_, { payload, listState }) => {
mutations.ADD_BOARD_ITEM_TO_LIST(state, payload);