debian-mirror-gitlab/spec/frontend/design_management/pages/index_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

801 lines
25 KiB
JavaScript
Raw Normal View History

2021-03-11 19:13:27 +05:30
import { GlEmptyState } from '@gitlab/ui';
2022-04-04 11:22:00 +05:30
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
2020-11-24 15:15:51 +05:30
import VueApollo, { ApolloMutation } from 'vue-apollo';
2020-05-24 23:13:21 +05:30
import VueRouter from 'vue-router';
2021-03-11 19:13:27 +05:30
import VueDraggable from 'vuedraggable';
2021-03-08 18:12:59 +05:30
import createMockApollo from 'helpers/mock_apollo_helper';
2022-04-04 11:22:00 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2021-01-03 14:25:43 +05:30
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
2021-01-29 00:20:46 +05:30
import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
2021-03-11 19:13:27 +05:30
import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
2020-05-24 23:13:21 +05:30
import DeleteButton from '~/design_management/components/delete_button.vue';
2021-03-11 19:13:27 +05:30
import DesignDestroyer from '~/design_management/components/design_destroyer.vue';
2020-11-24 15:15:51 +05:30
import Design from '~/design_management/components/list/item.vue';
2021-03-11 19:13:27 +05:30
import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql';
import uploadDesignMutation from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
import Index from '~/design_management/pages/index.vue';
import createRouter from '~/design_management/router';
2020-05-24 23:13:21 +05:30
import { DESIGNS_ROUTE_NAME } from '~/design_management/router/constants';
2021-03-11 19:13:27 +05:30
import * as utils from '~/design_management/utils/design_management_utils';
2020-05-24 23:13:21 +05:30
import {
EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE,
EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
} from '~/design_management/utils/error_messages';
2021-03-11 19:13:27 +05:30
import {
DESIGN_TRACKING_PAGE_NAME,
DESIGN_SNOWPLOW_EVENT_TYPES,
} from '~/design_management/utils/tracking';
2021-01-29 00:20:46 +05:30
import createFlash from '~/flash';
2021-03-11 19:13:27 +05:30
import DesignDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
2020-11-24 15:15:51 +05:30
import {
designListQueryResponse,
2021-01-03 14:25:43 +05:30
designUploadMutationCreatedResponse,
designUploadMutationUpdatedResponse,
2020-11-24 15:15:51 +05:30
permissionsQueryResponse,
moveDesignMutationResponse,
reorderedDesigns,
moveDesignMutationResponseWithErrors,
} from '../mock_data/apollo_mock';
2020-06-23 00:09:42 +05:30
jest.mock('~/flash.js');
const mockPageEl = {
classList: {
remove: jest.fn(),
},
};
jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageEl);
2020-05-24 23:13:21 +05:30
2020-10-24 23:57:45 +05:30
const scrollIntoViewMock = jest.fn();
HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
2020-06-23 00:09:42 +05:30
const router = createRouter();
2022-04-04 11:22:00 +05:30
Vue.use(VueRouter);
2020-05-24 23:13:21 +05:30
const mockDesigns = [
{
id: 'design-1',
image: 'design-1-image',
filename: 'design-1-name',
event: 'NONE',
notesCount: 0,
},
{
id: 'design-2',
image: 'design-2-image',
filename: 'design-2-name',
event: 'NONE',
notesCount: 1,
},
{
id: 'design-3',
image: 'design-3-image',
filename: 'design-3-name',
event: 'NONE',
notesCount: 0,
},
];
const mockVersion = {
2020-10-24 23:57:45 +05:30
id: 'gid://gitlab/DesignManagement::Version/1',
2020-05-24 23:13:21 +05:30
};
2020-11-24 15:15:51 +05:30
const designToMove = {
__typename: 'Design',
id: '2',
event: 'NONE',
filename: 'fox_2.jpg',
notesCount: 2,
image: 'image-2',
imageV432x230: 'image-2',
};
2020-05-24 23:13:21 +05:30
describe('Design management index page', () => {
2022-03-02 08:16:31 +05:30
const registerPath = '/users/sign_up?redirect_to_referer=yes';
const signInPath = '/users/sign_in?redirect_to_referer=yes';
2020-05-24 23:13:21 +05:30
let mutate;
let wrapper;
2020-11-24 15:15:51 +05:30
let fakeApollo;
let moveDesignHandler;
2020-05-24 23:13:21 +05:30
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
2021-04-17 20:07:23 +05:30
const findSelectAllButton = () => wrapper.find('[data-testid="select-all-designs-button"');
2020-05-24 23:13:21 +05:30
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
2021-01-03 14:25:43 +05:30
const findDesignCollectionIsCopying = () =>
wrapper.find('[data-testid="design-collection-is-copying"');
2020-05-24 23:13:21 +05:30
const findDeleteButton = () => wrapper.find(DeleteButton);
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
2020-10-24 23:57:45 +05:30
const dropzoneClasses = () => findDropzone().classes();
const findDropzoneWrapper = () => wrapper.find('[data-testid="design-dropzone-wrapper"]');
2020-05-24 23:13:21 +05:30
const findFirstDropzoneWithDesign = () => wrapper.findAll(DesignDropzone).at(1);
2020-10-24 23:57:45 +05:30
const findDesignsWrapper = () => wrapper.find('[data-testid="designs-root"]');
2020-11-24 15:15:51 +05:30
const findDesigns = () => wrapper.findAll(Design);
2021-01-03 14:25:43 +05:30
const draggableAttributes = () => wrapper.find(VueDraggable).vm.$attrs;
2021-01-29 00:20:46 +05:30
const findDesignUploadButton = () => wrapper.find('[data-testid="design-upload-button"]');
const findDesignToolbarWrapper = () => wrapper.find('[data-testid="design-toolbar-wrapper"]');
2020-11-24 15:15:51 +05:30
async function moveDesigns(localWrapper) {
2022-04-04 11:22:00 +05:30
await waitForPromises();
2020-11-24 15:15:51 +05:30
localWrapper.find(VueDraggable).vm.$emit('input', reorderedDesigns);
localWrapper.find(VueDraggable).vm.$emit('change', {
moved: {
newIndex: 0,
element: designToMove,
},
});
}
2020-05-24 23:13:21 +05:30
function createComponent({
loading = false,
allVersions = [],
2021-01-03 14:25:43 +05:30
designCollection = { designs: mockDesigns, copyState: 'READY' },
2020-05-24 23:13:21 +05:30
createDesign = true,
stubs = {},
mockMutate = jest.fn().mockResolvedValue(),
} = {}) {
mutate = mockMutate;
const $apollo = {
queries: {
2021-01-03 14:25:43 +05:30
designCollection: {
2020-05-24 23:13:21 +05:30
loading,
},
permissions: {
loading,
},
},
mutate,
};
wrapper = shallowMount(Index, {
2020-10-24 23:57:45 +05:30
data() {
return {
allVersions,
2021-01-03 14:25:43 +05:30
designCollection,
2020-10-24 23:57:45 +05:30
permissions: {
createDesign,
},
};
},
2020-05-24 23:13:21 +05:30
mocks: { $apollo },
router,
2020-10-24 23:57:45 +05:30
stubs: { DesignDestroyer, ApolloMutation, VueDraggable, ...stubs },
2021-03-08 18:12:59 +05:30
attachTo: document.body,
2020-10-24 23:57:45 +05:30
provide: {
projectPath: 'project-path',
issueIid: '1',
2022-03-02 08:16:31 +05:30
registerPath,
signInPath,
2020-05-24 23:13:21 +05:30
},
});
}
2020-11-24 15:15:51 +05:30
function createComponentWithApollo({
moveHandler = jest.fn().mockResolvedValue(moveDesignMutationResponse),
}) {
2022-04-04 11:22:00 +05:30
Vue.use(VueApollo);
2020-11-24 15:15:51 +05:30
moveDesignHandler = moveHandler;
const requestHandlers = [
[getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
[permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
[moveDesignMutation, moveDesignHandler],
];
2022-06-21 17:19:12 +05:30
fakeApollo = createMockApollo(requestHandlers, {}, { addTypename: true });
2020-11-24 15:15:51 +05:30
wrapper = shallowMount(Index, {
apolloProvider: fakeApollo,
router,
stubs: { VueDraggable },
2022-03-02 08:16:31 +05:30
provide: {
registerPath,
signInPath,
},
2020-11-24 15:15:51 +05:30
});
}
2020-05-24 23:13:21 +05:30
afterEach(() => {
wrapper.destroy();
2020-11-24 15:15:51 +05:30
wrapper = null;
2020-05-24 23:13:21 +05:30
});
describe('designs', () => {
it('renders loading icon', () => {
createComponent({ loading: true });
2020-10-24 23:57:45 +05:30
expect(wrapper.element).toMatchSnapshot();
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('renders error', async () => {
2020-05-24 23:13:21 +05:30
createComponent();
2022-03-02 08:16:31 +05:30
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
2020-05-24 23:13:21 +05:30
wrapper.setData({ error: true });
2021-03-08 18:12:59 +05:30
await nextTick();
expect(wrapper.element).toMatchSnapshot();
2020-05-24 23:13:21 +05:30
});
it('renders a toolbar with buttons when there are designs', () => {
2021-01-03 14:25:43 +05:30
createComponent({ allVersions: [mockVersion] });
2020-05-24 23:13:21 +05:30
2020-10-24 23:57:45 +05:30
expect(findToolbar().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
it('renders designs list and header with upload button', () => {
2021-01-03 14:25:43 +05:30
createComponent({ allVersions: [mockVersion] });
2020-05-24 23:13:21 +05:30
2021-01-29 00:20:46 +05:30
expect(findDesignsWrapper().exists()).toBe(true);
expect(findDesigns().length).toBe(3);
expect(findDesignToolbarWrapper().exists()).toBe(true);
expect(findDesignUploadButton().exists()).toBe(true);
2020-05-24 23:13:21 +05:30
});
it('does not render toolbar when there is no permission', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion], createDesign: false });
2021-01-29 00:20:46 +05:30
expect(findDesignToolbarWrapper().exists()).toBe(false);
expect(findDesignUploadButton().exists()).toBe(false);
2020-10-24 23:57:45 +05:30
});
it('has correct classes applied to design dropzone', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
expect(dropzoneClasses()).toContain('design-list-item');
expect(dropzoneClasses()).toContain('design-list-item-new');
});
it('has correct classes applied to dropzone wrapper', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
expect(findDropzoneWrapper().classes()).toEqual([
'gl-flex-direction-column',
'col-md-6',
'col-lg-3',
'gl-mb-3',
]);
2020-05-24 23:13:21 +05:30
});
});
describe('when has no designs', () => {
beforeEach(() => {
2021-01-03 14:25:43 +05:30
createComponent({ designCollection: { designs: [], copyState: 'READY' } });
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('renders design dropzone', async () => {
await nextTick();
expect(findDropzone().exists()).toBe(true);
});
2020-05-24 23:13:21 +05:30
2020-10-24 23:57:45 +05:30
it('has correct classes applied to design dropzone', () => {
expect(dropzoneClasses()).not.toContain('design-list-item');
expect(dropzoneClasses()).not.toContain('design-list-item-new');
});
it('has correct classes applied to dropzone wrapper', () => {
expect(findDropzoneWrapper().classes()).toEqual(['col-12']);
});
2021-03-08 18:12:59 +05:30
it('does not render a toolbar with buttons', async () => {
await nextTick();
expect(findToolbar().exists()).toBe(false);
});
2020-05-24 23:13:21 +05:30
});
2021-01-03 14:25:43 +05:30
describe('handling design collection copy state', () => {
it.each`
copyState | isRendered | description
${'IN_PROGRESS'} | ${true} | ${'renders'}
${'READY'} | ${false} | ${'does not render'}
${'ERROR'} | ${false} | ${'does not render'}
`(
'$description the copying message if design collection copyState is $copyState',
({ copyState, isRendered }) => {
createComponent({ designCollection: { designs: [], copyState } });
expect(findDesignCollectionIsCopying().exists()).toBe(isRendered);
},
);
});
2020-05-24 23:13:21 +05:30
describe('uploading designs', () => {
2021-03-08 18:12:59 +05:30
it('calls mutation on upload', async () => {
2020-05-24 23:13:21 +05:30
createComponent({ stubs: { GlEmptyState } });
const mutationVariables = {
update: expect.anything(),
context: {
hasUpload: true,
},
2021-03-08 18:12:59 +05:30
mutation: uploadDesignMutation,
2020-05-24 23:13:21 +05:30
variables: {
files: [{ name: 'test' }],
2020-10-24 23:57:45 +05:30
projectPath: 'project-path',
2020-05-24 23:13:21 +05:30
iid: '1',
},
optimisticResponse: {
__typename: 'Mutation',
designManagementUpload: {
__typename: 'DesignManagementUploadPayload',
designs: [
{
__typename: 'Design',
id: expect.anything(),
2021-01-03 14:25:43 +05:30
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
2020-05-24 23:13:21 +05:30
image: '',
imageV432x230: '',
filename: 'test',
fullPath: '',
event: 'NONE',
notesCount: 0,
diffRefs: {
__typename: 'DiffRefs',
baseSha: '',
startSha: '',
headSha: '',
},
discussions: {
__typename: 'DesignDiscussion',
nodes: [],
},
versions: {
__typename: 'DesignVersionConnection',
2020-10-24 23:57:45 +05:30
nodes: {
__typename: 'DesignVersion',
id: expect.anything(),
sha: expect.anything(),
2021-11-11 11:23:49 +05:30
createdAt: '',
author: {
__typename: 'UserCore',
id: expect.anything(),
name: '',
avatarUrl: '',
},
2020-05-24 23:13:21 +05:30
},
},
},
],
skippedDesigns: [],
errors: [],
},
},
};
2021-03-08 18:12:59 +05:30
await nextTick();
findDropzone().vm.$emit('change', [{ name: 'test' }]);
expect(mutate).toHaveBeenCalledWith(mutationVariables);
expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
expect(wrapper.vm.isSaving).toBeTruthy();
expect(dropzoneClasses()).toContain('design-list-item');
expect(dropzoneClasses()).toContain('design-list-item-new');
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('sets isSaving', async () => {
2020-05-24 23:13:21 +05:30
createComponent();
const uploadDesign = wrapper.vm.onUploadDesign([
{
name: 'test',
},
]);
expect(wrapper.vm.isSaving).toBe(true);
2021-03-08 18:12:59 +05:30
await uploadDesign;
expect(wrapper.vm.isSaving).toBe(false);
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('updates state appropriately after upload complete', async () => {
2020-05-24 23:13:21 +05:30
createComponent({ stubs: { GlEmptyState } });
2022-03-02 08:16:31 +05:30
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
2020-05-24 23:13:21 +05:30
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
2021-01-03 14:25:43 +05:30
wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
2021-03-08 18:12:59 +05:30
await nextTick();
expect(wrapper.vm.filesToBeSaved).toEqual([]);
expect(wrapper.vm.isSaving).toBeFalsy();
expect(wrapper.vm.isLatestVersion).toBe(true);
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('updates state appropriately after upload error', async () => {
2020-05-24 23:13:21 +05:30
createComponent({ stubs: { GlEmptyState } });
2022-03-02 08:16:31 +05:30
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
2020-05-24 23:13:21 +05:30
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
wrapper.vm.onUploadDesignError();
2021-03-08 18:12:59 +05:30
await nextTick();
expect(wrapper.vm.filesToBeSaved).toEqual([]);
expect(wrapper.vm.isSaving).toBeFalsy();
expect(createFlash).toHaveBeenCalled();
2020-05-24 23:13:21 +05:30
});
it('does not call mutation if createDesign is false', () => {
createComponent({ createDesign: false });
wrapper.vm.onUploadDesign([]);
expect(mutate).not.toHaveBeenCalled();
});
describe('upload count limit', () => {
const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
it('does not warn when the max files are uploaded', () => {
createComponent();
wrapper.vm.onUploadDesign(new Array(MAXIMUM_FILE_UPLOAD_LIMIT).fill(mockDesigns[0]));
expect(createFlash).not.toHaveBeenCalled();
});
it('warns when too many files are uploaded', () => {
createComponent();
wrapper.vm.onUploadDesign(new Array(MAXIMUM_FILE_UPLOAD_LIMIT + 1).fill(mockDesigns[0]));
expect(createFlash).toHaveBeenCalled();
});
});
2021-03-08 18:12:59 +05:30
it('flashes warning if designs are skipped', async () => {
2020-05-24 23:13:21 +05:30
createComponent({
mockMutate: () =>
Promise.resolve({
data: { designManagementUpload: { skippedDesigns: [{ filename: 'test.jpg' }] } },
}),
});
const uploadDesign = wrapper.vm.onUploadDesign([
{
name: 'test',
},
]);
2021-03-08 18:12:59 +05:30
await uploadDesign;
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith({
message: 'Upload skipped. test.jpg did not change.',
types: 'warning',
2020-05-24 23:13:21 +05:30
});
});
describe('dragging onto an existing design', () => {
2021-03-08 18:12:59 +05:30
let mockMutate;
2020-05-24 23:13:21 +05:30
beforeEach(() => {
2021-03-08 18:12:59 +05:30
mockMutate = jest.fn().mockResolvedValue();
createComponent({ designs: mockDesigns, allVersions: [mockVersion], mockMutate });
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('uploads designs with valid upload', () => {
2020-05-24 23:13:21 +05:30
const mockUploadPayload = [
{
name: mockDesigns[0].filename,
},
];
const designDropzone = findFirstDropzoneWithDesign();
designDropzone.vm.$emit('change', mockUploadPayload);
2021-03-08 18:12:59 +05:30
const [{ mutation, variables }] = mockMutate.mock.calls[0];
expect(mutation).toBe(uploadDesignMutation);
expect(variables).toStrictEqual({
files: mockUploadPayload,
iid: '1',
projectPath: 'project-path',
});
2020-05-24 23:13:21 +05:30
});
it.each`
description | eventPayload | message
${'> 1 file'} | ${[{ name: 'test' }, { name: 'test-2' }]} | ${EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE}
${'different filename'} | ${[{ name: 'wrong-name' }]} | ${EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE}
`('calls createFlash when upload has $description', ({ eventPayload, message }) => {
const designDropzone = findFirstDropzoneWithDesign();
designDropzone.vm.$emit('change', eventPayload);
expect(createFlash).toHaveBeenCalledTimes(1);
2021-01-29 00:20:46 +05:30
expect(createFlash).toHaveBeenCalledWith({ message });
2020-05-24 23:13:21 +05:30
});
});
2021-01-03 14:25:43 +05:30
describe('tracking', () => {
let trackingSpy;
beforeEach(() => {
trackingSpy = mockTracking('_category_', undefined, jest.spyOn);
createComponent({ stubs: { GlEmptyState } });
});
afterEach(() => {
unmockTracking();
});
it('tracks design creation', () => {
wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
expect(trackingSpy).toHaveBeenCalledTimes(1);
2021-02-22 17:27:13 +05:30
expect(trackingSpy).toHaveBeenCalledWith(
DESIGN_TRACKING_PAGE_NAME,
DESIGN_SNOWPLOW_EVENT_TYPES.CREATE_DESIGN,
);
2021-01-03 14:25:43 +05:30
});
it('tracks design modification', () => {
wrapper.vm.onUploadDesignDone(designUploadMutationUpdatedResponse);
expect(trackingSpy).toHaveBeenCalledTimes(1);
2021-02-22 17:27:13 +05:30
expect(trackingSpy).toHaveBeenCalledWith(
DESIGN_TRACKING_PAGE_NAME,
DESIGN_SNOWPLOW_EVENT_TYPES.UPDATE_DESIGN,
);
2021-01-03 14:25:43 +05:30
});
});
2020-05-24 23:13:21 +05:30
});
describe('on latest version when has designs', () => {
beforeEach(() => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
});
it('renders design checkboxes', () => {
expect(findDesignCheckboxes()).toHaveLength(mockDesigns.length);
});
it('renders toolbar buttons', () => {
expect(findToolbar().exists()).toBe(true);
2020-10-24 23:57:45 +05:30
expect(findToolbar().isVisible()).toBe(true);
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('adds two designs to selected designs when their checkboxes are checked', async () => {
findDesignCheckboxes().at(0).trigger('click');
await nextTick();
findDesignCheckboxes().at(1).trigger('click');
await nextTick();
expect(findDeleteButton().exists()).toBe(true);
expect(findSelectAllButton().text()).toBe('Deselect all');
2021-04-17 20:07:23 +05:30
findDeleteButton().vm.$emit('delete-selected-designs');
2021-03-08 18:12:59 +05:30
const [{ variables }] = mutate.mock.calls[0];
expect(variables.filenames).toStrictEqual([mockDesigns[0].filename, mockDesigns[1].filename]);
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('adds all designs to selected designs when Select All button is clicked', async () => {
2020-05-24 23:13:21 +05:30
findSelectAllButton().vm.$emit('click');
2021-03-08 18:12:59 +05:30
await nextTick();
expect(findDeleteButton().props().hasSelectedDesigns).toBe(true);
expect(findSelectAllButton().text()).toBe('Deselect all');
expect(wrapper.vm.selectedDesigns).toEqual(mockDesigns.map((design) => design.filename));
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('removes all designs from selected designs when at least one design was selected', async () => {
findDesignCheckboxes().at(0).trigger('click');
await nextTick();
findSelectAllButton().vm.$emit('click');
await nextTick();
expect(findDeleteButton().props().hasSelectedDesigns).toBe(false);
expect(findSelectAllButton().text()).toBe('Select all');
expect(wrapper.vm.selectedDesigns).toEqual([]);
2020-05-24 23:13:21 +05:30
});
});
2020-10-24 23:57:45 +05:30
it('on latest version when has no designs toolbar buttons are invisible', () => {
2021-01-03 14:25:43 +05:30
createComponent({
designCollection: { designs: [], copyState: 'READY' },
allVersions: [mockVersion],
});
2020-10-24 23:57:45 +05:30
expect(findToolbar().isVisible()).toBe(false);
2020-05-24 23:13:21 +05:30
});
describe('on non-latest version', () => {
beforeEach(() => {
2021-01-03 14:25:43 +05:30
createComponent({ allVersions: [mockVersion] });
2020-11-24 15:15:51 +05:30
});
2020-05-24 23:13:21 +05:30
2020-11-24 15:15:51 +05:30
it('does not render design checkboxes', async () => {
await router.replace({
2020-05-24 23:13:21 +05:30
name: DESIGNS_ROUTE_NAME,
query: {
version: '2',
},
});
expect(findDesignCheckboxes()).toHaveLength(0);
});
it('does not render Delete selected button', () => {
expect(findDeleteButton().exists()).toBe(false);
});
it('does not render Select All button', () => {
expect(findSelectAllButton().exists()).toBe(false);
});
});
describe('pasting a design', () => {
let event;
2021-03-08 18:12:59 +05:30
let mockMutate;
2020-05-24 23:13:21 +05:30
beforeEach(() => {
2021-03-08 18:12:59 +05:30
mockMutate = jest.fn().mockResolvedValue({});
createComponent({ designs: mockDesigns, allVersions: [mockVersion], mockMutate });
2020-05-24 23:13:21 +05:30
event = new Event('paste');
2020-10-24 23:57:45 +05:30
event.clipboardData = {
files: [{ name: 'image.png', type: 'image/png' }],
getData: () => 'test.png',
};
2020-05-24 23:13:21 +05:30
});
2021-03-08 18:12:59 +05:30
it('does not upload designs if designs wrapper is not hovered', () => {
2020-05-24 23:13:21 +05:30
document.dispatchEvent(event);
2021-03-08 18:12:59 +05:30
expect(mockMutate).not.toHaveBeenCalled();
2020-05-24 23:13:21 +05:30
});
2021-11-11 11:23:49 +05:30
it('does not upload designs if designs wrapper is destroyed', () => {
findDesignsWrapper().trigger('mouseenter');
wrapper.destroy();
document.dispatchEvent(event);
expect(mockMutate).not.toHaveBeenCalled();
});
2020-10-24 23:57:45 +05:30
describe('when designs wrapper is hovered', () => {
2021-03-08 18:12:59 +05:30
let realDateNow;
const today = () => new Date('2020-12-25');
beforeAll(() => {
realDateNow = Date.now;
global.Date.now = today;
});
afterAll(() => {
global.Date.now = realDateNow;
});
2020-10-24 23:57:45 +05:30
beforeEach(() => {
findDesignsWrapper().trigger('mouseenter');
});
2020-05-24 23:13:21 +05:30
2021-03-08 18:12:59 +05:30
it('uploads design with valid paste', () => {
2020-10-24 23:57:45 +05:30
document.dispatchEvent(event);
2020-05-24 23:13:21 +05:30
2021-03-08 18:12:59 +05:30
const [{ mutation, variables }] = mockMutate.mock.calls[0];
expect(mutation).toBe(uploadDesignMutation);
expect(variables).toStrictEqual({
files: expect.any(Array),
iid: '1',
projectPath: 'project-path',
});
expect(variables.files).toEqual(event.clipboardData.files.map((f) => new File([f], '')));
2020-10-24 23:57:45 +05:30
});
2020-05-24 23:13:21 +05:30
2021-12-11 22:18:48 +05:30
it('display original file name', () => {
event.clipboardData.files = [new File([new Blob()], 'test.png', { type: 'image/png' })];
document.dispatchEvent(event);
const [{ mutation, variables }] = mockMutate.mock.calls[0];
expect(mutation).toBe(uploadDesignMutation);
expect(variables).toStrictEqual({
files: expect.any(Array),
iid: '1',
projectPath: 'project-path',
});
expect(variables.files[0].name).toEqual('test.png');
});
2020-10-24 23:57:45 +05:30
it('renames a design if it has an image.png filename', () => {
2021-03-08 18:12:59 +05:30
event.clipboardData.getData = () => 'image.png';
2020-10-24 23:57:45 +05:30
document.dispatchEvent(event);
2020-05-24 23:13:21 +05:30
2021-03-08 18:12:59 +05:30
const [{ mutation, variables }] = mockMutate.mock.calls[0];
expect(mutation).toBe(uploadDesignMutation);
expect(variables).toStrictEqual({
files: expect.any(Array),
iid: '1',
projectPath: 'project-path',
});
expect(variables.files[0].name).toEqual(`design_${Date.now()}.png`);
2020-10-24 23:57:45 +05:30
});
2020-05-24 23:13:21 +05:30
2021-03-08 18:12:59 +05:30
it('does not call upload with invalid paste', () => {
2020-10-24 23:57:45 +05:30
event.clipboardData = {
items: [{ type: 'text/plain' }, { type: 'text' }],
files: [],
};
document.dispatchEvent(event);
2021-03-08 18:12:59 +05:30
expect(mockMutate).not.toHaveBeenCalled();
2020-10-24 23:57:45 +05:30
});
it('removes onPaste listener after mouseleave event', async () => {
findDesignsWrapper().trigger('mouseleave');
document.dispatchEvent(event);
2021-03-08 18:12:59 +05:30
expect(mockMutate).not.toHaveBeenCalled();
2020-10-24 23:57:45 +05:30
});
2020-05-24 23:13:21 +05:30
});
});
2020-06-23 00:09:42 +05:30
describe('when navigating', () => {
2021-03-08 18:12:59 +05:30
it('should trigger a scrollIntoView method if designs route is detected', async () => {
2020-10-24 23:57:45 +05:30
router.replace({
path: '/designs',
});
2021-01-03 14:25:43 +05:30
createComponent({ loading: true });
2020-10-24 23:57:45 +05:30
2021-03-08 18:12:59 +05:30
await nextTick();
expect(scrollIntoViewMock).toHaveBeenCalled();
2020-11-24 15:15:51 +05:30
});
});
describe('with mocked Apollo client', () => {
it('has a design with id 1 as a first one', async () => {
createComponentWithApollo({});
2022-04-04 11:22:00 +05:30
await waitForPromises();
2020-11-24 15:15:51 +05:30
expect(findDesigns()).toHaveLength(3);
2021-03-08 18:12:59 +05:30
expect(findDesigns().at(0).props('id')).toBe('1');
2020-11-24 15:15:51 +05:30
});
it('calls a mutation with correct parameters and reorders designs', async () => {
createComponentWithApollo({});
await moveDesigns(wrapper);
expect(moveDesignHandler).toHaveBeenCalled();
2022-04-04 11:22:00 +05:30
await waitForPromises();
2020-11-24 15:15:51 +05:30
2021-03-08 18:12:59 +05:30
expect(findDesigns().at(0).props('id')).toBe('2');
2020-11-24 15:15:51 +05:30
});
2021-01-03 14:25:43 +05:30
it('prevents reordering when reorderDesigns mutation is in progress', async () => {
createComponentWithApollo({});
await moveDesigns(wrapper);
expect(draggableAttributes().disabled).toBe(true);
2022-04-04 11:22:00 +05:30
await waitForPromises();
2021-01-03 14:25:43 +05:30
expect(draggableAttributes().disabled).toBe(false);
});
2020-11-24 15:15:51 +05:30
it('displays flash if mutation had a recoverable error', async () => {
createComponentWithApollo({
moveHandler: jest.fn().mockResolvedValue(moveDesignMutationResponseWithErrors),
});
await moveDesigns(wrapper);
2022-04-04 11:22:00 +05:30
await waitForPromises();
2020-11-24 15:15:51 +05:30
2021-01-29 00:20:46 +05:30
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
2020-11-24 15:15:51 +05:30
});
it('displays flash if mutation had a non-recoverable error', async () => {
createComponentWithApollo({
moveHandler: jest.fn().mockRejectedValue('Error'),
});
await moveDesigns(wrapper);
2022-04-04 11:22:00 +05:30
await waitForPromises();
2020-11-24 15:15:51 +05:30
2021-01-29 00:20:46 +05:30
expect(createFlash).toHaveBeenCalledWith({
message: 'Something went wrong when reordering designs. Please try again',
});
2020-10-24 23:57:45 +05:30
});
2020-06-23 00:09:42 +05:30
});
2020-05-24 23:13:21 +05:30
});