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

233 lines
6.8 KiB
JavaScript

import { GlLabel } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BoardCard from '~/boards/components/board_card.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue';
import selectedBoardItemsQuery from '~/boards/graphql/client/selected_board_items.query.graphql';
import activeBoardItemQuery from '~/boards/graphql/client/active_board_item.query.graphql';
import isShowingLabelsQuery from '~/graphql_shared/client/is_showing_labels.query.graphql';
import { mockLabelList, mockIssue, DEFAULT_COLOR } from '../mock_data';
describe('Board card', () => {
let wrapper;
Vue.use(VueApollo);
const mockSetActiveBoardItemResolver = jest.fn();
const mockSetSelectedBoardItemsResolver = jest.fn();
const mockApollo = createMockApollo([], {
Mutation: {
setActiveBoardItem: mockSetActiveBoardItemResolver,
setSelectedBoardItems: mockSetSelectedBoardItemsResolver,
},
});
// this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
const mountComponent = ({
propsData = {},
provide = {},
stubs = { BoardCardInner },
item = mockIssue,
selectedBoardItems = [],
activeBoardItem = {},
} = {}) => {
mockApollo.clients.defaultClient.cache.writeQuery({
query: isShowingLabelsQuery,
data: {
isShowingLabels: true,
},
});
mockApollo.clients.defaultClient.cache.writeQuery({
query: selectedBoardItemsQuery,
data: {
selectedBoardItems,
},
});
mockApollo.clients.defaultClient.cache.writeQuery({
query: activeBoardItemQuery,
data: {
activeBoardItem: { ...activeBoardItem, listId: 'gid://gitlab/List/1' },
},
});
wrapper = shallowMountExtended(BoardCard, {
apolloProvider: mockApollo,
stubs: {
...stubs,
BoardCardInner,
},
propsData: {
list: mockLabelList,
item,
index: 0,
...propsData,
},
provide: {
groupId: null,
rootPath: '/',
scopedLabelsAvailable: false,
isIssueBoard: true,
isEpicBoard: false,
issuableType: 'issue',
isGroupBoard: true,
disabled: false,
allowSubEpics: false,
...provide,
},
});
};
const selectCard = async () => {
wrapper.trigger('click');
await nextTick();
};
const multiSelectCard = async () => {
wrapper.trigger('click', { ctrlKey: true });
await nextTick();
};
beforeEach(() => {
window.gon = { features: {} };
});
describe('when GlLabel is clicked in BoardCardInner', () => {
it("doesn't call setSelectedBoardItemsMutation", async () => {
mountComponent();
await wrapper.findComponent(GlLabel).trigger('mouseup');
expect(mockSetSelectedBoardItemsResolver).toHaveBeenCalledTimes(0);
});
});
describe('when issuable title is clicked in BoardCardInner and issuesListDrawer feature is enabled', () => {
it('calls mockSetSelectedBoardItemsResolver', async () => {
mountComponent({ provide: { glFeatures: { issuesListDrawer: true } } });
await wrapper.findByTestId('board-card-title-link').trigger('click');
await waitForPromises();
expect(mockSetActiveBoardItemResolver).toHaveBeenCalledTimes(1);
});
});
it('should not highlight the card by default', () => {
mountComponent();
expect(wrapper.classes()).not.toContain('is-active');
expect(wrapper.classes()).not.toContain('multi-select');
});
it('should highlight the card with a correct style when selected', async () => {
mountComponent({ activeBoardItem: { ...mockIssue, listId: 'gid://gitlab/List/1' } });
await waitForPromises();
expect(wrapper.classes()).toContain('is-active');
expect(wrapper.classes()).not.toContain('multi-select');
});
it('should highlight the card with a correct style when multi-selected', () => {
mountComponent({ selectedBoardItems: [mockIssue.id] });
expect(wrapper.classes()).toContain('multi-select');
expect(wrapper.classes()).not.toContain('is-active');
});
describe('when mouseup event is called on the card', () => {
beforeEach(() => {
mountComponent();
});
describe('when not using multi-select', () => {
it('set active board item on client when clicking on card', async () => {
await selectCard();
await waitForPromises();
expect(mockSetActiveBoardItemResolver).toHaveBeenCalledWith(
{},
{
boardItem: mockIssue,
listId: 'gid://gitlab/List/2',
},
expect.anything(),
expect.anything(),
);
});
});
describe('when using multi-select', () => {
beforeEach(() => {
window.gon = { features: { boardMultiSelect: true } };
});
it('should call setSelectedBoardItemsMutation with correct parameters', async () => {
await multiSelectCard();
expect(mockSetSelectedBoardItemsResolver).toHaveBeenCalledTimes(1);
expect(mockSetSelectedBoardItemsResolver).toHaveBeenCalledWith(
expect.any(Object),
{
itemId: mockIssue.id,
},
expect.anything(),
expect.anything(),
);
});
});
});
describe('when card is loading', () => {
it('card is disabled and user cannot drag', () => {
mountComponent({ item: { ...mockIssue, isLoading: true } });
expect(wrapper.classes()).toContain('is-disabled');
expect(wrapper.classes()).not.toContain('gl-cursor-grab');
});
});
describe('when card is not loading', () => {
it('user can drag', () => {
mountComponent();
expect(wrapper.classes()).not.toContain('is-disabled');
expect(wrapper.classes()).toContain('gl-cursor-grab');
});
});
describe('epic colors', () => {
it('applies the correct color and border', () => {
mountComponent({
item: {
...mockIssue,
color: DEFAULT_COLOR,
},
});
expect(wrapper.classes()).toEqual(
expect.arrayContaining(['gl-pl-4', 'gl-border-l-solid', 'gl-border-l-4']),
);
expect(wrapper.attributes('style')).toContain(`border-left-color: ${DEFAULT_COLOR}`);
});
it('does not render border if color is not present', () => {
mountComponent({
item: {
...mockIssue,
color: null,
},
});
expect(wrapper.classes()).not.toEqual(
expect.arrayContaining(['gl-pl-4', 'gl-border-l-solid', 'gl-border-l-4']),
);
expect(wrapper.attributes('style')).toBe(undefined);
});
});
});