Commit 03947a82 authored by Axel García's avatar Axel García

Move set epic network logic to boards actions

This uses axios on the boards store to handle
the request of setting the data from the server.
It doesn't commit any mutation.
parent 9afe5498
......@@ -3,7 +3,6 @@ import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
import EpicsSelect from 'ee/vue_shared/components/sidebar/epics_select/base.vue';
import { debounceByAnimationFrame } from '~/lib/utils/common_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import issueSetEpic from '../../queries/issue_set_epic.mutation.graphql';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import { UPDATE_ISSUE_BY_ID } from '~/boards/stores/mutation_types';
import { RECEIVE_EPICS_SUCCESS } from '../../stores/mutation_types';
......@@ -41,7 +40,7 @@ export default {
updateIssueById: UPDATE_ISSUE_BY_ID,
receiveEpicsSuccess: RECEIVE_EPICS_SUCCESS,
}),
...mapActions(['fetchIssuesForEpic']),
...mapActions(['setActiveIssueEpic']),
handleEdit(isEditing) {
if (isEditing) {
this.$refs.epicSelect.handleEditClick();
......@@ -52,30 +51,25 @@ export default {
this.$refs.sidebarItem.collapse();
const epicId = selectedEpic?.id ? `gid://gitlab/Epic/${selectedEpic.id}` : null;
const { data } = await this.$apollo.mutate({
mutation: issueSetEpic,
variables: {
input: {
epicId,
iid: String(this.issue.iid),
projectPath: this.projectPath,
},
},
});
const input = {
epicId,
projectPath: this.projectPath,
};
if (data.issueSetEpic.errors?.length > 0) {
this.loading = false;
return;
}
try {
const epic = await this.setActiveIssueEpic(input);
const { epic } = data.issueSetEpic.issue;
if (epic && !this.getEpicById(epic.id)) {
this.receiveEpicsSuccess([epic, ...this.epics]);
if (epic && !this.getEpicById(epic.id)) {
this.receiveEpicsSuccess([epic, ...this.epics]);
}
debounceByAnimationFrame(() => {
this.updateIssueById({ issueId: this.issue.id, prop: 'epic', value: epic });
this.loading = false;
})();
} catch (e) {
this.loading = false;
}
debounceByAnimationFrame(() => {
this.updateIssueById({ issueId: this.issue.id, prop: 'epic', value: epic });
})();
this.loading = false;
},
},
};
......
......@@ -15,6 +15,7 @@ import eventHub from '~/boards/eventhub';
import createDefaultClient from '~/lib/graphql';
import epicsSwimlanesQuery from '../queries/epics_swimlanes.query.graphql';
import issueSetEpic from '../queries/issue_set_epic.mutation.graphql';
import listsIssuesQuery from '~/boards/queries/lists_issues.query.graphql';
const notImplemented = () => {
......@@ -234,4 +235,23 @@ export default {
resetEpics: ({ commit }) => {
commit(types.RESET_EPICS);
},
setActiveIssueEpic: async ({ getters }, input) => {
const { data } = await gqlClient.mutate({
mutation: issueSetEpic,
variables: {
input: {
iid: String(getters.getActiveIssue.iid),
epicId: input.epicId,
projectPath: input.projectPath,
},
},
});
if (data.issueSetEpic.errors?.length > 0) {
throw new Error(data.issueSetEpic.errors);
}
return data.issueSetEpic.issue.epic;
},
};
import { shallowMount } from '@vue/test-utils';
import BoardSidebarEpicSelect from 'ee/boards/components/sidebar/board_sidebar_epic_select.vue';
import issueSetEpic from 'ee/boards/queries/issue_set_epic.mutation.graphql';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import { createStore } from '~/boards/stores';
......@@ -8,8 +7,6 @@ const TEST_GROUP_ID = 7;
const TEST_EPIC_ID = 8;
const TEST_EPIC = { id: 'gid://gitlab/Epic/1', title: 'Test epic' };
const TEST_ISSUE = { id: 'gid://gitlab/Issue/1', iid: 9, epic: null, referencePath: 'h/b#2' };
const TEST_EPIC_SET = { data: { issueSetEpic: { issue: { ...TEST_ISSUE, epic: TEST_EPIC } } } };
const TEST_FAILED_EPIC_SET = { data: { issueSetEpic: { errors: ['mutation failed'] } } };
jest.mock('~/lib/utils/common_utils', () => ({ debounceByAnimationFrame: callback => callback }));
......@@ -23,7 +20,7 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
wrapper = null;
});
const createWrapper = ({ mutationResult = TEST_EPIC_SET } = {}) => {
const createWrapper = () => {
store = createStore();
jest.spyOn(store, 'dispatch').mockImplementation(() => {});
wrapper = shallowMount(BoardSidebarEpicSelect, {
......@@ -35,11 +32,6 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
stubs: {
'board-editable-item': BoardEditableItem,
},
mocks: {
$apollo: {
mutate: jest.fn().mockResolvedValue(mutationResult),
},
},
});
store.state.epics = [TEST_EPIC];
......@@ -58,6 +50,7 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
describe('when epic is selected', () => {
beforeEach(async () => {
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueEpic').mockImplementation(() => TEST_EPIC);
findEpicSelect().vm.$emit('onEpicSelect', { ...TEST_EPIC, id: TEST_EPIC_ID });
await wrapper.vm.$nextTick();
});
......@@ -68,15 +61,9 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
});
it('commits change to the server', () => {
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: issueSetEpic,
variables: {
input: {
epicId: `gid://gitlab/Epic/${TEST_EPIC_ID}`,
iid: String(TEST_ISSUE.iid),
projectPath: 'h/b',
},
},
expect(wrapper.vm.setActiveIssueEpic).toHaveBeenCalledWith({
epicId: `gid://gitlab/Epic/${TEST_EPIC_ID}`,
projectPath: 'h/b',
});
});
......@@ -86,10 +73,9 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
});
describe('when no epic is selected', () => {
const issueWithoutEpic = { data: { issueSetEpic: { issue: { ...TEST_ISSUE } } } };
beforeEach(async () => {
createWrapper({ mutationResult: issueWithoutEpic });
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueEpic').mockImplementation(() => null);
findEpicSelect().vm.$emit('onEpicSelect', null);
await wrapper.vm.$nextTick();
});
......@@ -106,12 +92,14 @@ describe('ee/boards/components/sidebar/board_sidebar_epic_select.vue', () => {
describe('when the mutation fails', () => {
const issueWithEpic = { ...TEST_ISSUE, epic: TEST_EPIC };
const faultyEpic = { id: '?', title: 'Faulty epic' };
beforeEach(async () => {
createWrapper({ mutationResult: TEST_FAILED_EPIC_SET });
createWrapper();
store.state.issues = { [TEST_ISSUE.id]: { ...issueWithEpic } };
findEpicSelect().vm.$emit('onEpicSelect', faultyEpic);
jest.spyOn(wrapper.vm, 'setActiveIssueEpic').mockImplementation(() => {
throw new Error(['failed mutation']);
});
findEpicSelect().vm.$emit('onEpicSelect', {});
await wrapper.vm.$nextTick();
});
......
......@@ -350,3 +350,34 @@ describe('resetEpics', () => {
return testAction(actions.resetEpics, {}, {}, [{ type: types.RESET_EPICS }], []);
});
});
describe('setActiveIssueEpic', () => {
const getters = { getActiveIssue: mockIssue };
const epicWithData = {
id: 'gid://gitlab/Epic/42',
iid: 1,
title: 'Epic title',
};
const input = {
epicId: epicWithData.id,
projectPath: 'h/b',
};
it('should return epic after setting the issue', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: epicWithData } } } });
const result = await actions.setActiveIssueEpic({ getters }, input);
expect(result.id).toEqual(epicWithData.id);
});
it('throws error if fails', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { errors: ['failed mutation'] } } });
await expect(actions.setActiveIssueEpic({ getters }, input)).rejects.toThrow(Error);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment