Commit c3c1b697 authored by Florie Guibert's avatar Florie Guibert

Fetch lists for epic boards

GraphQL query to fetch lists for current epic boards
Render empty lists
GraphQL query to fetch epics in lists
parent 774a38ed
......@@ -46,7 +46,7 @@ export default {
watch: {
filterParams: {
handler() {
this.fetchIssuesForList({ listId: this.list.id });
this.fetchItemsForList({ listId: this.list.id });
},
deep: true,
immediate: true,
......@@ -63,7 +63,7 @@ export default {
},
},
methods: {
...mapActions(['fetchIssuesForList']),
...mapActions(['fetchItemsForList']),
},
};
</script>
......
......@@ -11,12 +11,20 @@ import BoardColumnDeprecated from './board_column_deprecated.vue';
export default {
components: {
BoardColumn: gon.features?.graphqlBoardLists ? BoardColumn : BoardColumnDeprecated,
BoardColumn:
gon.features?.graphqlBoardLists || gon.features?.epicBoards
? BoardColumn
: BoardColumnDeprecated,
BoardContentSidebar: () => import('ee_component/boards/components/board_content_sidebar.vue'),
EpicsSwimlanes: () => import('ee_component/boards/components/epics_swimlanes.vue'),
GlAlert,
},
mixins: [glFeatureFlagMixin()],
inject: {
isEpicBoard: {
default: false,
},
},
props: {
lists: {
type: Array,
......@@ -36,7 +44,7 @@ export default {
...mapState(['boardLists', 'error']),
...mapGetters(['isSwimlanesOn']),
boardListsToUse() {
return this.glFeatures.graphqlBoardLists || this.isSwimlanesOn
return this.glFeatures.graphqlBoardLists || this.isSwimlanesOn || this.isEpicBoard
? sortBy([...Object.values(this.boardLists)], 'position')
: this.lists;
},
......
......@@ -112,7 +112,7 @@ export default {
this.listRef.removeEventListener('scroll', this.onScroll);
},
methods: {
...mapActions(['fetchIssuesForList', 'moveIssue']),
...mapActions(['fetchItemsForList', 'moveIssue']),
listHeight() {
return this.listRef.getBoundingClientRect().height;
},
......@@ -126,7 +126,7 @@ export default {
this.listRef.scrollTop = 0;
},
loadNextPage() {
this.fetchIssuesForList({ listId: this.list.id, fetchNext: true });
this.fetchItemsForList({ listId: this.list.id, fetchNext: true });
},
toggleForm() {
this.showIssueForm = !this.showIssueForm;
......
......@@ -83,7 +83,11 @@ export default {
}
},
fetchLists: ({ commit, state, dispatch }) => {
fetchLists: ({ dispatch }) => {
dispatch('fetchIssueLists');
},
fetchIssueLists: ({ commit, state, dispatch }) => {
const { boardType, filterParams, fullPath, boardId } = state;
const variables = {
......@@ -257,8 +261,8 @@ export default {
});
},
fetchIssuesForList: ({ state, commit }, { listId, fetchNext = false }) => {
commit(types.REQUEST_ISSUES_FOR_LIST, { listId, fetchNext });
fetchItemsForList: ({ state, commit }, { listId, fetchNext = false }) => {
commit(types.REQUEST_ITEMS_FOR_LIST, { listId, fetchNext });
const { fullPath, boardId, boardType, filterParams } = state;
......@@ -285,9 +289,9 @@ export default {
const { lists } = data[boardType]?.board;
const listIssues = formatListIssues(lists);
const listPageInfo = formatListsPageInfo(lists);
commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, { listIssues, listPageInfo, listId });
commit(types.RECEIVE_ITEMS_FOR_LIST_SUCCESS, { listIssues, listPageInfo, listId });
})
.catch(() => commit(types.RECEIVE_ISSUES_FOR_LIST_FAILURE, listId));
.catch(() => commit(types.RECEIVE_ITEMS_FOR_LIST_FAILURE, listId));
},
resetIssues: ({ commit }) => {
......
......@@ -14,9 +14,9 @@ export const MOVE_LIST = 'MOVE_LIST';
export const UPDATE_LIST_FAILURE = 'UPDATE_LIST_FAILURE';
export const REMOVE_LIST = 'REMOVE_LIST';
export const REMOVE_LIST_FAILURE = 'REMOVE_LIST_FAILURE';
export const REQUEST_ISSUES_FOR_LIST = 'REQUEST_ISSUES_FOR_LIST';
export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE';
export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS';
export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST';
export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE';
export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
export const CREATE_ISSUE_FAILURE = 'CREATE_ISSUE_FAILURE';
export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE';
export const RECEIVE_ADD_ISSUE_SUCCESS = 'RECEIVE_ADD_ISSUE_SUCCESS';
......
......@@ -32,12 +32,13 @@ export const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfter
export default {
[mutationTypes.SET_INITIAL_BOARD_DATA](state, data) {
const { boardType, disabled, boardId, fullPath, boardConfig } = data;
const { boardType, disabled, boardId, fullPath, boardConfig, isEpicBoard } = data;
state.boardId = boardId;
state.fullPath = fullPath;
state.boardType = boardType;
state.disabled = disabled;
state.boardConfig = boardConfig;
state.isEpicBoard = isEpicBoard;
},
[mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => {
......@@ -103,14 +104,11 @@ export default {
state.boardLists = listsBackup;
},
[mutationTypes.REQUEST_ISSUES_FOR_LIST]: (state, { listId, fetchNext }) => {
[mutationTypes.REQUEST_ITEMS_FOR_LIST]: (state, { listId, fetchNext }) => {
Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (
state,
{ listIssues, listPageInfo, listId },
) => {
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (state, { listIssues, listPageInfo, listId }) => {
const { listData, issues } = listIssues;
Vue.set(state, 'issues', { ...state.issues, ...issues });
Vue.set(
......@@ -122,7 +120,7 @@ export default {
Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_FAILURE]: (state, listId) => {
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_FAILURE]: (state, listId) => {
state.error = s__(
'Boards|An error occurred while fetching the board issues. Please reload the page.',
);
......
import { urlParamsToObject } from '~/lib/utils/common_utils';
import { objectToQuery } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import {
IterationFilterType,
IterationIDs,
......@@ -25,6 +26,55 @@ export function fullUserId(userId) {
return `gid://gitlab/User/${userId}`;
}
export function fullEpicBoardId(epicBoardId) {
return `gid://gitlab/Boards::EpicBoard/${epicBoardId}`;
}
export function formatListEpics(listEpics) {
const epics = {};
let listEpicsCount;
const listData = listEpics.nodes.reduce((map, list) => {
// TODO update when list.epics.count is available
listEpicsCount = list.epics.edges.length;
const sortedEpics = list.epics.edges.map((epicNode) => ({
...epicNode.node,
}));
// TODO update when relativePosition is available on epic
// sortedEpics = sortBy(sortedEpics, 'relativePosition');
return {
...map,
[list.id]: sortedEpics.map((i) => {
const id = getIdFromGraphQLId(i.id);
const listEpic = {
...i,
id,
labels: i.labels?.nodes || [],
assignees: i.assignees?.nodes || [],
};
epics[id] = listEpic;
return id;
}),
};
}, {});
return { listData, epics, listEpicsCount };
}
export function formatEpicListsPageInfo(lists) {
const listData = lists.nodes.reduce((map, list) => {
return {
...map,
[list.id]: list.epics.pageInfo,
};
}, {});
return listData;
}
export function transformBoardConfig(boardConfig) {
const updatedBoardConfig = {};
const passedFilterParams = urlParamsToObject(window.location.search);
......@@ -86,5 +136,6 @@ export default {
fullEpicId,
fullMilestoneId,
fullUserId,
fullEpicBoardId,
transformBoardConfig,
};
......@@ -75,7 +75,7 @@ export default {
},
},
methods: {
...mapActions(['moveList', 'fetchIssuesForList']),
...mapActions(['moveList', 'fetchItemsForList']),
handleDragOnEnd(params) {
const { newIndex, oldIndex, item, to } = params;
const { listId } = item.dataset;
......@@ -91,7 +91,7 @@ export default {
fetchMoreUnassignedIssues() {
this.lists.forEach((list) => {
if (this.pageInfoByListId[list.id]?.hasNextPage) {
this.fetchIssuesForList({ listId: list.id, fetchNext: true, noEpicIssues: true });
this.fetchItemsForList({ listId: list.id, fetchNext: true, noEpicIssues: true });
}
});
},
......
......@@ -78,7 +78,7 @@ export default {
filterParams: {
handler() {
if (this.isUnassignedIssuesLane) {
this.fetchIssuesForList({ listId: this.list.id, noEpicIssues: true });
this.fetchItemsForList({ listId: this.list.id, noEpicIssues: true });
}
},
deep: true,
......@@ -102,7 +102,7 @@ export default {
eventHub.$off(`toggle-issue-form-${this.list.id}`, this.toggleForm);
},
methods: {
...mapActions(['moveIssue', 'moveIssueEpic', 'fetchIssuesForList']),
...mapActions(['moveIssue', 'moveIssueEpic', 'fetchItemsForList']),
toggleForm() {
this.showIssueForm = !this.showIssueForm;
if (this.showIssueForm && this.isUnassignedIssuesLane) {
......
#import "~/graphql_shared/fragments/label.fragment.graphql"
query ListEpics($fullPath: ID!, $boardId: BoardsEpicBoardID!) {
group(fullPath: $fullPath) {
epicBoard(id: $boardId) {
lists {
nodes {
id
title
position
listType
label {
...Label
}
}
}
}
}
}
#import "~/graphql_shared/fragments/epic.fragment.graphql"
query ListEpics(
$fullPath: ID!
$boardId: BoardsEpicBoardID!
$id: BoardsEpicListID
$after: String
$first: Int
) {
group(fullPath: $fullPath) {
epicBoard(id: $boardId) {
lists(id: $id) {
nodes {
id
epics(first: $first, after: $after) {
edges {
node {
...EpicNode
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
}
}
}
......@@ -21,7 +21,12 @@ import {
urlParamsToObject,
} from '~/lib/utils/common_utils';
import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
import { fullEpicId } from '../boards_util';
import {
fullEpicId,
fullEpicBoardId,
formatListEpics,
formatEpicListsPageInfo,
} from '../boards_util';
import { EpicFilterType, IterationFilterType, GroupByParamType } from '../constants';
import epicQuery from '../graphql/epic.query.graphql';
......@@ -31,6 +36,9 @@ import issueSetEpicMutation from '../graphql/issue_set_epic.mutation.graphql';
import issueSetWeightMutation from '../graphql/issue_set_weight.mutation.graphql';
import listUpdateLimitMetricsMutation from '../graphql/list_update_limit_metrics.mutation.graphql';
import updateBoardEpicUserPreferencesMutation from '../graphql/updateBoardEpicUserPreferences.mutation.graphql';
import epicBoardListsQuery from '../graphql/epic_board_lists.query.graphql';
import listsEpicsQuery from '../graphql/lists_epics.query.graphql';
import boardsStoreEE from './boards_store_ee';
import * as types from './mutation_types';
......@@ -72,6 +80,30 @@ const fetchAndFormatListIssues = (state, extraVariables) => {
});
};
const fetchAndFormatListEpics = (state, extraVariables) => {
const { fullPath, boardId, filterParams } = state;
const variables = {
fullPath,
boardId: fullEpicBoardId(boardId),
filters: { ...filterParams },
...extraVariables,
};
return gqlClient
.query({
query: listsEpicsQuery,
context: {
isSingleRequest: true,
},
variables,
})
.then(({ data }) => {
const { lists } = data.group?.epicBoard;
return { listEpics: formatListEpics(lists), listPageInfo: formatEpicListsPageInfo(lists) };
});
};
export default {
...actionsCE,
......@@ -115,7 +147,7 @@ export default {
commit(types.SET_FILTERS, filterParams);
},
performSearch({ dispatch, getters }) {
performSearch({ dispatch, getters, state }) {
dispatch(
'setFilters',
convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)),
......@@ -125,7 +157,7 @@ export default {
dispatch('resetEpics');
dispatch('resetIssues');
dispatch('fetchEpicsSwimlanes', {});
} else if (gon.features.graphqlBoardLists) {
} else if (gon.features.graphqlBoardLists || state.isEpicBoard) {
dispatch('fetchLists');
dispatch('resetIssues');
}
......@@ -267,8 +299,8 @@ export default {
notImplemented();
},
fetchIssuesForList: ({ state, commit }, { listId, fetchNext = false, noEpicIssues = false }) => {
commit(types.REQUEST_ISSUES_FOR_LIST, { listId, fetchNext });
fetchItemsForList: ({ state, commit }, { listId, fetchNext = false, noEpicIssues = false }) => {
commit(types.REQUEST_ITEMS_FOR_LIST, { listId, fetchNext });
const { epicId, ...filterParams } = state.filterParams;
if (noEpicIssues && epicId !== undefined) {
......@@ -284,16 +316,30 @@ export default {
first: 20,
};
if (state.isEpicBoard) {
// This currently always fails. Epics will be loaded and displayed in the next iteration
return fetchAndFormatListEpics(state, variables)
.then(({ listEpics, listPageInfo }) => {
commit(types.RECEIVE_ITEMS_FOR_LIST_SUCCESS, {
listEpics,
listPageInfo,
listId,
noEpicIssues,
});
})
.catch(() => commit(types.RECEIVE_ITEMS_FOR_LIST_FAILURE, listId));
}
return fetchAndFormatListIssues(state, variables)
.then(({ listIssues, listPageInfo }) => {
commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, {
commit(types.RECEIVE_ITEMS_FOR_LIST_SUCCESS, {
listIssues,
listPageInfo,
listId,
noEpicIssues,
});
})
.catch(() => commit(types.RECEIVE_ISSUES_FOR_LIST_FAILURE, listId));
.catch(() => commit(types.RECEIVE_ITEMS_FOR_LIST_FAILURE, listId));
},
fetchIssuesForEpic: ({ state, commit }, epicId) => {
......@@ -478,4 +524,35 @@ export default {
commit(types.MOVE_ISSUE_FAILURE, { originalIssue, fromListId, toListId, originalIndex }),
);
},
fetchLists: ({ state, dispatch }) => {
const { isEpicBoard } = state;
if (!isEpicBoard) {
dispatch('fetchIssueLists');
} else {
dispatch('fetchEpicLists');
}
},
fetchEpicLists: ({ commit, state }) => {
const { filterParams, fullPath, boardId } = state;
const variables = {
fullPath,
boardId: fullEpicBoardId(boardId),
filters: filterParams,
};
return gqlClient
.query({
query: epicBoardListsQuery,
variables,
})
.then(({ data }) => {
const { lists } = data.group?.epicBoard;
commit(types.RECEIVE_BOARD_LISTS_SUCCESS, formatBoardLists(lists));
})
.catch(() => commit(types.RECEIVE_BOARD_LISTS_FAILURE));
},
};
......@@ -8,15 +8,16 @@ export const REQUEST_REMOVE_BOARD = 'REQUEST_REMOVE_BOARD';
export const RECEIVE_REMOVE_BOARD_SUCCESS = 'RECEIVE_REMOVE_BOARD_SUCCESS';
export const RECEIVE_REMOVE_BOARD_ERROR = 'RECEIVE_REMOVE_BOARD_ERROR';
export const TOGGLE_PROMOTION_STATE = 'TOGGLE_PROMOTION_STATE';
export const REQUEST_ISSUES_FOR_LIST = 'REQUEST_ISSUES_FOR_LIST';
export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE';
export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS';
export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST';
export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE';
export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
export const REQUEST_ISSUES_FOR_EPIC = 'REQUEST_ISSUES_FOR_EPIC';
export const RECEIVE_ISSUES_FOR_EPIC_SUCCESS = 'RECEIVE_ISSUES_FOR_EPIC_SUCCESS';
export const RECEIVE_ISSUES_FOR_EPIC_FAILURE = 'RECEIVE_ISSUES_FOR_EPIC_FAILURE';
export const TOGGLE_EPICS_SWIMLANES = 'TOGGLE_EPICS_SWIMLANES';
export const SET_EPICS_SWIMLANES = 'SET_EPICS_SWIMLANES';
export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS';
export const RECEIVE_BOARD_LISTS_FAILURE = 'RECEIVE_BOARD_LISTS_FAILURE';
export const UPDATE_LIST_SUCCESS = 'UPDATE_LIST_SUCCESS';
export const UPDATE_LIST_FAILURE = 'UPDATE_LIST_FAILURE';
export const RECEIVE_SWIMLANES_FAILURE = 'RECEIVE_SWIMLANES_FAILURE';
......
......@@ -63,7 +63,7 @@ export default {
state.error = s__('Boards|An error occurred while updating the list. Please try again.');
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (
state,
{ listIssues, listPageInfo, listId, noEpicIssues },
) => {
......
......@@ -12,4 +12,5 @@ export default () => ({
epicsCacheById: {},
epicFetchInProgress: false,
epicsFlags: {},
isEpicBoard: false,
});
......@@ -61,6 +61,7 @@ export default () => {
? parseInt($boardApp.dataset.boardWeight, 10)
: null,
scopedLabelsAvailable: parseBoolean($boardApp.dataset.scopedLabels),
isEpicBoard: true,
},
store,
apolloProvider,
......@@ -96,10 +97,14 @@ export default () => {
? parseInt($boardApp.dataset.boardWeight, 10)
: null,
},
isEpicBoard: true,
});
},
mounted() {
this.performSearch();
},
methods: {
...mapActions(['setInitialBoardData']),
...mapActions(['setInitialBoardData', 'performSearch']),
getNodes(data) {
return data[this.parent]?.board?.lists.nodes;
},
......
......@@ -7,6 +7,9 @@ class Groups::EpicBoardsController < Groups::ApplicationController
before_action :authorize_read_board!, only: [:index]
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:epic_boards, group, default_enabled: false)
end
feature_category :boards
......
......@@ -6,7 +6,7 @@ import boardsStoreEE from 'ee/boards/stores/boards_store_ee';
import * as types from 'ee/boards/stores/mutation_types';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
import { formatListIssues } from '~/boards/boards_util';
import { formatListIssues, formatBoardLists } from '~/boards/boards_util';
import * as typesCE from '~/boards/stores/mutation_types';
import * as commonUtils from '~/lib/utils/common_utils';
import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
......@@ -135,6 +135,81 @@ describe('performSearch', () => {
});
});
describe('fetchLists', () => {
it('should dispatch fetchIssueLists action when isEpicBoard is false on state', () => {
testAction({
action: actions.fetchLists,
state: { isEpicBoard: false },
expectedActions: [{ type: 'fetchIssueLists' }],
});
});
it('should dispatch fetchEpicLists action when isEpicBoard is true on state', () => {
testAction({
action: actions.fetchLists,
state: { isEpicBoard: true },
expectedActions: [{ type: 'fetchEpicLists' }],
});
});
});
describe('fetchEpicLists', () => {
const state = {
fullPath: 'gitlab-org',
boardId: '1',
filterParams: {},
};
const queryResponse = {
data: {
group: {
epicBoard: {
lists: {
nodes: mockLists,
},
},
},
},
};
const formattedLists = formatBoardLists(queryResponse.data.group.epicBoard.lists);
it('should commit mutations RECEIVE_BOARD_LISTS_SUCCESS on success', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchEpicLists,
{},
state,
[
{
type: types.RECEIVE_BOARD_LISTS_SUCCESS,
payload: formattedLists,
},
],
[],
done,
);
});
it('should commit mutations RECEIVE_BOARD_LISTS_FAILURE on failure', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
testAction(
actions.fetchEpicLists,
{},
state,
[
{
type: types.RECEIVE_BOARD_LISTS_FAILURE,
},
],
[],
done,
);
});
});
describe('fetchEpicsSwimlanes', () => {
const state = {
fullPath: 'gitlab-org',
......@@ -425,7 +500,7 @@ describe('fetchIssuesForEpic', () => {
const formattedIssues = formatListIssues(queryResponse.data.group.board.lists);
it('should commit mutations REQUEST_ISSUES_FOR_EPIC and RECEIVE_ISSUES_FOR_LIST_SUCCESS on success', (done) => {
it('should commit mutations REQUEST_ISSUES_FOR_EPIC and RECEIVE_ITEMS_FOR_LIST_SUCCESS on success', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
......@@ -441,7 +516,7 @@ describe('fetchIssuesForEpic', () => {
);
});
it('should commit mutations REQUEST_ISSUES_FOR_EPIC and RECEIVE_ISSUES_FOR_LIST_FAILURE on failure', (done) => {
it('should commit mutations REQUEST_ISSUES_FOR_EPIC and RECEIVE_ITEMS_FOR_LIST_FAILURE on failure', (done) => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
testAction(
......
......@@ -11,7 +11,7 @@ const localVue = createLocalVue();
localVue.use(Vuex);
const actions = {
fetchIssuesForList: jest.fn(),
fetchItemsForList: jest.fn(),
};
const createStore = (state = defaultState) => {
......@@ -170,7 +170,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 +179,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 () => {
......
......@@ -114,6 +114,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',
......@@ -140,7 +149,7 @@ describe('fetchLists', () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchLists,
actions.fetchIssueLists,
{},
state,
[
......@@ -154,6 +163,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: {
......@@ -170,7 +196,7 @@ describe('fetchLists', () => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchLists,
actions.fetchIssueLists,
{},
state,
[
......@@ -492,7 +518,7 @@ describe('removeList', () => {
});
});
describe('fetchIssuesForList', () => {
describe('fetchItemsForList', () => {
const listId = mockLists[0].id;
const state = {
......@@ -535,20 +561,20 @@ 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,
type: types.RECEIVE_ITEMS_FOR_LIST_SUCCESS,
payload: { listIssues: formattedIssues, listPageInfo, listId },
},
],
......@@ -557,19 +583,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,
......
......@@ -235,7 +235,7 @@ describe('Board Store Mutations', () => {
});
});
describe('RECEIVE_ISSUES_FOR_LIST_SUCCESS', () => {
describe('RECEIVE_ITEMS_FOR_LIST_SUCCESS', () => {
it('updates issuesByListId and issues on state', () => {
const listIssues = {
'gid://gitlab/List/1': [mockIssue.id],
......@@ -260,7 +260,7 @@ describe('Board Store Mutations', () => {
},
};
mutations.RECEIVE_ISSUES_FOR_LIST_SUCCESS(state, {
mutations.RECEIVE_ITEMS_FOR_LIST_SUCCESS(state, {
listIssues: { listData: listIssues, issues },
listPageInfo,
listId: 'gid://gitlab/List/1',
......@@ -271,7 +271,7 @@ describe('Board Store Mutations', () => {
});
});
describe('RECEIVE_ISSUES_FOR_LIST_FAILURE', () => {
describe('RECEIVE_ITEMS_FOR_LIST_FAILURE', () => {
it('sets error message', () => {
state = {
...state,
......@@ -281,7 +281,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.',
......
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