Commit 791de1f5 authored by Simon Knox's avatar Simon Knox

Merge branch...

Merge branch '328564-use-a-correct-group-path-when-fetching-an-epic-in-graphql-boards' into 'master'

Use a correct group path when fetching epic in graphql boards

See merge request gitlab-org/gitlab!59937
parents 45e56844 deb8bb3f
...@@ -21,6 +21,9 @@ fragment IssueNode on Issue { ...@@ -21,6 +21,9 @@ fragment IssueNode on Issue {
epic { epic {
id id
iid iid
group {
fullPath
}
} }
milestone { milestone {
id id
......
...@@ -382,10 +382,10 @@ export default { ...@@ -382,10 +382,10 @@ export default {
} }
const { const {
epic: { id, iid }, epic: { id, iid, group: { fullPath } = {} },
} = getters.activeBoardItem; } = getters.activeBoardItem;
if (state.epicsCacheById[id]) { if (!iid || !fullPath || state.epicsCacheById[id]) {
return false; return false;
} }
...@@ -399,7 +399,7 @@ export default { ...@@ -399,7 +399,7 @@ export default {
} = await gqlClient.query({ } = await gqlClient.query({
query: epicQuery, query: epicQuery,
variables: { variables: {
fullPath: getters.groupPathForActiveIssue, fullPath,
iid, iid,
}, },
}); });
...@@ -440,7 +440,7 @@ export default { ...@@ -440,7 +440,7 @@ export default {
commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, { commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
itemId: getters.activeBoardItem.id, itemId: getters.activeBoardItem.id,
prop: 'epic', prop: 'epic',
value: epic ? { id: epic.id, iid: epic.iid } : null, value: epic ? { id: epic.id, iid: epic.iid, group: { fullPath: epic.group.fullPath } } : null,
}); });
commit(types.SET_EPIC_FETCH_IN_PROGRESS, false); commit(types.SET_EPIC_FETCH_IN_PROGRESS, false);
}, },
......
fragment EpicNode on Epic { fragment EpicNode on Epic {
id id
iid iid
group {
fullPath
}
title title
state state
reference reference
......
...@@ -170,6 +170,7 @@ export const mockIssue = { ...@@ -170,6 +170,7 @@ export const mockIssue = {
epic: { epic: {
id: 'gid://gitlab/Epic/41', id: 'gid://gitlab/Epic/41',
iid: 2, iid: 2,
group: { fullPath: mockIssueGroupPath },
}, },
}; };
...@@ -188,6 +189,7 @@ export const mockIssue2 = { ...@@ -188,6 +189,7 @@ export const mockIssue2 = {
epic: { epic: {
id: 'gid://gitlab/Epic/40', id: 'gid://gitlab/Epic/40',
iid: 1, iid: 1,
group: { fullPath: 'gitlab-org' },
}, },
}; };
...@@ -229,6 +231,7 @@ export const mockEpic = { ...@@ -229,6 +231,7 @@ export const mockEpic = {
title: 'Epic title', title: 'Epic title',
state: 'opened', state: 'opened',
webUrl: '/groups/gitlab-org/-/epics/1', webUrl: '/groups/gitlab-org/-/epics/1',
group: { fullPath: 'gitlab-org' },
descendantCounts: { descendantCounts: {
openedIssues: 3, openedIssues: 3,
closedIssues: 2, closedIssues: 2,
...@@ -237,6 +240,13 @@ export const mockEpic = { ...@@ -237,6 +240,13 @@ export const mockEpic = {
labels: [], labels: [],
}; };
export const mockEpic2 = {
id: 'gid://gitlab/Epic/42',
iid: '2',
group: { fullPath: 'gitlab-org' },
title: 'Epic title 2',
};
export const mockIssueWithEpic = { export const mockIssueWithEpic = {
...mockIssue3, ...mockIssue3,
epic: { epic: {
......
...@@ -22,6 +22,7 @@ import { ...@@ -22,6 +22,7 @@ import {
mockIssue, mockIssue,
mockIssues, mockIssues,
mockEpic, mockEpic,
mockEpic2,
mockMilestones, mockMilestones,
mockAssignees, mockAssignees,
} from '../mock_data'; } from '../mock_data';
...@@ -657,8 +658,7 @@ describe('resetEpics', () => { ...@@ -657,8 +658,7 @@ describe('resetEpics', () => {
describe('fetchEpicForActiveIssue', () => { describe('fetchEpicForActiveIssue', () => {
const assignedEpic = { const assignedEpic = {
id: mockIssue.epic.id, ...mockIssue.epic,
iid: mockIssue.epic.iid,
}; };
describe("when active issue doesn't have an assigned epic", () => { describe("when active issue doesn't have an assigned epic", () => {
...@@ -669,6 +669,19 @@ describe('fetchEpicForActiveIssue', () => { ...@@ -669,6 +669,19 @@ describe('fetchEpicForActiveIssue', () => {
}); });
}); });
describe("when active issue doesn't have the full epic information", () => {
// Edge Case: when user drops/moves a card onto an epic swimlane,
// until IssueMoveList request is completed, the issue item only has epic id.
// This causes a problem when user also has the sidebar open because
// board_sidebar_epic_select watches for the issue item's `epic` field
// and tries to extract epic id, epic iid and fullpath to request for detailed epic info.
const getters = { activeBoardItem: { ...mockIssue, epic: { id: 'something' } } };
it('should not fetch any epic', async () => {
await testAction(actions.fetchEpicForActiveIssue, undefined, { ...getters }, [], []);
});
});
describe('when the assigned epic for active issue is found in state.epicsCacheById', () => { describe('when the assigned epic for active issue is found in state.epicsCacheById', () => {
const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } }; const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: { [assignedEpic.id]: assignedEpic } }; const state = { epicsCacheById: { [assignedEpic.id]: assignedEpic } };
...@@ -749,21 +762,16 @@ describe('setActiveIssueEpic', () => { ...@@ -749,21 +762,16 @@ describe('setActiveIssueEpic', () => {
epics: [{ id: 'gid://gitlab/Epic/422', iid: 99, title: 'existing epic' }], epics: [{ id: 'gid://gitlab/Epic/422', iid: 99, title: 'existing epic' }],
}; };
const getters = { activeBoardItem: { ...mockIssue, projectPath: 'h/b' } }; const getters = { activeBoardItem: { ...mockIssue, projectPath: 'h/b' } };
const epicWithData = {
id: 'gid://gitlab/Epic/42',
iid: 1,
title: 'Epic title',
};
describe('when the updated issue has an assigned epic', () => { describe('when the updated issue has an assigned epic', () => {
it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_BOARD_ITEM_BY_ID on success', async () => { it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_BOARD_ITEM_BY_ID on success', async () => {
jest jest
.spyOn(gqlClient, 'mutate') .spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: epicWithData } } } }); .mockResolvedValue({ data: { issueSetEpic: { issue: { epic: mockEpic2 } } } });
await testAction( await testAction(
actions.setActiveIssueEpic, actions.setActiveIssueEpic,
epicWithData.id, mockEpic2.id,
{ ...state, ...getters }, { ...state, ...getters },
[ [
{ {
...@@ -772,18 +780,18 @@ describe('setActiveIssueEpic', () => { ...@@ -772,18 +780,18 @@ describe('setActiveIssueEpic', () => {
}, },
{ {
type: types.RECEIVE_EPICS_SUCCESS, type: types.RECEIVE_EPICS_SUCCESS,
payload: { epics: [epicWithData, ...state.epics] }, payload: { epics: [mockEpic2, ...state.epics] },
}, },
{ {
type: types.UPDATE_CACHED_EPICS, type: types.UPDATE_CACHED_EPICS,
payload: [epicWithData], payload: [mockEpic2],
}, },
{ {
type: typesCE.UPDATE_BOARD_ITEM_BY_ID, type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload: { payload: {
itemId: mockIssue.id, itemId: mockIssue.id,
prop: 'epic', prop: 'epic',
value: { id: epicWithData.id, iid: epicWithData.iid }, value: { id: mockEpic2.id, iid: mockEpic2.iid, group: mockEpic2.group },
}, },
}, },
{ {
...@@ -830,7 +838,7 @@ describe('setActiveIssueEpic', () => { ...@@ -830,7 +838,7 @@ describe('setActiveIssueEpic', () => {
.spyOn(gqlClient, 'mutate') .spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { errors: ['failed mutation'] } } }); .mockResolvedValue({ data: { issueSetEpic: { errors: ['failed mutation'] } } });
await expect(actions.setActiveIssueEpic({ getters }, epicWithData.id)).rejects.toThrow(Error); await expect(actions.setActiveIssueEpic({ getters }, mockEpic2.id)).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