Commit 1deeaa3b authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'donald-apollo-board' into 'master'

On boards, move weight and issue count to async call

See merge request gitlab-org/gitlab!73854
parents 858e48d3 8458810d
...@@ -8,6 +8,7 @@ import defaultSortableConfig from '~/sortable/sortable_config'; ...@@ -8,6 +8,7 @@ import defaultSortableConfig from '~/sortable/sortable_config';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { toggleFormEventPrefix, DraggableItemTypes } from '../constants'; import { toggleFormEventPrefix, DraggableItemTypes } from '../constants';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import listQuery from '../graphql/board_lists_deferred.query.graphql';
import BoardCard from './board_card.vue'; import BoardCard from './board_card.vue';
import BoardNewIssue from './board_new_issue.vue'; import BoardNewIssue from './board_new_issue.vue';
...@@ -50,11 +51,22 @@ export default { ...@@ -50,11 +51,22 @@ export default {
showEpicForm: false, showEpicForm: false,
}; };
}, },
apollo: {
boardList: {
query: listQuery,
variables() {
return {
id: this.list.id,
filters: this.filterParams,
};
},
},
},
computed: { computed: {
...mapState(['pageInfoByListId', 'listsFlags']), ...mapState(['pageInfoByListId', 'listsFlags', 'filterParams']),
...mapGetters(['isEpicBoard']), ...mapGetters(['isEpicBoard']),
listItemsCount() { listItemsCount() {
return this.isEpicBoard ? this.list.epicsCount : this.list.issuesCount; return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount;
}, },
paginatedIssueText() { paginatedIssueText() {
return sprintf(__('Showing %{pageSize} of %{total} %{issuableType}'), { return sprintf(__('Showing %{pageSize} of %{total} %{issuableType}'), {
......
...@@ -20,6 +20,7 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; ...@@ -20,6 +20,7 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AccessorUtilities from '../../lib/utils/accessor'; import AccessorUtilities from '../../lib/utils/accessor';
import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants'; import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import listQuery from '../graphql/board_lists_deferred.query.graphql';
import ItemCount from './item_count.vue'; import ItemCount from './item_count.vue';
export default { export default {
...@@ -74,7 +75,7 @@ export default { ...@@ -74,7 +75,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['activeId']), ...mapState(['activeId', 'filterParams']),
...mapGetters(['isEpicBoard', 'isSwimlanesOn']), ...mapGetters(['isEpicBoard', 'isSwimlanesOn']),
isLoggedIn() { isLoggedIn() {
return Boolean(this.currentUserId); return Boolean(this.currentUserId);
...@@ -119,14 +120,11 @@ export default { ...@@ -119,14 +120,11 @@ export default {
} }
return false; return false;
}, },
itemsCount() {
return this.list.issuesCount;
},
countIcon() { countIcon() {
return 'issues'; return 'issues';
}, },
itemsTooltipLabel() { itemsTooltipLabel() {
return n__(`%d issue`, `%d issues`, this.itemsCount); return n__(`%d issue`, `%d issues`, this.boardLists?.issuesCount);
}, },
chevronTooltip() { chevronTooltip() {
return this.list.collapsed ? this.$options.i18n.expand : this.$options.i18n.collapse; return this.list.collapsed ? this.$options.i18n.expand : this.$options.i18n.collapse;
...@@ -158,6 +156,23 @@ export default { ...@@ -158,6 +156,23 @@ export default {
userCanDrag() { userCanDrag() {
return !this.disabled && isListDraggable(this.list); return !this.disabled && isListDraggable(this.list);
}, },
isLoading() {
return this.$apollo.queries.boardList.loading;
},
},
apollo: {
boardList: {
query: listQuery,
variables() {
return {
id: this.list.id,
filters: this.filterParams,
};
},
skip() {
return this.isEpicBoard;
},
},
}, },
created() { created() {
const localCollapsed = parseBoolean(localStorage.getItem(`${this.uniqueKey}.collapsed`)); const localCollapsed = parseBoolean(localStorage.getItem(`${this.uniqueKey}.collapsed`));
...@@ -375,10 +390,10 @@ export default { ...@@ -375,10 +390,10 @@ export default {
</gl-sprintf> </gl-sprintf>
</div> </div>
<div v-else>• {{ itemsTooltipLabel }}</div> <div v-else>• {{ itemsTooltipLabel }}</div>
<div v-if="weightFeatureAvailable"> <div v-if="weightFeatureAvailable && !isLoading">
<gl-sprintf :message="__('%{totalWeight} total weight')"> <gl-sprintf :message="__('%{totalWeight} total weight')">
<template #totalWeight>{{ list.totalWeight }}</template> <template #totalWeight>{{ boardList.totalWeight }}</template>
</gl-sprintf> </gl-sprintf>
</div> </div>
</gl-tooltip> </gl-tooltip>
...@@ -396,14 +411,18 @@ export default { ...@@ -396,14 +411,18 @@ export default {
<gl-tooltip :target="() => $refs.itemCount" :title="itemsTooltipLabel" /> <gl-tooltip :target="() => $refs.itemCount" :title="itemsTooltipLabel" />
<span ref="itemCount" class="gl-display-inline-flex gl-align-items-center"> <span ref="itemCount" class="gl-display-inline-flex gl-align-items-center">
<gl-icon class="gl-mr-2" :name="countIcon" /> <gl-icon class="gl-mr-2" :name="countIcon" />
<item-count :items-size="itemsCount" :max-issue-count="list.maxIssueCount" /> <item-count
v-if="!isLoading"
:items-size="isEpicBoard ? list.epicsCount : boardList.issuesCount"
:max-issue-count="list.maxIssueCount"
/>
</span> </span>
<!-- EE start --> <!-- EE start -->
<template v-if="weightFeatureAvailable && !isEpicBoard"> <template v-if="weightFeatureAvailable && !isEpicBoard && !isLoading">
<gl-tooltip :target="() => $refs.weightTooltip" :title="weightCountToolTip" /> <gl-tooltip :target="() => $refs.weightTooltip" :title="weightCountToolTip" />
<span ref="weightTooltip" class="gl-display-inline-flex gl-ml-3"> <span ref="weightTooltip" class="gl-display-inline-flex gl-ml-3">
<gl-icon class="gl-mr-2" name="weight" /> <gl-icon class="gl-mr-2" name="weight" />
{{ list.totalWeight }} {{ boardList.totalWeight }}
</span> </span>
</template> </template>
<!-- EE end --> <!-- EE end -->
......
...@@ -4,7 +4,6 @@ fragment BoardListShared on BoardList { ...@@ -4,7 +4,6 @@ fragment BoardListShared on BoardList {
position position
listType listType
collapsed collapsed
issuesCount
label { label {
id id
title title
......
query BoardList($id: ID!, $filters: BoardIssueInput) {
boardList(id: $id, issueFilters: $filters) {
id
issuesCount
}
}
#import "ee_else_ce/boards/graphql/issue.fragment.graphql" #import "ee_else_ce/boards/graphql/issue.fragment.graphql"
query BoardListEE( query BoardListsEE(
$fullPath: ID! $fullPath: ID!
$boardId: ID! $boardId: ID!
$id: ID $id: ID
......
...@@ -30,6 +30,7 @@ import { ...@@ -30,6 +30,7 @@ import {
} from 'ee_else_ce/boards/boards_util'; } from 'ee_else_ce/boards/boards_util';
import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create.mutation.graphql'; import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create.mutation.graphql';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql'; import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
import totalCountAndWeightQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility'; import { queryToObject } from '~/lib/utils/url_utility';
...@@ -501,9 +502,10 @@ export default { ...@@ -501,9 +502,10 @@ export default {
updateIssueOrder: async ({ commit, dispatch, state }, { moveData, mutationVariables = {} }) => { updateIssueOrder: async ({ commit, dispatch, state }, { moveData, mutationVariables = {} }) => {
try { try {
const { itemId, fromListId, toListId, moveBeforeId, moveAfterId } = moveData; const { itemId, fromListId, toListId, moveBeforeId, moveAfterId, itemNotInToList } = moveData;
const { const {
fullBoardId, fullBoardId,
filterParams,
boardItems: { boardItems: {
[itemId]: { iid, referencePath }, [itemId]: { iid, referencePath },
}, },
...@@ -522,6 +524,67 @@ export default { ...@@ -522,6 +524,67 @@ export default {
// 'mutationVariables' allows EE code to pass in extra parameters. // 'mutationVariables' allows EE code to pass in extra parameters.
...mutationVariables, ...mutationVariables,
}, },
update(
cache,
{
data: {
issueMoveList: {
issue: { weight },
},
},
},
) {
if (fromListId === toListId) return;
const updateFromList = () => {
const fromList = cache.readQuery({
query: totalCountAndWeightQuery,
variables: { id: fromListId, filters: filterParams },
});
const updatedFromList = {
boardList: {
__typename: 'BoardList',
id: fromList.boardList.id,
issuesCount: fromList.boardList.issuesCount - 1,
totalWeight: fromList.boardList.totalWeight - Number(weight),
},
};
cache.writeQuery({
query: totalCountAndWeightQuery,
variables: { id: fromListId, filters: filterParams },
data: updatedFromList,
});
};
const updateToList = () => {
if (!itemNotInToList) return;
const toList = cache.readQuery({
query: totalCountAndWeightQuery,
variables: { id: toListId, filters: filterParams },
});
const updatedToList = {
boardList: {
__typename: 'BoardList',
id: toList.boardList.id,
issuesCount: toList.boardList.issuesCount + 1,
totalWeight: toList.boardList.totalWeight + Number(weight),
},
};
cache.writeQuery({
query: totalCountAndWeightQuery,
variables: { id: toListId, filters: filterParams },
data: updatedToList,
});
};
updateFromList();
updateToList();
},
}); });
if (data?.issueMoveList?.errors.length || !data.issueMoveList) { if (data?.issueMoveList?.errors.length || !data.issueMoveList) {
...@@ -565,7 +628,7 @@ export default { ...@@ -565,7 +628,7 @@ export default {
}, },
addListNewIssue: ( addListNewIssue: (
{ state: { boardConfig, boardType, fullPath }, dispatch, commit }, { state: { boardConfig, boardType, fullPath, filterParams }, dispatch, commit },
{ issueInput, list, placeholderId = `tmp-${new Date().getTime()}` }, { issueInput, list, placeholderId = `tmp-${new Date().getTime()}` },
) => { ) => {
const input = formatIssueInput(issueInput, boardConfig); const input = formatIssueInput(issueInput, boardConfig);
...@@ -581,6 +644,27 @@ export default { ...@@ -581,6 +644,27 @@ export default {
.mutate({ .mutate({
mutation: issueCreateMutation, mutation: issueCreateMutation,
variables: { input }, variables: { input },
update(cache) {
const fromList = cache.readQuery({
query: totalCountAndWeightQuery,
variables: { id: list.id, filters: filterParams },
});
const updatedList = {
boardList: {
__typename: 'BoardList',
id: fromList.boardList.id,
issuesCount: fromList.boardList.issuesCount + 1,
totalWeight: fromList.boardList.totalWeight,
},
};
cache.writeQuery({
query: totalCountAndWeightQuery,
variables: { id: list.id, filters: filterParams },
data: updatedList,
});
},
}) })
.then(({ data }) => { .then(({ data }) => {
if (data.createIssue.errors.length) { if (data.createIssue.errors.length) {
......
...@@ -5,17 +5,32 @@ import { mapGetters } from 'vuex'; ...@@ -5,17 +5,32 @@ import { mapGetters } from 'vuex';
/* eslint-disable @gitlab/no-runtime-template-compiler */ /* eslint-disable @gitlab/no-runtime-template-compiler */
import BoardListHeaderFoss from '~/boards/components/board_list_header.vue'; import BoardListHeaderFoss from '~/boards/components/board_list_header.vue';
import { n__, __, sprintf } from '~/locale'; import { n__, __, sprintf } from '~/locale';
import listQuery from '../graphql/board_lists_deferred.query.graphql';
export default { export default {
extends: BoardListHeaderFoss, extends: BoardListHeaderFoss,
inject: ['weightFeatureAvailable'], inject: ['weightFeatureAvailable'],
apollo: {
boardList: {
query: listQuery,
variables() {
return {
id: this.list.id,
filters: this.filterParams,
};
},
skip() {
return this.isEpicBoard;
},
},
},
computed: { computed: {
...mapGetters(['isEpicBoard']), ...mapGetters(['isEpicBoard']),
countIcon() { countIcon() {
return this.isEpicBoard ? 'epic' : 'issues'; return this.isEpicBoard ? 'epic' : 'issues';
}, },
itemsCount() { itemsCount() {
return this.isEpicBoard ? this.list.epicsCount : this.list.issuesCount; return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount;
}, },
itemsTooltipLabel() { itemsTooltipLabel() {
const { maxIssueCount } = this.list; const { maxIssueCount } = this.list;
...@@ -31,7 +46,7 @@ export default { ...@@ -31,7 +46,7 @@ export default {
: n__(`%d issue`, `%d issues`, this.itemsCount); : n__(`%d issue`, `%d issues`, this.itemsCount);
}, },
weightCountToolTip() { weightCountToolTip() {
const { totalWeight } = this.list; const { totalWeight } = this.boardList;
if (this.weightFeatureAvailable) { if (this.weightFeatureAvailable) {
return sprintf(__('%{totalWeight} total weight'), { totalWeight }); return sprintf(__('%{totalWeight} total weight'), { totalWeight });
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
fragment BoardListFragment on BoardList { fragment BoardListFragment on BoardList {
...BoardListShared ...BoardListShared
maxIssueCount maxIssueCount
totalWeight
assignee { assignee {
id id
name name
......
query BoardListEE($id: ID!, $filters: BoardIssueInput) {
boardList(id: $id, issueFilters: $filters) {
id
totalWeight
issuesCount
}
}
...@@ -96,7 +96,7 @@ export default { ...@@ -96,7 +96,7 @@ export default {
...actionsCE, ...actionsCE,
addListNewIssue: async ( addListNewIssue: async (
{ state: { boardConfig, boardType, fullPath }, dispatch, commit }, { state: { boardConfig, boardType, fullPath, filterParams }, dispatch, commit },
issueInputObj, issueInputObj,
) => { ) => {
const { iterationId } = boardConfig; const { iterationId } = boardConfig;
...@@ -127,6 +127,7 @@ export default { ...@@ -127,6 +127,7 @@ export default {
boardConfig: { ...boardConfig, iterationId, iterationCadenceId }, boardConfig: { ...boardConfig, iterationId, iterationCadenceId },
boardType, boardType,
fullPath, fullPath,
filterParams,
}, },
dispatch, dispatch,
commit, commit,
......
import { GlButton, GlButtonGroup } from '@gitlab/ui'; import { GlButton, GlButtonGroup } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import BoardListHeader from 'ee/boards/components/board_list_header.vue'; import BoardListHeader from 'ee/boards/components/board_list_header.vue';
import defaultGetters from 'ee/boards/stores/getters'; import defaultGetters from 'ee/boards/stores/getters';
import { mockList, mockLabelList } from 'jest/boards/mock_data'; import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { boardListQueryResponse, mockList, mockLabelList } from 'jest/boards/mock_data';
import { ListType, inactiveId } from '~/boards/constants'; import { ListType, inactiveId } from '~/boards/constants';
import boardsEventHub from '~/boards/eventhub'; import boardsEventHub from '~/boards/eventhub';
import listQuery from 'ee/boards/graphql/board_lists_deferred.query.graphql';
import sidebarEventHub from '~/sidebar/event_hub'; import sidebarEventHub from '~/sidebar/event_hub';
const localVue = createLocalVue(); Vue.use(VueApollo);
Vue.use(Vuex);
localVue.use(Vuex);
const listMocks = { const listMocks = {
[ListType.assignee]: { [ListType.assignee]: {
...@@ -34,6 +38,18 @@ const listMocks = { ...@@ -34,6 +38,18 @@ const listMocks = {
describe('Board List Header Component', () => { describe('Board List Header Component', () => {
let store; let store;
let wrapper; let wrapper;
let fakeApollo;
beforeEach(() => {
store = new Vuex.Store({ state: { activeId: inactiveId }, defaultGetters });
});
afterEach(() => {
wrapper.destroy();
fakeApollo = null;
localStorage.clear();
});
const createComponent = ({ const createComponent = ({
listType = ListType.backlog, listType = ListType.backlog,
...@@ -41,6 +57,7 @@ describe('Board List Header Component', () => { ...@@ -41,6 +57,7 @@ describe('Board List Header Component', () => {
withLocalStorage = true, withLocalStorage = true,
isSwimlanesHeader = false, isSwimlanesHeader = false,
weightFeatureAvailable = false, weightFeatureAvailable = false,
listQueryHandler = jest.fn().mockResolvedValue(boardListQueryResponse()),
currentUserId = 1, currentUserId = 1,
state = { activeId: inactiveId }, state = { activeId: inactiveId },
getters = {}, getters = {},
...@@ -61,6 +78,7 @@ describe('Board List Header Component', () => { ...@@ -61,6 +78,7 @@ describe('Board List Header Component', () => {
); );
} }
fakeApollo = createMockApollo([[listQuery, listQueryHandler]]);
store = new Vuex.Store({ store = new Vuex.Store({
state, state,
getters: { getters: {
...@@ -72,8 +90,8 @@ describe('Board List Header Component', () => { ...@@ -72,8 +90,8 @@ describe('Board List Header Component', () => {
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(BoardListHeader, { wrapper = shallowMount(BoardListHeader, {
apolloProvider: fakeApollo,
store, store,
localVue,
propsData: { propsData: {
disabled: false, disabled: false,
list: listMock, list: listMock,
...@@ -188,10 +206,15 @@ describe('Board List Header Component', () => { ...@@ -188,10 +206,15 @@ describe('Board List Header Component', () => {
}); });
describe('weightFeatureAvailable', () => { describe('weightFeatureAvailable', () => {
it('weightFeatureAvailable is true', () => { it('weightFeatureAvailable is true', async () => {
createComponent({ weightFeatureAvailable: true }); createComponent({ weightFeatureAvailable: true });
expect(wrapper.find({ ref: 'weightTooltip' }).exists()).toBe(true); await waitForPromises();
const weightTooltip = wrapper.find({ ref: 'weightTooltip' });
expect(weightTooltip.exists()).toBe(true);
expect(weightTooltip.text()).toContain(boardListQueryResponse().data.boardList.totalWeight);
}); });
it('weightFeatureAvailable is false', () => { it('weightFeatureAvailable is false', () => {
......
...@@ -1467,6 +1467,7 @@ describe('addListNewIssue', () => { ...@@ -1467,6 +1467,7 @@ describe('addListNewIssue', () => {
iterationCadenceId, iterationCadenceId,
}), }),
}, },
update: expect.anything(),
}); });
}); });
}); });
...@@ -1500,6 +1501,7 @@ describe('addListNewIssue', () => { ...@@ -1500,6 +1501,7 @@ describe('addListNewIssue', () => {
variables: { variables: {
input: formatIssueInput(mockIssue, state.boardConfig), input: formatIssueInput(mockIssue, state.boardConfig),
}, },
update: expect.anything(),
}); });
}); });
}); });
...@@ -1536,6 +1538,7 @@ describe('addListNewIssue', () => { ...@@ -1536,6 +1538,7 @@ describe('addListNewIssue', () => {
variables: { variables: {
input: formatIssueInput(mockIssue, state.boardConfig), input: formatIssueInput(mockIssue, state.boardConfig),
}, },
update: expect.anything(),
}); });
}); });
}); });
......
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import BoardCard from '~/boards/components/board_card.vue'; import BoardCard from '~/boards/components/board_card.vue';
...@@ -6,7 +7,15 @@ import BoardList from '~/boards/components/board_list.vue'; ...@@ -6,7 +7,15 @@ import BoardList from '~/boards/components/board_list.vue';
import BoardNewIssue from '~/boards/components/board_new_issue.vue'; import BoardNewIssue from '~/boards/components/board_new_issue.vue';
import BoardNewItem from '~/boards/components/board_new_item.vue'; import BoardNewItem from '~/boards/components/board_new_item.vue';
import defaultState from '~/boards/stores/state'; import defaultState from '~/boards/stores/state';
import { mockList, mockIssuesByListId, issues, mockGroupProjects } from './mock_data'; import createMockApollo from 'helpers/mock_apollo_helper';
import listQuery from '~/boards/graphql/board_lists_deferred.query.graphql';
import {
mockList,
mockIssuesByListId,
issues,
mockGroupProjects,
boardListQueryResponse,
} from './mock_data';
export default function createComponent({ export default function createComponent({
listIssueProps = {}, listIssueProps = {},
...@@ -15,16 +24,23 @@ export default function createComponent({ ...@@ -15,16 +24,23 @@ export default function createComponent({
actions = {}, actions = {},
getters = {}, getters = {},
provide = {}, provide = {},
data = {},
state = defaultState, state = defaultState,
stubs = { stubs = {
BoardNewIssue, BoardNewIssue,
BoardNewItem, BoardNewItem,
BoardCard, BoardCard,
}, },
issuesCount,
} = {}) { } = {}) {
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(VueApollo);
localVue.use(Vuex); localVue.use(Vuex);
const fakeApollo = createMockApollo([
[listQuery, jest.fn().mockResolvedValue(boardListQueryResponse(issuesCount))],
]);
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
selectedProject: mockGroupProjects[0], selectedProject: mockGroupProjects[0],
...@@ -68,6 +84,7 @@ export default function createComponent({ ...@@ -68,6 +84,7 @@ export default function createComponent({
} }
const component = shallowMount(BoardList, { const component = shallowMount(BoardList, {
apolloProvider: fakeApollo,
localVue, localVue,
store, store,
propsData: { propsData: {
...@@ -87,6 +104,11 @@ export default function createComponent({ ...@@ -87,6 +104,11 @@ export default function createComponent({
...provide, ...provide,
}, },
stubs, stubs,
data() {
return {
...data,
};
},
}); });
return component; return component;
......
...@@ -38,7 +38,7 @@ describe('Board list component', () => { ...@@ -38,7 +38,7 @@ describe('Board list component', () => {
describe('When Expanded', () => { describe('When Expanded', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createComponent(); wrapper = createComponent({ issuesCount: 1 });
}); });
it('renders component', () => { it('renders component', () => {
...@@ -97,14 +97,6 @@ describe('Board list component', () => { ...@@ -97,14 +97,6 @@ describe('Board list component', () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(wrapper.find('.board-list-count').attributes('data-issue-id')).toBe('-1'); expect(wrapper.find('.board-list-count').attributes('data-issue-id')).toBe('-1');
}); });
it('shows how many more issues to load', async () => {
wrapper.vm.showCount = true;
wrapper.setProps({ list: { issuesCount: 20 } });
await wrapper.vm.$nextTick();
expect(wrapper.find('.board-list-count').text()).toBe('Showing 1 of 20 issues');
});
}); });
describe('load more issues', () => { describe('load more issues', () => {
...@@ -113,9 +105,7 @@ describe('Board list component', () => { ...@@ -113,9 +105,7 @@ describe('Board list component', () => {
}; };
beforeEach(() => { beforeEach(() => {
wrapper = createComponent({ wrapper = createComponent();
listProps: { issuesCount: 25 },
});
}); });
it('does not load issues if already loading', () => { it('does not load issues if already loading', () => {
...@@ -131,13 +121,27 @@ describe('Board list component', () => { ...@@ -131,13 +121,27 @@ describe('Board list component', () => {
it('shows loading more spinner', async () => { it('shows loading more spinner', async () => {
wrapper = createComponent({ wrapper = createComponent({
state: { listsFlags: { 'gid://gitlab/List/1': { isLoadingMore: true } } }, state: { listsFlags: { 'gid://gitlab/List/1': { isLoadingMore: true } } },
data: {
showCount: true,
},
}); });
wrapper.vm.showCount = true;
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(findIssueCountLoadingIcon().exists()).toBe(true); expect(findIssueCountLoadingIcon().exists()).toBe(true);
}); });
it('shows how many more issues to load', async () => {
// wrapper.vm.showCount = true;
wrapper = createComponent({
data: {
showCount: true,
},
});
await wrapper.vm.$nextTick();
expect(wrapper.find('.board-list-count').text()).toBe('Showing 1 of 20 issues');
});
}); });
describe('max issue count warning', () => { describe('max issue count warning', () => {
......
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { mockLabelList } from 'jest/boards/mock_data'; import { boardListQueryResponse, mockLabelList } from 'jest/boards/mock_data';
import BoardListHeader from '~/boards/components/board_list_header.vue'; import BoardListHeader from '~/boards/components/board_list_header.vue';
import { ListType } from '~/boards/constants'; import { ListType } from '~/boards/constants';
import listQuery from '~/boards/graphql/board_lists_deferred.query.graphql';
const localVue = createLocalVue(); Vue.use(VueApollo);
Vue.use(Vuex);
localVue.use(Vuex);
describe('Board List Header Component', () => { describe('Board List Header Component', () => {
let wrapper; let wrapper;
let store; let store;
let fakeApollo;
const updateListSpy = jest.fn(); const updateListSpy = jest.fn();
const toggleListCollapsedSpy = jest.fn(); const toggleListCollapsedSpy = jest.fn();
...@@ -20,6 +24,7 @@ describe('Board List Header Component', () => { ...@@ -20,6 +24,7 @@ describe('Board List Header Component', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null; wrapper = null;
fakeApollo = null;
localStorage.clear(); localStorage.clear();
}); });
...@@ -29,6 +34,7 @@ describe('Board List Header Component', () => { ...@@ -29,6 +34,7 @@ describe('Board List Header Component', () => {
collapsed = false, collapsed = false,
withLocalStorage = true, withLocalStorage = true,
currentUserId = 1, currentUserId = 1,
listQueryHandler = jest.fn().mockResolvedValue(boardListQueryResponse()),
} = {}) => { } = {}) => {
const boardId = '1'; const boardId = '1';
...@@ -56,10 +62,12 @@ describe('Board List Header Component', () => { ...@@ -56,10 +62,12 @@ describe('Board List Header Component', () => {
getters: { isEpicBoard: () => false }, getters: { isEpicBoard: () => false },
}); });
fakeApollo = createMockApollo([[listQuery, listQueryHandler]]);
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(BoardListHeader, { shallowMount(BoardListHeader, {
apolloProvider: fakeApollo,
store, store,
localVue,
propsData: { propsData: {
disabled: false, disabled: false,
list: listMock, list: listMock,
......
...@@ -662,3 +662,14 @@ export const mockGroupLabelsResponse = { ...@@ -662,3 +662,14 @@ export const mockGroupLabelsResponse = {
}, },
}, },
}; };
export const boardListQueryResponse = (issuesCount = 20) => ({
data: {
boardList: {
__typename: 'BoardList',
id: 'gid://gitlab/BoardList/5',
totalWeight: 5,
issuesCount,
},
},
});
...@@ -1241,6 +1241,7 @@ describe('updateIssueOrder', () => { ...@@ -1241,6 +1241,7 @@ describe('updateIssueOrder', () => {
moveBeforeId: undefined, moveBeforeId: undefined,
moveAfterId: undefined, moveAfterId: undefined,
}, },
update: expect.anything(),
}; };
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({ jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: { data: {
...@@ -1447,6 +1448,7 @@ describe('addListNewIssue', () => { ...@@ -1447,6 +1448,7 @@ describe('addListNewIssue', () => {
variables: { variables: {
input: formatIssueInput(mockIssue, stateWithBoardConfig.boardConfig), input: formatIssueInput(mockIssue, stateWithBoardConfig.boardConfig),
}, },
update: expect.anything(),
}); });
}); });
...@@ -1478,6 +1480,7 @@ describe('addListNewIssue', () => { ...@@ -1478,6 +1480,7 @@ describe('addListNewIssue', () => {
variables: { variables: {
input: formatIssueInput(issue, stateWithBoardConfig.boardConfig), input: formatIssueInput(issue, stateWithBoardConfig.boardConfig),
}, },
update: expect.anything(),
}); });
expect(payload.labelIds).toEqual(['gid://gitlab/GroupLabel/4', 'gid://gitlab/GroupLabel/5']); expect(payload.labelIds).toEqual(['gid://gitlab/GroupLabel/4', 'gid://gitlab/GroupLabel/5']);
expect(payload.assigneeIds).toEqual(['gid://gitlab/User/1', 'gid://gitlab/User/2']); expect(payload.assigneeIds).toEqual(['gid://gitlab/User/1', 'gid://gitlab/User/2']);
......
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