summaryrefslogtreecommitdiff
path: root/spec/frontend/design_management/pages
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2021-01-20 13:34:23 -0600
committerRobert Speicher <rspeicher@gmail.com>2021-01-20 13:34:23 -0600
commit6438df3a1e0fb944485cebf07976160184697d72 (patch)
tree00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /spec/frontend/design_management/pages
parent42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff)
downloadgitlab-ce-6438df3a1e0fb944485cebf07976160184697d72.tar.gz
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'spec/frontend/design_management/pages')
-rw-r--r--spec/frontend/design_management/pages/index_spec.js284
1 files changed, 132 insertions, 152 deletions
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index 147169dd9aa..7d28d6f6d11 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -1,14 +1,15 @@
+import { nextTick } from 'vue';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo, { ApolloMutation } from 'vue-apollo';
import VueDraggable from 'vuedraggable';
import VueRouter from 'vue-router';
import { GlEmptyState } from '@gitlab/ui';
-import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
import Index from '~/design_management/pages/index.vue';
-import uploadDesignQuery from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
+import uploadDesignMutation from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
import DesignDestroyer from '~/design_management/components/design_destroyer.vue';
import DesignDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
import DeleteButton from '~/design_management/components/delete_button.vue';
@@ -113,7 +114,7 @@ describe('Design management index page', () => {
async function moveDesigns(localWrapper) {
await jest.runOnlyPendingTimers();
- await localWrapper.vm.$nextTick();
+ await nextTick();
localWrapper.find(VueDraggable).vm.$emit('input', reorderedDesigns);
localWrapper.find(VueDraggable).vm.$emit('change', {
@@ -159,7 +160,7 @@ describe('Design management index page', () => {
localVue,
router,
stubs: { DesignDestroyer, ApolloMutation, VueDraggable, ...stubs },
- attachToDocument: true,
+ attachTo: document.body,
provide: {
projectPath: 'project-path',
issueIid: '1',
@@ -200,14 +201,13 @@ describe('Design management index page', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders error', () => {
+ it('renders error', async () => {
createComponent();
wrapper.setData({ error: true });
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.element).toMatchSnapshot();
- });
+ await nextTick();
+ expect(wrapper.element).toMatchSnapshot();
});
it('renders a toolbar with buttons when there are designs', () => {
@@ -254,10 +254,10 @@ describe('Design management index page', () => {
createComponent({ designCollection: { designs: [], copyState: 'READY' } });
});
- it('renders design dropzone', () =>
- wrapper.vm.$nextTick().then(() => {
- expect(findDropzone().exists()).toBe(true);
- }));
+ it('renders design dropzone', async () => {
+ await nextTick();
+ expect(findDropzone().exists()).toBe(true);
+ });
it('has correct classes applied to design dropzone', () => {
expect(dropzoneClasses()).not.toContain('design-list-item');
@@ -268,10 +268,10 @@ describe('Design management index page', () => {
expect(findDropzoneWrapper().classes()).toEqual(['col-12']);
});
- it('does not render a toolbar with buttons', () =>
- wrapper.vm.$nextTick().then(() => {
- expect(findToolbar().exists()).toBe(false);
- }));
+ it('does not render a toolbar with buttons', async () => {
+ await nextTick();
+ expect(findToolbar().exists()).toBe(false);
+ });
});
describe('handling design collection copy state', () => {
@@ -290,7 +290,7 @@ describe('Design management index page', () => {
});
describe('uploading designs', () => {
- it('calls mutation on upload', () => {
+ it('calls mutation on upload', async () => {
createComponent({ stubs: { GlEmptyState } });
const mutationVariables = {
@@ -298,7 +298,7 @@ describe('Design management index page', () => {
context: {
hasUpload: true,
},
- mutation: uploadDesignQuery,
+ mutation: uploadDesignMutation,
variables: {
files: [{ name: 'test' }],
projectPath: 'project-path',
@@ -348,21 +348,16 @@ describe('Design management index page', () => {
},
};
- return wrapper.vm
- .$nextTick()
- .then(() => {
- findDropzone().vm.$emit('change', [{ name: 'test' }]);
- expect(mutate).toHaveBeenCalledWith(mutationVariables);
- expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
- expect(wrapper.vm.isSaving).toBeTruthy();
- })
- .then(() => {
- expect(dropzoneClasses()).toContain('design-list-item');
- expect(dropzoneClasses()).toContain('design-list-item-new');
- });
+ 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');
});
- it('sets isSaving', () => {
+ it('sets isSaving', async () => {
createComponent();
const uploadDesign = wrapper.vm.onUploadDesign([
@@ -373,35 +368,31 @@ describe('Design management index page', () => {
expect(wrapper.vm.isSaving).toBe(true);
- return uploadDesign.then(() => {
- expect(wrapper.vm.isSaving).toBe(false);
- });
+ await uploadDesign;
+ expect(wrapper.vm.isSaving).toBe(false);
});
- it('updates state appropriately after upload complete', () => {
+ it('updates state appropriately after upload complete', async () => {
createComponent({ stubs: { GlEmptyState } });
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.filesToBeSaved).toEqual([]);
- expect(wrapper.vm.isSaving).toBeFalsy();
- expect(wrapper.vm.isLatestVersion).toBe(true);
- });
+ await nextTick();
+
+ expect(wrapper.vm.filesToBeSaved).toEqual([]);
+ expect(wrapper.vm.isSaving).toBeFalsy();
+ expect(wrapper.vm.isLatestVersion).toBe(true);
});
- it('updates state appropriately after upload error', () => {
+ it('updates state appropriately after upload error', async () => {
createComponent({ stubs: { GlEmptyState } });
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
wrapper.vm.onUploadDesignError();
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.filesToBeSaved).toEqual([]);
- expect(wrapper.vm.isSaving).toBeFalsy();
- expect(createFlash).toHaveBeenCalled();
-
- createFlash.mockReset();
- });
+ await nextTick();
+ expect(wrapper.vm.filesToBeSaved).toEqual([]);
+ expect(wrapper.vm.isSaving).toBeFalsy();
+ expect(createFlash).toHaveBeenCalled();
});
it('does not call mutation if createDesign is false', () => {
@@ -415,10 +406,6 @@ describe('Design management index page', () => {
describe('upload count limit', () => {
const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
- afterEach(() => {
- createFlash.mockReset();
- });
-
it('does not warn when the max files are uploaded', () => {
createComponent();
@@ -436,7 +423,7 @@ describe('Design management index page', () => {
});
});
- it('flashes warning if designs are skipped', () => {
+ it('flashes warning if designs are skipped', async () => {
createComponent({
mockMutate: () =>
Promise.resolve({
@@ -450,25 +437,22 @@ describe('Design management index page', () => {
},
]);
- return uploadDesign.then(() => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
- message: 'Upload skipped. test.jpg did not change.',
- types: 'warning',
- });
+ await uploadDesign;
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Upload skipped. test.jpg did not change.',
+ types: 'warning',
});
});
describe('dragging onto an existing design', () => {
+ let mockMutate;
beforeEach(() => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ mockMutate = jest.fn().mockResolvedValue();
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion], mockMutate });
});
- it('calls onUploadDesign with valid upload', () => {
- wrapper.setMethods({
- onUploadDesign: jest.fn(),
- });
-
+ it('uploads designs with valid upload', () => {
const mockUploadPayload = [
{
name: mockDesigns[0].filename,
@@ -478,8 +462,13 @@ describe('Design management index page', () => {
const designDropzone = findFirstDropzoneWithDesign();
designDropzone.vm.$emit('change', mockUploadPayload);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith(mockUploadPayload);
+ const [{ mutation, variables }] = mockMutate.mock.calls[0];
+ expect(mutation).toBe(uploadDesignMutation);
+ expect(variables).toStrictEqual({
+ files: mockUploadPayload,
+ iid: '1',
+ projectPath: 'project-path',
+ });
});
it.each`
@@ -544,57 +533,39 @@ describe('Design management index page', () => {
expect(findToolbar().isVisible()).toBe(true);
});
- it('adds two designs to selected designs when their checkboxes are checked', () => {
- findDesignCheckboxes()
- .at(0)
- .trigger('click');
-
- return wrapper.vm
- .$nextTick()
- .then(() => {
- findDesignCheckboxes()
- .at(1)
- .trigger('click');
-
- return wrapper.vm.$nextTick();
- })
- .then(() => {
- expect(findDeleteButton().exists()).toBe(true);
- expect(findSelectAllButton().text()).toBe('Deselect all');
- findDeleteButton().vm.$emit('deleteSelectedDesigns');
- const [{ variables }] = mutate.mock.calls[0];
- expect(variables.filenames).toStrictEqual([
- mockDesigns[0].filename,
- mockDesigns[1].filename,
- ]);
- });
+ 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');
+ findDeleteButton().vm.$emit('deleteSelectedDesigns');
+ const [{ variables }] = mutate.mock.calls[0];
+ expect(variables.filenames).toStrictEqual([mockDesigns[0].filename, mockDesigns[1].filename]);
});
- it('adds all designs to selected designs when Select All button is clicked', () => {
+ it('adds all designs to selected designs when Select All button is clicked', async () => {
findSelectAllButton().vm.$emit('click');
- return wrapper.vm.$nextTick().then(() => {
- expect(findDeleteButton().props().hasSelectedDesigns).toBe(true);
- expect(findSelectAllButton().text()).toBe('Deselect all');
- expect(wrapper.vm.selectedDesigns).toEqual(mockDesigns.map(design => design.filename));
- });
+ await nextTick();
+ expect(findDeleteButton().props().hasSelectedDesigns).toBe(true);
+ expect(findSelectAllButton().text()).toBe('Deselect all');
+ expect(wrapper.vm.selectedDesigns).toEqual(mockDesigns.map((design) => design.filename));
});
- it('removes all designs from selected designs when at least one design was selected', () => {
- findDesignCheckboxes()
- .at(0)
- .trigger('click');
-
- return wrapper.vm
- .$nextTick()
- .then(() => {
- findSelectAllButton().vm.$emit('click');
- })
- .then(() => {
- expect(findDeleteButton().props().hasSelectedDesigns).toBe(false);
- expect(findSelectAllButton().text()).toBe('Select all');
- expect(wrapper.vm.selectedDesigns).toEqual([]);
- });
+ 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([]);
});
});
@@ -632,12 +603,10 @@ describe('Design management index page', () => {
describe('pasting a design', () => {
let event;
+ let mockMutate;
beforeEach(() => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
-
- wrapper.setMethods({
- onUploadDesign: jest.fn(),
- });
+ mockMutate = jest.fn().mockResolvedValue({});
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion], mockMutate });
event = new Event('paste');
event.clipboardData = {
@@ -646,36 +615,56 @@ describe('Design management index page', () => {
};
});
- it('does not call paste event if designs wrapper is not hovered', () => {
+ it('does not upload designs if designs wrapper is not hovered', () => {
document.dispatchEvent(event);
- expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled();
+ expect(mockMutate).not.toHaveBeenCalled();
});
describe('when designs wrapper is hovered', () => {
+ let realDateNow;
+ const today = () => new Date('2020-12-25');
+ beforeAll(() => {
+ realDateNow = Date.now;
+ global.Date.now = today;
+ });
+
+ afterAll(() => {
+ global.Date.now = realDateNow;
+ });
+
beforeEach(() => {
findDesignsWrapper().trigger('mouseenter');
});
- it('calls onUploadDesign with valid paste', () => {
+ it('uploads design with valid paste', () => {
document.dispatchEvent(event);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith([
- new File([{ name: 'image.png' }], 'test.png'),
- ]);
+ 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], '')));
});
it('renames a design if it has an image.png filename', () => {
+ event.clipboardData.getData = () => 'image.png';
document.dispatchEvent(event);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledTimes(1);
- expect(wrapper.vm.onUploadDesign).toHaveBeenCalledWith([
- new File([{ name: 'image.png' }], `design_${Date.now()}.png`),
- ]);
+ 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`);
});
- it('does not call onUploadDesign with invalid paste', () => {
+ it('does not call upload with invalid paste', () => {
event.clipboardData = {
items: [{ type: 'text/plain' }, { type: 'text' }],
files: [],
@@ -683,28 +672,27 @@ describe('Design management index page', () => {
document.dispatchEvent(event);
- expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled();
+ expect(mockMutate).not.toHaveBeenCalled();
});
it('removes onPaste listener after mouseleave event', async () => {
findDesignsWrapper().trigger('mouseleave');
document.dispatchEvent(event);
- expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled();
+ expect(mockMutate).not.toHaveBeenCalled();
});
});
});
describe('when navigating', () => {
- it('should trigger a scrollIntoView method if designs route is detected', () => {
+ it('should trigger a scrollIntoView method if designs route is detected', async () => {
router.replace({
path: '/designs',
});
createComponent({ loading: true });
- return wrapper.vm.$nextTick().then(() => {
- expect(scrollIntoViewMock).toHaveBeenCalled();
- });
+ await nextTick();
+ expect(scrollIntoViewMock).toHaveBeenCalled();
});
});
@@ -713,14 +701,10 @@ describe('Design management index page', () => {
createComponentWithApollo({});
await jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(findDesigns()).toHaveLength(3);
- expect(
- findDesigns()
- .at(0)
- .props('id'),
- ).toBe('1');
+ expect(findDesigns().at(0).props('id')).toBe('1');
});
it('calls a mutation with correct parameters and reorders designs', async () => {
@@ -730,13 +714,9 @@ describe('Design management index page', () => {
expect(moveDesignHandler).toHaveBeenCalled();
- await wrapper.vm.$nextTick();
+ await nextTick();
- expect(
- findDesigns()
- .at(0)
- .props('id'),
- ).toBe('2');
+ expect(findDesigns().at(0).props('id')).toBe('2');
});
it('prevents reordering when reorderDesigns mutation is in progress', async () => {
@@ -747,8 +727,8 @@ describe('Design management index page', () => {
expect(draggableAttributes().disabled).toBe(true);
await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
- await wrapper.vm.$nextTick(); // kick off the DOM update
- await wrapper.vm.$nextTick(); // kick off the DOM update for finally block
+ await nextTick(); // kick off the DOM update
+ await nextTick(); // kick off the DOM update for finally block
expect(draggableAttributes().disabled).toBe(false);
});
@@ -760,7 +740,7 @@ describe('Design management index page', () => {
await moveDesigns(wrapper);
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
});
@@ -772,9 +752,9 @@ describe('Design management index page', () => {
await moveDesigns(wrapper);
- await wrapper.vm.$nextTick(); // kick off the DOM update
+ await nextTick(); // kick off the DOM update
await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
- await wrapper.vm.$nextTick(); // kick off the DOM update for flash
+ await nextTick(); // kick off the DOM update for flash
expect(createFlash).toHaveBeenCalledWith({
message: 'Something went wrong when reordering designs. Please try again',