gitlab-ce/spec/frontend/boards/components/board_content_spec.js

292 lines
9.2 KiB
JavaScript

import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vue, { nextTick } from 'vue';
import Draggable from 'vuedraggable';
import createMockApollo from 'helpers/mock_apollo_helper';
import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import { removeParams, updateHistory } from '~/lib/utils/url_utility';
import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
import * as cacheUpdates from '~/boards/graphql/cache_updates';
import BoardColumn from '~/boards/components/board_column.vue';
import BoardContent from '~/boards/components/board_content.vue';
import BoardContentSidebar from '~/boards/components/board_content_sidebar.vue';
import updateBoardListMutation from '~/boards/graphql/board_list_update.mutation.graphql';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue';
import BoardDrawerWrapper from '~/boards/components/board_drawer_wrapper.vue';
import WorkItemDrawer from '~/work_items/components/work_item_drawer.vue';
import { DraggableItemTypes } from 'ee_else_ce/boards/constants';
import { DETAIL_VIEW_QUERY_PARAM_NAME } from '~/work_items/constants';
import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
import {
mockLists,
mockListsById,
updateBoardListResponse,
boardListsQueryResponse,
} from '../mock_data';
jest.mock('~/lib/utils/url_utility');
Vue.use(VueApollo);
describe('BoardContent', () => {
/** @type {import('@vue/test-utils').Wrapper} */
let wrapper;
let mockApollo;
const updateListHandler = jest.fn().mockResolvedValue(updateBoardListResponse);
const errorMessage = 'Failed to update list';
const updateListHandlerFailure = jest.fn().mockRejectedValue(new Error(errorMessage));
const mockUpdateCache = jest.fn();
const createComponent = ({
props = {},
canAdminList = true,
issuableType = 'issue',
isIssueBoard = true,
isEpicBoard = false,
handler = updateListHandler,
workItemDrawerEnabled = false,
} = {}) => {
mockApollo = createMockApollo([[updateBoardListMutation, handler]]);
mockApollo.clients.defaultClient.cache.updateQuery = mockUpdateCache;
const listQueryVariables = { isProject: true };
mockApollo.clients.defaultClient.writeQuery({
query: boardListsQuery,
variables: listQueryVariables,
data: boardListsQueryResponse.data,
});
wrapper = shallowMount(BoardContent, {
apolloProvider: mockApollo,
propsData: {
boardId: 'gid://gitlab/Board/1',
filterParams: {},
isSwimlanesOn: false,
boardLists: mockListsById,
listQueryVariables,
addColumnFormVisible: false,
useWorkItemDrawer: workItemDrawerEnabled,
...props,
},
provide: {
boardType: 'project',
canAdminList,
issuableType,
isIssueBoard,
isEpicBoard,
isGroupBoard: true,
disabled: false,
fullPath: 'project-path',
},
stubs: {
BoardContentSidebar: stubComponent(BoardContentSidebar, {
template: '<div></div>',
}),
BoardDrawerWrapper: stubComponent(BoardDrawerWrapper, {
template: `
<div>
<slot
:active-issuable="{ listId: 1 }"
:onDrawerClosed="() => {}"
:onIssuableDeleted="() => {}"
:onAttributeUpdated="() => {}"
:onStateUpdated="() => {}"/>
</div>`,
}),
},
});
};
const findBoardColumns = () => wrapper.findAllComponents(BoardColumn);
const findBoardAddNewColumn = () => wrapper.findComponent(BoardAddNewColumn);
const findDraggable = () => wrapper.findComponent(Draggable);
const findError = () => wrapper.findComponent(GlAlert);
const findDrawerWrapper = () => wrapper.findComponent(BoardDrawerWrapper);
const findWorkItemDrawer = () => wrapper.findComponent(WorkItemDrawer);
const moveList = () => {
const movableListsOrder = [mockLists[0].id, mockLists[1].id];
findDraggable().vm.$emit('end', {
item: { dataset: { listId: mockLists[0].id, draggableItemType: DraggableItemTypes.list } },
newIndex: 1,
to: {
children: movableListsOrder.map((listId) => ({ dataset: { listId } })),
},
});
};
beforeEach(() => {
cacheUpdates.setError = jest.fn();
});
describe('default', () => {
beforeEach(async () => {
createComponent();
await waitForPromises();
});
it('renders a BoardColumn component per list', () => {
expect(wrapper.findAllComponents(BoardColumn)).toHaveLength(mockLists.length);
});
it('renders BoardContentSidebar', () => {
expect(wrapper.findComponent(BoardContentSidebar).exists()).toBe(true);
});
it('does not render board drawer wrapper', () => {
expect(findDrawerWrapper().exists()).toBe(false);
});
it('does not display EpicsSwimlanes component', () => {
expect(wrapper.findComponent(EpicsSwimlanes).exists()).toBe(false);
expect(findError().exists()).toBe(false);
});
it('sets delay and delayOnTouchOnly attributes on board list', () => {
const listEl = wrapper.findComponent({ ref: 'list' });
expect(listEl.attributes('delay')).toBe('100');
expect(listEl.attributes('delayontouchonly')).toBe('true');
});
it('does not show the "add column" form', () => {
expect(findBoardAddNewColumn().exists()).toBe(false);
});
it('reorders lists', async () => {
moveList();
await waitForPromises();
expect(updateListHandler).toHaveBeenCalled();
});
it('sets error on reorder lists failure', async () => {
createComponent({ handler: updateListHandlerFailure });
moveList();
await waitForPromises();
expect(cacheUpdates.setError).toHaveBeenCalled();
});
describe('when error is passed', () => {
beforeEach(async () => {
createComponent({ props: { error: 'Error' } });
await waitForPromises();
});
it('displays error banner', () => {
expect(findError().exists()).toBe(true);
});
it('dismisses error', async () => {
findError().vm.$emit('dismiss');
await nextTick();
expect(cacheUpdates.setError).toHaveBeenCalledWith({ message: null, captureError: false });
});
});
});
describe('when issuableType is not issue', () => {
beforeEach(() => {
createComponent({ issuableType: 'foo', isIssueBoard: false });
});
it('does not render BoardContentSidebar', () => {
expect(wrapper.findComponent(BoardContentSidebar).exists()).toBe(false);
});
it('does not render board drawer wrapper', () => {
expect(findDrawerWrapper().exists()).toBe(false);
});
});
describe('can admin list', () => {
beforeEach(() => {
createComponent({ canAdminList: true });
});
it('renders draggable component', () => {
expect(findDraggable().exists()).toBe(true);
});
it('renders BoardAddNewColumnTrigger component', () => {
expect(wrapper.findComponent(BoardAddNewColumnTrigger).exists()).toBe(true);
});
});
describe('can not admin list', () => {
beforeEach(() => {
createComponent({ canAdminList: false });
});
it('does not render draggable component', () => {
expect(findDraggable().exists()).toBe(false);
});
it('does not BoardAddNewColumnTrigger component', () => {
expect(wrapper.findComponent(BoardAddNewColumnTrigger).exists()).toBe(false);
});
});
describe('when "add column" form is visible', () => {
beforeEach(() => {
createComponent({ props: { addColumnFormVisible: true } });
});
it('shows the "add column" form', () => {
expect(findBoardAddNewColumn().exists()).toBe(true);
});
it('hides other columns on mobile viewports', () => {
findBoardColumns().wrappers.forEach((column) => {
expect(column.classes()).toEqual(['!gl-hidden', 'sm:!gl-inline-block']);
});
});
});
describe('when work item drawer is enabled', () => {
beforeEach(() => {
createComponent({ workItemDrawerEnabled: true });
});
it('does not render board sidebar', () => {
expect(wrapper.findComponent(BoardContentSidebar).exists()).toBe(false);
});
it('renders board drawer wrapper', () => {
expect(findDrawerWrapper().exists()).toBe(true);
});
it('updates Apollo cache when work item in the drawer is updated', () => {
findWorkItemDrawer().vm.$emit('work-item-updated', { iid: '1' });
expect(mockUpdateCache).toHaveBeenCalled();
});
});
describe('when all columns cannot find active item', () => {
beforeEach(() => {
createComponent({ workItemDrawerEnabled: true });
findBoardColumns().wrappers.forEach((column) => {
column.vm.$emit('cannot-find-active-item');
});
});
it('calls `updateHistory`', () => {
expect(updateHistory).toHaveBeenCalled();
});
it('calls `removeParams`', () => {
expect(removeParams).toHaveBeenCalledWith([DETAIL_VIEW_QUERY_PARAM_NAME]);
});
});
});