diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 04:45:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 04:45:44 +0300 |
commit | 85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch) | |
tree | 9160f299afd8c80c038f08e1545be119f5e3f1e1 /spec/frontend/design_management_legacy/components | |
parent | 15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff) |
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'spec/frontend/design_management_legacy/components')
32 files changed, 0 insertions, 4351 deletions
diff --git a/spec/frontend/design_management_legacy/components/__snapshots__/design_note_pin_spec.js.snap b/spec/frontend/design_management_legacy/components/__snapshots__/design_note_pin_spec.js.snap deleted file mode 100644 index 62a0f675cff..00000000000 --- a/spec/frontend/design_management_legacy/components/__snapshots__/design_note_pin_spec.js.snap +++ /dev/null @@ -1,42 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design note pin component should match the snapshot of note when repositioning 1`] = ` -<button - aria-label="Comment form position" - class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 btn-transparent comment-indicator" - style="left: 10px; top: 10px; cursor: move;" - type="button" -> - <gl-icon-stub - name="image-comment-dark" - size="24" - /> -</button> -`; - -exports[`Design note pin component should match the snapshot of note with index 1`] = ` -<button - aria-label="Comment '1' position" - class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 js-image-badge badge badge-pill" - style="left: 10px; top: 10px;" - type="button" -> - - 1 - -</button> -`; - -exports[`Design note pin component should match the snapshot of note without index 1`] = ` -<button - aria-label="Comment form position" - class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 btn-transparent comment-indicator" - style="left: 10px; top: 10px;" - type="button" -> - <gl-icon-stub - name="image-comment-dark" - size="24" - /> -</button> -`; diff --git a/spec/frontend/design_management_legacy/components/__snapshots__/design_presentation_spec.js.snap b/spec/frontend/design_management_legacy/components/__snapshots__/design_presentation_spec.js.snap deleted file mode 100644 index 189962c5b2e..00000000000 --- a/spec/frontend/design_management_legacy/components/__snapshots__/design_presentation_spec.js.snap +++ /dev/null @@ -1,104 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management design presentation component currentCommentForm is equal to current annotation position when isAnnotating is true 1`] = ` -<div - class="h-100 w-100 p-3 overflow-auto position-relative" -> - <div - class="h-100 w-100 d-flex align-items-center position-relative" - > - <design-image-stub - image="test.jpg" - name="test" - scale="1" - /> - - <design-overlay-stub - currentcommentform="[object Object]" - dimensions="[object Object]" - notes="" - position="[object Object]" - /> - </div> -</div> -`; - -exports[`Design management design presentation component currentCommentForm is null when isAnnotating is false 1`] = ` -<div - class="h-100 w-100 p-3 overflow-auto position-relative" -> - <div - class="h-100 w-100 d-flex align-items-center position-relative" - > - <design-image-stub - image="test.jpg" - name="test" - scale="1" - /> - - <design-overlay-stub - dimensions="[object Object]" - notes="" - position="[object Object]" - /> - </div> -</div> -`; - -exports[`Design management design presentation component currentCommentForm is null when isAnnotating is true but annotation position is falsey 1`] = ` -<div - class="h-100 w-100 p-3 overflow-auto position-relative" -> - <div - class="h-100 w-100 d-flex align-items-center position-relative" - > - <design-image-stub - image="test.jpg" - name="test" - scale="1" - /> - - <design-overlay-stub - dimensions="[object Object]" - notes="" - position="[object Object]" - /> - </div> -</div> -`; - -exports[`Design management design presentation component renders empty state when no image provided 1`] = ` -<div - class="h-100 w-100 p-3 overflow-auto position-relative" -> - <div - class="h-100 w-100 d-flex align-items-center position-relative" - > - <!----> - - <!----> - </div> -</div> -`; - -exports[`Design management design presentation component renders image and overlay when image provided 1`] = ` -<div - class="h-100 w-100 p-3 overflow-auto position-relative" -> - <div - class="h-100 w-100 d-flex align-items-center position-relative" - > - <design-image-stub - image="test.jpg" - name="test" - scale="1" - /> - - <design-overlay-stub - dimensions="[object Object]" - notes="" - position="[object Object]" - /> - </div> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/__snapshots__/design_scaler_spec.js.snap b/spec/frontend/design_management_legacy/components/__snapshots__/design_scaler_spec.js.snap deleted file mode 100644 index cb4575cbd11..00000000000 --- a/spec/frontend/design_management_legacy/components/__snapshots__/design_scaler_spec.js.snap +++ /dev/null @@ -1,115 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management design scaler component minus and reset buttons are disabled when scale === 1 1`] = ` -<div - class="design-scaler btn-group" - role="group" -> - <button - class="btn" - disabled="disabled" - > - <span - class="d-flex-center gl-icon s16" - > - - – - - </span> - </button> - - <button - class="btn" - disabled="disabled" - > - <gl-icon-stub - name="redo" - size="16" - /> - </button> - - <button - class="btn" - > - <gl-icon-stub - name="plus" - size="16" - /> - </button> -</div> -`; - -exports[`Design management design scaler component minus and reset buttons are enabled when scale > 1 1`] = ` -<div - class="design-scaler btn-group" - role="group" -> - <button - class="btn" - > - <span - class="d-flex-center gl-icon s16" - > - - – - - </span> - </button> - - <button - class="btn" - > - <gl-icon-stub - name="redo" - size="16" - /> - </button> - - <button - class="btn" - > - <gl-icon-stub - name="plus" - size="16" - /> - </button> -</div> -`; - -exports[`Design management design scaler component plus button is disabled when scale === 2 1`] = ` -<div - class="design-scaler btn-group" - role="group" -> - <button - class="btn" - > - <span - class="d-flex-center gl-icon s16" - > - - – - - </span> - </button> - - <button - class="btn" - > - <gl-icon-stub - name="redo" - size="16" - /> - </button> - - <button - class="btn" - disabled="disabled" - > - <gl-icon-stub - name="plus" - size="16" - /> - </button> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/__snapshots__/image_spec.js.snap b/spec/frontend/design_management_legacy/components/__snapshots__/image_spec.js.snap deleted file mode 100644 index acaa62b11eb..00000000000 --- a/spec/frontend/design_management_legacy/components/__snapshots__/image_spec.js.snap +++ /dev/null @@ -1,68 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management large image component renders image 1`] = ` -<div - class="m-auto js-design-image" -> - <!----> - - <img - alt="test" - class="mh-100 img-fluid" - src="test.jpg" - /> -</div> -`; - -exports[`Design management large image component renders loading state 1`] = ` -<div - class="m-auto js-design-image" - isloading="true" -> - <!----> - - <img - alt="" - class="mh-100 img-fluid" - src="" - /> -</div> -`; - -exports[`Design management large image component renders media broken icon on error 1`] = ` -<gl-icon-stub - class="text-secondary-100" - name="media-broken" - size="48" -/> -`; - -exports[`Design management large image component sets correct classes and styles if imageStyle is set 1`] = ` -<div - class="m-auto js-design-image" -> - <!----> - - <img - alt="test" - class="mh-100" - src="test.jpg" - style="width: 100px; height: 100px;" - /> -</div> -`; - -exports[`Design management large image component zoom sets image style when zoomed 1`] = ` -<div - class="m-auto js-design-image" -> - <!----> - - <img - alt="test" - class="mh-100" - src="test.jpg" - style="width: 200px; height: 200px;" - /> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/delete_button_spec.js b/spec/frontend/design_management_legacy/components/delete_button_spec.js deleted file mode 100644 index 73b4908d06a..00000000000 --- a/spec/frontend/design_management_legacy/components/delete_button_spec.js +++ /dev/null @@ -1,51 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui'; -import BatchDeleteButton from '~/design_management_legacy/components/delete_button.vue'; - -describe('Batch delete button component', () => { - let wrapper; - - const findButton = () => wrapper.find(GlDeprecatedButton); - const findModal = () => wrapper.find(GlModal); - - function createComponent(isDeleting = false) { - wrapper = shallowMount(BatchDeleteButton, { - propsData: { - isDeleting, - }, - directives: { - GlModalDirective, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders non-disabled button by default', () => { - createComponent(); - - expect(findButton().exists()).toBe(true); - expect(findButton().attributes('disabled')).toBeFalsy(); - }); - - it('renders disabled button when design is deleting', () => { - createComponent(true); - expect(findButton().attributes('disabled')).toBeTruthy(); - }); - - it('emits `deleteSelectedDesigns` event on modal ok click', () => { - createComponent(); - findButton().vm.$emit('click'); - return wrapper.vm - .$nextTick() - .then(() => { - findModal().vm.$emit('ok'); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(wrapper.emitted().deleteSelectedDesigns).toBeTruthy(); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_note_pin_spec.js b/spec/frontend/design_management_legacy/components/design_note_pin_spec.js deleted file mode 100644 index 3077928cf86..00000000000 --- a/spec/frontend/design_management_legacy/components/design_note_pin_spec.js +++ /dev/null @@ -1,49 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import DesignNotePin from '~/design_management_legacy/components/design_note_pin.vue'; - -describe('Design note pin component', () => { - let wrapper; - - function createComponent(propsData = {}) { - wrapper = shallowMount(DesignNotePin, { - propsData: { - position: { - left: '10px', - top: '10px', - }, - ...propsData, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('should match the snapshot of note without index', () => { - createComponent(); - expect(wrapper.element).toMatchSnapshot(); - }); - - it('should match the snapshot of note with index', () => { - createComponent({ label: 1 }); - expect(wrapper.element).toMatchSnapshot(); - }); - - it('should match the snapshot of note when repositioning', () => { - createComponent({ repositioning: true }); - expect(wrapper.element).toMatchSnapshot(); - }); - - describe('pinStyle', () => { - it('sets cursor to `move` when repositioning = true', () => { - createComponent({ repositioning: true }); - expect(wrapper.vm.pinStyle.cursor).toBe('move'); - }); - - it('does not set cursor when repositioning = false', () => { - createComponent(); - expect(wrapper.vm.pinStyle.cursor).toBe(undefined); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_note_spec.js.snap b/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_note_spec.js.snap deleted file mode 100644 index b55bacb6fc5..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_note_spec.js.snap +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design note component should match the snapshot 1`] = ` -<timeline-entry-item-stub - class="design-note note-form" - id="note_123" -> - <user-avatar-link-stub - imgalt="" - imgcssclasses="" - imgsize="40" - imgsrc="" - linkhref="" - tooltipplacement="top" - tooltiptext="" - username="" - /> - - <div - class="d-flex justify-content-between" - > - <div> - <a - class="js-user-link" - data-user-id="author-id" - > - <span - class="note-header-author-name bold" - > - - </span> - - <!----> - - <span - class="note-headline-light" - > - @ - </span> - </a> - - <span - class="note-headline-light note-headline-meta" - > - <span - class="system-note-message" - /> - - <!----> - </span> - </div> - - <div - class="gl-display-flex" - > - - <!----> - </div> - </div> - - <div - class="note-text js-note-text md" - data-qa-selector="note_content" - /> - -</timeline-entry-item-stub> -`; diff --git a/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_reply_form_spec.js.snap b/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_reply_form_spec.js.snap deleted file mode 100644 index e01c79e3520..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/__snapshots__/design_reply_form_spec.js.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design reply form component renders button text as "Comment" when creating a comment 1`] = ` -"<button data-track-event=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn btn-success btn-md disabled\\"> - <!----> - Comment -</button>" -`; - -exports[`Design reply form component renders button text as "Save comment" when creating a comment 1`] = ` -"<button data-track-event=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn btn-success btn-md disabled\\"> - <!----> - Save comment -</button>" -`; diff --git a/spec/frontend/design_management_legacy/components/design_notes/design_discussion_spec.js b/spec/frontend/design_management_legacy/components/design_notes/design_discussion_spec.js deleted file mode 100644 index d20be97f470..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/design_discussion_spec.js +++ /dev/null @@ -1,318 +0,0 @@ -import { mount } from '@vue/test-utils'; -import { GlLoadingIcon } from '@gitlab/ui'; -import notes from '../../mock_data/notes'; -import DesignDiscussion from '~/design_management_legacy/components/design_notes/design_discussion.vue'; -import DesignNote from '~/design_management_legacy/components/design_notes/design_note.vue'; -import DesignReplyForm from '~/design_management_legacy/components/design_notes/design_reply_form.vue'; -import createNoteMutation from '~/design_management_legacy/graphql/mutations/create_note.mutation.graphql'; -import toggleResolveDiscussionMutation from '~/design_management_legacy/graphql/mutations/toggle_resolve_discussion.mutation.graphql'; -import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue'; -import ToggleRepliesWidget from '~/design_management_legacy/components/design_notes/toggle_replies_widget.vue'; - -const discussion = { - id: '0', - resolved: false, - resolvable: true, - notes, -}; - -describe('Design discussions component', () => { - let wrapper; - - const findDesignNotes = () => wrapper.findAll(DesignNote); - const findReplyPlaceholder = () => wrapper.find(ReplyPlaceholder); - const findReplyForm = () => wrapper.find(DesignReplyForm); - const findRepliesWidget = () => wrapper.find(ToggleRepliesWidget); - const findResolveButton = () => wrapper.find('[data-testid="resolve-button"]'); - const findResolveIcon = () => wrapper.find('[data-testid="resolve-icon"]'); - const findResolvedMessage = () => wrapper.find('[data-testid="resolved-message"]'); - const findResolveLoadingIcon = () => wrapper.find(GlLoadingIcon); - const findResolveCheckbox = () => wrapper.find('[data-testid="resolve-checkbox"]'); - - const mutationVariables = { - mutation: createNoteMutation, - update: expect.anything(), - variables: { - input: { - noteableId: 'noteable-id', - body: 'test', - discussionId: '0', - }, - }, - }; - const mutate = jest.fn(() => Promise.resolve()); - const $apollo = { - mutate, - }; - - function createComponent(props = {}, data = {}) { - wrapper = mount(DesignDiscussion, { - propsData: { - resolvedDiscussionsExpanded: true, - discussion, - noteableId: 'noteable-id', - designId: 'design-id', - discussionIndex: 1, - discussionWithOpenForm: '', - ...props, - }, - data() { - return { - ...data, - }; - }, - mocks: { - $apollo, - $route: { - hash: '#note_1', - }, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when discussion is not resolvable', () => { - beforeEach(() => { - createComponent({ - discussion: { - ...discussion, - resolvable: false, - }, - }); - }); - - it('does not render an icon to resolve a thread', () => { - expect(findResolveIcon().exists()).toBe(false); - }); - - it('does not render a checkbox in reply form', () => { - findReplyPlaceholder().vm.$emit('onMouseDown'); - - return wrapper.vm.$nextTick().then(() => { - expect(findResolveCheckbox().exists()).toBe(false); - }); - }); - }); - - describe('when discussion is unresolved', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders correct amount of discussion notes', () => { - expect(findDesignNotes()).toHaveLength(2); - expect(findDesignNotes().wrappers.every(w => w.isVisible())).toBe(true); - }); - - it('renders reply placeholder', () => { - expect(findReplyPlaceholder().isVisible()).toBe(true); - }); - - it('does not render toggle replies widget', () => { - expect(findRepliesWidget().exists()).toBe(false); - }); - - it('renders a correct icon to resolve a thread', () => { - expect(findResolveIcon().props('name')).toBe('check-circle'); - }); - - it('renders a checkbox with Resolve thread text in reply form', () => { - findReplyPlaceholder().vm.$emit('onClick'); - wrapper.setProps({ discussionWithOpenForm: discussion.id }); - - return wrapper.vm.$nextTick().then(() => { - expect(findResolveCheckbox().text()).toBe('Resolve thread'); - }); - }); - - it('does not render resolved message', () => { - expect(findResolvedMessage().exists()).toBe(false); - }); - }); - - describe('when discussion is resolved', () => { - beforeEach(() => { - createComponent({ - discussion: { - ...discussion, - resolved: true, - resolvedBy: notes[0].author, - resolvedAt: '2020-05-08T07:10:45Z', - }, - }); - }); - - it('shows only the first note', () => { - expect( - findDesignNotes() - .at(0) - .isVisible(), - ).toBe(true); - expect( - findDesignNotes() - .at(1) - .isVisible(), - ).toBe(false); - }); - - it('renders resolved message', () => { - expect(findResolvedMessage().exists()).toBe(true); - }); - - it('does not show renders reply placeholder', () => { - expect(findReplyPlaceholder().isVisible()).toBe(false); - }); - - it('renders toggle replies widget with correct props', () => { - expect(findRepliesWidget().exists()).toBe(true); - expect(findRepliesWidget().props()).toEqual({ - collapsed: true, - replies: notes.slice(1), - }); - }); - - it('renders a correct icon to resolve a thread', () => { - expect(findResolveIcon().props('name')).toBe('check-circle-filled'); - }); - - describe('when replies are expanded', () => { - beforeEach(() => { - findRepliesWidget().vm.$emit('toggle'); - return wrapper.vm.$nextTick(); - }); - - it('renders replies widget with collapsed prop equal to false', () => { - expect(findRepliesWidget().props('collapsed')).toBe(false); - }); - - it('renders the second note', () => { - expect( - findDesignNotes() - .at(1) - .isVisible(), - ).toBe(true); - }); - - it('renders a reply placeholder', () => { - expect(findReplyPlaceholder().isVisible()).toBe(true); - }); - - it('renders a checkbox with Unresolve thread text in reply form', () => { - findReplyPlaceholder().vm.$emit('onClick'); - wrapper.setProps({ discussionWithOpenForm: discussion.id }); - - return wrapper.vm.$nextTick().then(() => { - expect(findResolveCheckbox().text()).toBe('Unresolve thread'); - }); - }); - }); - }); - - it('hides reply placeholder and opens form on placeholder click', () => { - createComponent(); - findReplyPlaceholder().vm.$emit('onClick'); - wrapper.setProps({ discussionWithOpenForm: discussion.id }); - - return wrapper.vm.$nextTick().then(() => { - expect(findReplyPlaceholder().exists()).toBe(false); - expect(findReplyForm().exists()).toBe(true); - }); - }); - - it('calls mutation on submitting form and closes the form', () => { - createComponent( - { discussionWithOpenForm: discussion.id }, - { discussionComment: 'test', isFormRendered: true }, - ); - - findReplyForm().vm.$emit('submitForm'); - expect(mutate).toHaveBeenCalledWith(mutationVariables); - - return mutate() - .then(() => { - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(findReplyForm().exists()).toBe(false); - }); - }); - - it('clears the discussion comment on closing comment form', () => { - createComponent( - { discussionWithOpenForm: discussion.id }, - { discussionComment: 'test', isFormRendered: true }, - ); - - return wrapper.vm - .$nextTick() - .then(() => { - findReplyForm().vm.$emit('cancelForm'); - - expect(wrapper.vm.discussionComment).toBe(''); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(findReplyForm().exists()).toBe(false); - }); - }); - - it('applies correct class to design notes when discussion is highlighted', () => { - createComponent( - {}, - { - activeDiscussion: { - id: notes[0].id, - source: 'pin', - }, - }, - ); - - expect(wrapper.findAll(DesignNote).wrappers.every(note => note.classes('gl-bg-blue-50'))).toBe( - true, - ); - }); - - it('calls toggleResolveDiscussion mutation on resolve thread button click', () => { - createComponent(); - findResolveButton().trigger('click'); - expect(mutate).toHaveBeenCalledWith({ - mutation: toggleResolveDiscussionMutation, - variables: { - id: discussion.id, - resolve: true, - }, - }); - return wrapper.vm.$nextTick(() => { - expect(findResolveLoadingIcon().exists()).toBe(true); - }); - }); - - it('calls toggleResolveDiscussion mutation after adding a note if checkbox was checked', () => { - createComponent( - { discussionWithOpenForm: discussion.id }, - { discussionComment: 'test', isFormRendered: true }, - ); - findResolveButton().trigger('click'); - findReplyForm().vm.$emit('submitForm'); - - return mutate().then(() => { - expect(mutate).toHaveBeenCalledWith({ - mutation: toggleResolveDiscussionMutation, - variables: { - id: discussion.id, - resolve: true, - }, - }); - }); - }); - - it('emits openForm event on opening the form', () => { - createComponent(); - findReplyPlaceholder().vm.$emit('onClick'); - - expect(wrapper.emitted('openForm')).toBeTruthy(); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_notes/design_note_spec.js b/spec/frontend/design_management_legacy/components/design_notes/design_note_spec.js deleted file mode 100644 index aa187cd1388..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/design_note_spec.js +++ /dev/null @@ -1,170 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { ApolloMutation } from 'vue-apollo'; -import DesignNote from '~/design_management_legacy/components/design_notes/design_note.vue'; -import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; -import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import DesignReplyForm from '~/design_management_legacy/components/design_notes/design_reply_form.vue'; - -const scrollIntoViewMock = jest.fn(); -const note = { - id: 'gid://gitlab/DiffNote/123', - author: { - id: 'author-id', - }, - body: 'test', - userPermissions: { - adminNote: false, - }, -}; -HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; - -const $route = { - hash: '#note_123', -}; - -const mutate = jest.fn().mockResolvedValue({ data: { updateNote: {} } }); - -describe('Design note component', () => { - let wrapper; - - const findUserAvatar = () => wrapper.find(UserAvatarLink); - const findUserLink = () => wrapper.find('.js-user-link'); - const findReplyForm = () => wrapper.find(DesignReplyForm); - const findEditButton = () => wrapper.find('.js-note-edit'); - const findNoteContent = () => wrapper.find('.js-note-text'); - - function createComponent(props = {}, data = { isEditing: false }) { - wrapper = shallowMount(DesignNote, { - propsData: { - note: {}, - ...props, - }, - data() { - return { - ...data, - }; - }, - mocks: { - $route, - $apollo: { - mutate, - }, - }, - stubs: { - ApolloMutation, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('should match the snapshot', () => { - createComponent({ - note, - }); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('should render an author', () => { - createComponent({ - note, - }); - - expect(findUserAvatar().exists()).toBe(true); - expect(findUserLink().exists()).toBe(true); - }); - - it('should render a time ago tooltip if note has createdAt property', () => { - createComponent({ - note: { - ...note, - createdAt: '2019-07-26T15:02:20Z', - }, - }); - - expect(wrapper.find(TimeAgoTooltip).exists()).toBe(true); - }); - - it('should trigger a scrollIntoView method', () => { - createComponent({ - note, - }); - - expect(scrollIntoViewMock).toHaveBeenCalled(); - }); - - it('should not render edit icon when user does not have a permission', () => { - createComponent({ - note, - }); - - expect(findEditButton().exists()).toBe(false); - }); - - describe('when user has a permission to edit note', () => { - it('should open an edit form on edit button click', () => { - createComponent({ - note: { - ...note, - userPermissions: { - adminNote: true, - }, - }, - }); - - findEditButton().trigger('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(findReplyForm().exists()).toBe(true); - expect(findNoteContent().exists()).toBe(false); - }); - }); - - describe('when edit form is rendered', () => { - beforeEach(() => { - createComponent( - { - note: { - ...note, - userPermissions: { - adminNote: true, - }, - }, - }, - { isEditing: true }, - ); - }); - - it('should not render note content and should render reply form', () => { - expect(findNoteContent().exists()).toBe(false); - expect(findReplyForm().exists()).toBe(true); - }); - - it('hides the form on hideForm event', () => { - findReplyForm().vm.$emit('cancelForm'); - - return wrapper.vm.$nextTick().then(() => { - expect(findReplyForm().exists()).toBe(false); - expect(findNoteContent().exists()).toBe(true); - }); - }); - - it('calls a mutation on submitForm event and hides a form', () => { - findReplyForm().vm.$emit('submitForm'); - expect(mutate).toHaveBeenCalled(); - - return mutate() - .then(() => { - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(findReplyForm().exists()).toBe(false); - expect(findNoteContent().exists()).toBe(true); - }); - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_notes/design_reply_form_spec.js b/spec/frontend/design_management_legacy/components/design_notes/design_reply_form_spec.js deleted file mode 100644 index 088a71b64af..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/design_reply_form_spec.js +++ /dev/null @@ -1,184 +0,0 @@ -import { mount } from '@vue/test-utils'; -import DesignReplyForm from '~/design_management_legacy/components/design_notes/design_reply_form.vue'; - -const showModal = jest.fn(); - -const GlModal = { - template: '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-ok"></slot></div>', - methods: { - show: showModal, - }, -}; - -describe('Design reply form component', () => { - let wrapper; - - const findTextarea = () => wrapper.find('textarea'); - const findSubmitButton = () => wrapper.find({ ref: 'submitButton' }); - const findCancelButton = () => wrapper.find({ ref: 'cancelButton' }); - const findModal = () => wrapper.find({ ref: 'cancelCommentModal' }); - - function createComponent(props = {}, mountOptions = {}) { - wrapper = mount(DesignReplyForm, { - propsData: { - value: '', - isSaving: false, - ...props, - }, - stubs: { GlModal }, - ...mountOptions, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('textarea has focus after component mount', () => { - // We need to attach to document, so that `document.activeElement` is properly set in jsdom - createComponent({}, { attachToDocument: true }); - - expect(findTextarea().element).toEqual(document.activeElement); - }); - - it('renders button text as "Comment" when creating a comment', () => { - createComponent(); - - expect(findSubmitButton().html()).toMatchSnapshot(); - }); - - it('renders button text as "Save comment" when creating a comment', () => { - createComponent({ isNewComment: false }); - - expect(findSubmitButton().html()).toMatchSnapshot(); - }); - - describe('when form has no text', () => { - beforeEach(() => { - createComponent({ - value: '', - }); - }); - - it('submit button is disabled', () => { - expect(findSubmitButton().attributes().disabled).toBeTruthy(); - }); - - it('does not emit submitForm event on textarea ctrl+enter keydown', () => { - findTextarea().trigger('keydown.enter', { - ctrlKey: true, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('submitForm')).toBeFalsy(); - }); - }); - - it('does not emit submitForm event on textarea meta+enter keydown', () => { - findTextarea().trigger('keydown.enter', { - metaKey: true, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('submitForm')).toBeFalsy(); - }); - }); - - it('emits cancelForm event on pressing escape button on textarea', () => { - findTextarea().trigger('keyup.esc'); - - expect(wrapper.emitted('cancelForm')).toBeTruthy(); - }); - - it('emits cancelForm event on clicking Cancel button', () => { - findCancelButton().vm.$emit('click'); - - expect(wrapper.emitted('cancelForm')).toHaveLength(1); - }); - }); - - describe('when form has text', () => { - beforeEach(() => { - createComponent({ - value: 'test', - }); - }); - - it('submit button is enabled', () => { - expect(findSubmitButton().attributes().disabled).toBeFalsy(); - }); - - it('emits submitForm event on Comment button click', () => { - findSubmitButton().vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('submitForm')).toBeTruthy(); - }); - }); - - it('emits submitForm event on textarea ctrl+enter keydown', () => { - findTextarea().trigger('keydown.enter', { - ctrlKey: true, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('submitForm')).toBeTruthy(); - }); - }); - - it('emits submitForm event on textarea meta+enter keydown', () => { - findTextarea().trigger('keydown.enter', { - metaKey: true, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('submitForm')).toBeTruthy(); - }); - }); - - it('emits input event on changing textarea content', () => { - findTextarea().setValue('test2'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('input')).toBeTruthy(); - }); - }); - - it('emits cancelForm event on Escape key if text was not changed', () => { - findTextarea().trigger('keyup.esc'); - - expect(wrapper.emitted('cancelForm')).toBeTruthy(); - }); - - it('opens confirmation modal on Escape key when text has changed', () => { - wrapper.setProps({ value: 'test2' }); - - return wrapper.vm.$nextTick().then(() => { - findTextarea().trigger('keyup.esc'); - expect(showModal).toHaveBeenCalled(); - }); - }); - - it('emits cancelForm event on Cancel button click if text was not changed', () => { - findCancelButton().trigger('click'); - - expect(wrapper.emitted('cancelForm')).toBeTruthy(); - }); - - it('opens confirmation modal on Cancel button click when text has changed', () => { - wrapper.setProps({ value: 'test2' }); - - return wrapper.vm.$nextTick().then(() => { - findCancelButton().trigger('click'); - expect(showModal).toHaveBeenCalled(); - }); - }); - - it('emits cancelForm event on modal Ok button click', () => { - findTextarea().trigger('keyup.esc'); - findModal().vm.$emit('ok'); - - expect(wrapper.emitted('cancelForm')).toBeTruthy(); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_notes/toggle_replies_widget_spec.js b/spec/frontend/design_management_legacy/components/design_notes/toggle_replies_widget_spec.js deleted file mode 100644 index acc7cbbca52..00000000000 --- a/spec/frontend/design_management_legacy/components/design_notes/toggle_replies_widget_spec.js +++ /dev/null @@ -1,98 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlIcon, GlButton, GlLink } from '@gitlab/ui'; -import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import ToggleRepliesWidget from '~/design_management_legacy/components/design_notes/toggle_replies_widget.vue'; -import notes from '../../mock_data/notes'; - -describe('Toggle replies widget component', () => { - let wrapper; - - const findToggleWrapper = () => wrapper.find('[data-testid="toggle-comments-wrapper"]'); - const findIcon = () => wrapper.find(GlIcon); - const findButton = () => wrapper.find(GlButton); - const findAuthorLink = () => wrapper.find(GlLink); - const findTimeAgo = () => wrapper.find(TimeAgoTooltip); - - function createComponent(props = {}) { - wrapper = shallowMount(ToggleRepliesWidget, { - propsData: { - collapsed: true, - replies: notes, - ...props, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when replies are collapsed', () => { - beforeEach(() => { - createComponent(); - }); - - it('should not have expanded class', () => { - expect(findToggleWrapper().classes()).not.toContain('expanded'); - }); - - it('should render chevron-right icon', () => { - expect(findIcon().props('name')).toBe('chevron-right'); - }); - - it('should have replies length on button', () => { - expect(findButton().text()).toBe('2 replies'); - }); - - it('should render a link to the last reply author', () => { - expect(findAuthorLink().exists()).toBe(true); - expect(findAuthorLink().text()).toBe(notes[1].author.name); - expect(findAuthorLink().attributes('href')).toBe(notes[1].author.webUrl); - }); - - it('should render correct time ago tooltip', () => { - expect(findTimeAgo().exists()).toBe(true); - expect(findTimeAgo().props('time')).toBe(notes[1].createdAt); - }); - }); - - describe('when replies are expanded', () => { - beforeEach(() => { - createComponent({ collapsed: false }); - }); - - it('should have expanded class', () => { - expect(findToggleWrapper().classes()).toContain('expanded'); - }); - - it('should render chevron-down icon', () => { - expect(findIcon().props('name')).toBe('chevron-down'); - }); - - it('should have Collapse replies text on button', () => { - expect(findButton().text()).toBe('Collapse replies'); - }); - - it('should not have a link to the last reply author', () => { - expect(findAuthorLink().exists()).toBe(false); - }); - - it('should not render time ago tooltip', () => { - expect(findTimeAgo().exists()).toBe(false); - }); - }); - - it('should emit toggle event on icon click', () => { - createComponent(); - findIcon().vm.$emit('click', new MouseEvent('click')); - - expect(wrapper.emitted('toggle')).toHaveLength(1); - }); - - it('should emit toggle event on button click', () => { - createComponent(); - findButton().vm.$emit('click', new MouseEvent('click')); - - expect(wrapper.emitted('toggle')).toHaveLength(1); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_overlay_spec.js b/spec/frontend/design_management_legacy/components/design_overlay_spec.js deleted file mode 100644 index c014f3479f4..00000000000 --- a/spec/frontend/design_management_legacy/components/design_overlay_spec.js +++ /dev/null @@ -1,410 +0,0 @@ -import { mount } from '@vue/test-utils'; -import DesignOverlay from '~/design_management_legacy/components/design_overlay.vue'; -import updateActiveDiscussion from '~/design_management_legacy/graphql/mutations/update_active_discussion.mutation.graphql'; -import notes from '../mock_data/notes'; -import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '~/design_management_legacy/constants'; - -const mutate = jest.fn(() => Promise.resolve()); - -describe('Design overlay component', () => { - let wrapper; - - const mockDimensions = { width: 100, height: 100 }; - - const findOverlay = () => wrapper.find('.image-diff-overlay'); - const findAllNotes = () => wrapper.findAll('.js-image-badge'); - const findCommentBadge = () => wrapper.find('.comment-indicator'); - const findFirstBadge = () => findAllNotes().at(0); - const findSecondBadge = () => findAllNotes().at(1); - - const clickAndDragBadge = (elem, fromPoint, toPoint) => { - elem.trigger('mousedown', { clientX: fromPoint.x, clientY: fromPoint.y }); - return wrapper.vm.$nextTick().then(() => { - elem.trigger('mousemove', { clientX: toPoint.x, clientY: toPoint.y }); - return wrapper.vm.$nextTick(); - }); - }; - - function createComponent(props = {}, data = {}) { - wrapper = mount(DesignOverlay, { - propsData: { - dimensions: mockDimensions, - position: { - top: '0', - left: '0', - }, - resolvedDiscussionsExpanded: false, - ...props, - }, - data() { - return { - activeDiscussion: { - id: null, - source: null, - }, - ...data, - }; - }, - mocks: { - $apollo: { - mutate, - }, - }, - }); - } - - it('should have correct inline style', () => { - createComponent(); - - expect(wrapper.find('.image-diff-overlay').attributes().style).toBe( - 'width: 100px; height: 100px; top: 0px; left: 0px;', - ); - }); - - it('should emit `openCommentForm` when clicking on overlay', () => { - createComponent(); - const newCoordinates = { - x: 10, - y: 10, - }; - - wrapper - .find('.image-diff-overlay-add-comment') - .trigger('mouseup', { offsetX: newCoordinates.x, offsetY: newCoordinates.y }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('openCommentForm')).toEqual([ - [{ x: newCoordinates.x, y: newCoordinates.y }], - ]); - }); - }); - - describe('with notes', () => { - it('should render only the first note', () => { - createComponent({ - notes, - }); - expect(findAllNotes()).toHaveLength(1); - }); - - describe('with resolved discussions toggle expanded', () => { - beforeEach(() => { - createComponent({ - notes, - resolvedDiscussionsExpanded: true, - }); - }); - - it('should render all notes', () => { - expect(findAllNotes()).toHaveLength(notes.length); - }); - - it('should have set the correct position for each note badge', () => { - expect(findFirstBadge().attributes().style).toBe('left: 10px; top: 15px;'); - expect(findSecondBadge().attributes().style).toBe('left: 50px; top: 50px;'); - }); - - it('should apply resolved class to the resolved note pin', () => { - expect(findSecondBadge().classes()).toContain('resolved'); - }); - - it('when there is an active discussion, should apply inactive class to all pins besides the active one', () => { - wrapper.setData({ - activeDiscussion: { - id: notes[0].id, - source: 'discussion', - }, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(findSecondBadge().classes()).toContain('inactive'); - }); - }); - }); - - it('should recalculate badges positions on window resize', () => { - createComponent({ - notes, - dimensions: { - width: 400, - height: 400, - }, - }); - - expect(findFirstBadge().attributes().style).toBe('left: 40px; top: 60px;'); - - wrapper.setProps({ - dimensions: { - width: 200, - height: 200, - }, - }); - - return wrapper.vm.$nextTick().then(() => { - expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 30px;'); - }); - }); - - it('should call an update active discussion mutation when clicking a note without moving it', () => { - const note = notes[0]; - const { position } = note; - const mutationVariables = { - mutation: updateActiveDiscussion, - variables: { - id: note.id, - source: ACTIVE_DISCUSSION_SOURCE_TYPES.pin, - }, - }; - - findFirstBadge().trigger('mousedown', { clientX: position.x, clientY: position.y }); - - return wrapper.vm.$nextTick().then(() => { - findFirstBadge().trigger('mouseup', { clientX: position.x, clientY: position.y }); - expect(mutate).toHaveBeenCalledWith(mutationVariables); - }); - }); - }); - - describe('when moving notes', () => { - it('should update badge style when note is being moved', () => { - createComponent({ - notes, - }); - - const { position } = notes[0]; - - return clickAndDragBadge( - findFirstBadge(), - { x: position.x, y: position.y }, - { x: 20, y: 20 }, - ).then(() => { - expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 20px; cursor: move;'); - }); - }); - - it('should emit `moveNote` event when note-moving action ends', () => { - createComponent({ notes }); - const note = notes[0]; - const { position } = note; - const newCoordinates = { x: 20, y: 20 }; - - wrapper.setData({ - movingNoteNewPosition: { - ...position, - ...newCoordinates, - }, - movingNoteStartPosition: { - noteId: notes[0].id, - discussionId: notes[0].discussion.id, - ...position, - }, - }); - - const badge = findFirstBadge(); - return clickAndDragBadge(badge, { x: position.x, y: position.y }, newCoordinates) - .then(() => { - badge.trigger('mouseup'); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(wrapper.emitted('moveNote')).toEqual([ - [ - { - noteId: notes[0].id, - discussionId: notes[0].discussion.id, - coordinates: newCoordinates, - }, - ], - ]); - }); - }); - - describe('without [adminNote] permission', () => { - const mockNoteNotAuthorised = { - ...notes[0], - userPermissions: { - adminNote: false, - }, - }; - - const mockNoteCoordinates = { - x: mockNoteNotAuthorised.position.x, - y: mockNoteNotAuthorised.position.y, - }; - - it('should be unable to move a note', () => { - createComponent({ - dimensions: mockDimensions, - notes: [mockNoteNotAuthorised], - }); - - const badge = findAllNotes().at(0); - return clickAndDragBadge(badge, { ...mockNoteCoordinates }, { x: 20, y: 20 }).then(() => { - // note position should not change after a click-and-drag attempt - expect(findFirstBadge().attributes().style).toContain( - `left: ${mockNoteCoordinates.x}px; top: ${mockNoteCoordinates.y}px;`, - ); - }); - }); - }); - }); - - describe('with a new form', () => { - it('should render a new comment badge', () => { - createComponent({ - currentCommentForm: { - ...notes[0].position, - }, - }); - - expect(findCommentBadge().exists()).toBe(true); - expect(findCommentBadge().attributes().style).toBe('left: 10px; top: 15px;'); - }); - - describe('when moving the comment badge', () => { - it('should update badge style to reflect new position', () => { - const { position } = notes[0]; - - createComponent({ - currentCommentForm: { - ...position, - }, - }); - - return clickAndDragBadge( - findCommentBadge(), - { x: position.x, y: position.y }, - { x: 20, y: 20 }, - ).then(() => { - expect(findCommentBadge().attributes().style).toBe( - 'left: 20px; top: 20px; cursor: move;', - ); - }); - }); - - it('should update badge style when note-moving action ends', () => { - const { position } = notes[0]; - createComponent({ - currentCommentForm: { - ...position, - }, - }); - - const commentBadge = findCommentBadge(); - const toPoint = { x: 20, y: 20 }; - - return clickAndDragBadge(commentBadge, { x: position.x, y: position.y }, toPoint) - .then(() => { - commentBadge.trigger('mouseup'); - // simulates the currentCommentForm being updated in index.vue component, and - // propagated back down to this prop - wrapper.setProps({ - currentCommentForm: { height: position.height, width: position.width, ...toPoint }, - }); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(commentBadge.attributes().style).toBe('left: 20px; top: 20px;'); - }); - }); - - it.each` - element | getElementFunc | event - ${'overlay'} | ${findOverlay} | ${'mouseleave'} - ${'comment badge'} | ${findCommentBadge} | ${'mouseup'} - `( - 'should emit `openCommentForm` event when $event fired on $element element', - ({ getElementFunc, event }) => { - createComponent({ - notes, - currentCommentForm: { - ...notes[0].position, - }, - }); - - const newCoordinates = { x: 20, y: 20 }; - wrapper.setData({ - movingNoteStartPosition: { - ...notes[0].position, - }, - movingNoteNewPosition: { - ...notes[0].position, - ...newCoordinates, - }, - }); - - getElementFunc().trigger(event); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('openCommentForm')).toEqual([[newCoordinates]]); - }); - }, - ); - }); - }); - - describe('getMovingNotePositionDelta', () => { - it('should calculate delta correctly from state', () => { - createComponent(); - - wrapper.setData({ - movingNoteStartPosition: { - clientX: 10, - clientY: 20, - }, - }); - - const mockMouseEvent = { - clientX: 30, - clientY: 10, - }; - - expect(wrapper.vm.getMovingNotePositionDelta(mockMouseEvent)).toEqual({ - deltaX: 20, - deltaY: -10, - }); - }); - }); - - describe('isPositionInOverlay', () => { - createComponent({ dimensions: mockDimensions }); - - it.each` - test | coordinates | expectedResult - ${'within overlay bounds'} | ${{ x: 50, y: 50 }} | ${true} - ${'outside overlay bounds'} | ${{ x: 101, y: 101 }} | ${false} - `('returns [$expectedResult] when position is $test', ({ coordinates, expectedResult }) => { - const position = { ...mockDimensions, ...coordinates }; - - expect(wrapper.vm.isPositionInOverlay(position)).toBe(expectedResult); - }); - }); - - describe('getNoteRelativePosition', () => { - it('calculates position correctly', () => { - createComponent({ dimensions: mockDimensions }); - const position = { x: 50, y: 50, width: 200, height: 200 }; - - expect(wrapper.vm.getNoteRelativePosition(position)).toEqual({ left: 25, top: 25 }); - }); - }); - - describe('canMoveNote', () => { - it.each` - adminNotePermission | canMoveNoteResult - ${true} | ${true} - ${false} | ${false} - ${undefined} | ${false} - `( - 'returns [$canMoveNoteResult] when [adminNote permission] is [$adminNotePermission]', - ({ adminNotePermission, canMoveNoteResult }) => { - createComponent(); - - const note = { - userPermissions: { - adminNote: adminNotePermission, - }, - }; - expect(wrapper.vm.canMoveNote(note)).toBe(canMoveNoteResult); - }, - ); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_presentation_spec.js b/spec/frontend/design_management_legacy/components/design_presentation_spec.js deleted file mode 100644 index ceff86b0549..00000000000 --- a/spec/frontend/design_management_legacy/components/design_presentation_spec.js +++ /dev/null @@ -1,553 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import DesignPresentation from '~/design_management_legacy/components/design_presentation.vue'; -import DesignOverlay from '~/design_management_legacy/components/design_overlay.vue'; - -const mockOverlayData = { - overlayDimensions: { - width: 100, - height: 100, - }, - overlayPosition: { - top: '0', - left: '0', - }, -}; - -describe('Design management design presentation component', () => { - let wrapper; - - function createComponent( - { - image, - imageName, - discussions = [], - isAnnotating = false, - resolvedDiscussionsExpanded = false, - } = {}, - data = {}, - stubs = {}, - ) { - wrapper = shallowMount(DesignPresentation, { - propsData: { - image, - imageName, - discussions, - isAnnotating, - resolvedDiscussionsExpanded, - }, - stubs, - }); - - wrapper.setData(data); - wrapper.element.scrollTo = jest.fn(); - } - - const findOverlayCommentButton = () => wrapper.find('.image-diff-overlay-add-comment'); - - /** - * Spy on $refs and mock given values - * @param {Object} viewportDimensions {width, height} - * @param {Object} childDimensions {width, height} - * @param {Float} scrollTopPerc 0 < x < 1 - * @param {Float} scrollLeftPerc 0 < x < 1 - */ - function mockRefDimensions( - ref, - viewportDimensions, - childDimensions, - scrollTopPerc, - scrollLeftPerc, - ) { - jest.spyOn(ref, 'scrollWidth', 'get').mockReturnValue(childDimensions.width); - jest.spyOn(ref, 'scrollHeight', 'get').mockReturnValue(childDimensions.height); - jest.spyOn(ref, 'offsetWidth', 'get').mockReturnValue(viewportDimensions.width); - jest.spyOn(ref, 'offsetHeight', 'get').mockReturnValue(viewportDimensions.height); - jest - .spyOn(ref, 'scrollLeft', 'get') - .mockReturnValue((childDimensions.width - viewportDimensions.width) * scrollLeftPerc); - jest - .spyOn(ref, 'scrollTop', 'get') - .mockReturnValue((childDimensions.height - viewportDimensions.height) * scrollTopPerc); - } - - function clickDragExplore(startCoords, endCoords, { useTouchEvents, mouseup } = {}) { - const event = useTouchEvents - ? { - mousedown: 'touchstart', - mousemove: 'touchmove', - mouseup: 'touchend', - } - : { - mousedown: 'mousedown', - mousemove: 'mousemove', - mouseup: 'mouseup', - }; - - const addCommentOverlay = findOverlayCommentButton(); - - // triggering mouse events on this element best simulates - // reality, as it is the lowest-level node that needs to - // respond to mouse events - addCommentOverlay.trigger(event.mousedown, { - clientX: startCoords.clientX, - clientY: startCoords.clientY, - }); - return wrapper.vm - .$nextTick() - .then(() => { - addCommentOverlay.trigger(event.mousemove, { - clientX: endCoords.clientX, - clientY: endCoords.clientY, - }); - - return wrapper.vm.$nextTick(); - }) - .then(() => { - if (mouseup) { - addCommentOverlay.trigger(event.mouseup); - return wrapper.vm.$nextTick(); - } - - return undefined; - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders image and overlay when image provided', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('renders empty state when no image provided', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('openCommentForm event emits correct data', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - - wrapper.vm.openCommentForm({ x: 1, y: 1 }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('openCommentForm')).toEqual([ - [{ ...mockOverlayData.overlayDimensions, x: 1, y: 1 }], - ]); - }); - }); - - describe('currentCommentForm', () => { - it('is null when isAnnotating is false', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.currentCommentForm).toBeNull(); - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('is null when isAnnotating is true but annotation position is falsey', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - isAnnotating: true, - }, - mockOverlayData, - ); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.currentCommentForm).toBeNull(); - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('is equal to current annotation position when isAnnotating is true', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - isAnnotating: true, - }, - { - ...mockOverlayData, - currentAnnotationPosition: { - x: 1, - y: 1, - width: 100, - height: 100, - }, - }, - ); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.currentCommentForm).toEqual({ - x: 1, - y: 1, - width: 100, - height: 100, - }); - expect(wrapper.element).toMatchSnapshot(); - }); - }); - }); - - describe('setOverlayPosition', () => { - beforeEach(() => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('sets overlay position correctly when overlay is smaller than viewport', () => { - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(200); - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(200); - - wrapper.vm.setOverlayPosition(); - expect(wrapper.vm.overlayPosition).toEqual({ - left: `calc(50% - ${mockOverlayData.overlayDimensions.width / 2}px)`, - top: `calc(50% - ${mockOverlayData.overlayDimensions.height / 2}px)`, - }); - }); - - it('sets overlay position correctly when overlay width is larger than viewports', () => { - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(50); - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(200); - - wrapper.vm.setOverlayPosition(); - expect(wrapper.vm.overlayPosition).toEqual({ - left: '0', - top: `calc(50% - ${mockOverlayData.overlayDimensions.height / 2}px)`, - }); - }); - - it('sets overlay position correctly when overlay height is larger than viewports', () => { - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetWidth', 'get').mockReturnValue(200); - jest.spyOn(wrapper.vm.$refs.presentationViewport, 'offsetHeight', 'get').mockReturnValue(50); - - wrapper.vm.setOverlayPosition(); - expect(wrapper.vm.overlayPosition).toEqual({ - left: `calc(50% - ${mockOverlayData.overlayDimensions.width / 2}px)`, - top: '0', - }); - }); - }); - - describe('getViewportCenter', () => { - beforeEach(() => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - }); - - it('calculate center correctly with no scroll', () => { - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 10, height: 10 }, - { width: 20, height: 20 }, - 0, - 0, - ); - - expect(wrapper.vm.getViewportCenter()).toEqual({ - x: 5, - y: 5, - }); - }); - - it('calculate center correctly with some scroll', () => { - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 10, height: 10 }, - { width: 20, height: 20 }, - 0.5, - 0.5, - ); - - expect(wrapper.vm.getViewportCenter()).toEqual({ - x: 10, - y: 10, - }); - }); - - it('Returns default case if no overflow (scrollWidth==offsetWidth, etc.)', () => { - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 20, height: 20 }, - { width: 20, height: 20 }, - 0.5, - 0.5, - ); - - expect(wrapper.vm.getViewportCenter()).toEqual({ - x: 10, - y: 10, - }); - }); - }); - - describe('scaleZoomFocalPoint', () => { - it('scales focal point correctly when zooming in', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - { - ...mockOverlayData, - zoomFocalPoint: { - x: 5, - y: 5, - width: 50, - height: 50, - }, - }, - ); - - wrapper.vm.scaleZoomFocalPoint(); - expect(wrapper.vm.zoomFocalPoint).toEqual({ - x: 10, - y: 10, - width: 100, - height: 100, - }); - }); - - it('scales focal point correctly when zooming out', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - { - ...mockOverlayData, - zoomFocalPoint: { - x: 10, - y: 10, - width: 200, - height: 200, - }, - }, - ); - - wrapper.vm.scaleZoomFocalPoint(); - expect(wrapper.vm.zoomFocalPoint).toEqual({ - x: 5, - y: 5, - width: 100, - height: 100, - }); - }); - }); - - describe('onImageResize', () => { - it('sets zoom focal point on initial load', () => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - ); - - wrapper.setMethods({ - shiftZoomFocalPoint: jest.fn(), - scaleZoomFocalPoint: jest.fn(), - scrollToFocalPoint: jest.fn(), - }); - - wrapper.vm.onImageResize({ width: 10, height: 10 }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.shiftZoomFocalPoint).toHaveBeenCalled(); - expect(wrapper.vm.initialLoad).toBe(false); - }); - }); - - it('calls scaleZoomFocalPoint and scrollToFocalPoint after initial load', () => { - wrapper.vm.onImageResize({ width: 10, height: 10 }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.scaleZoomFocalPoint).toHaveBeenCalled(); - expect(wrapper.vm.scrollToFocalPoint).toHaveBeenCalled(); - }); - }); - }); - - describe('onPresentationMousedown', () => { - it.each` - scenario | width | height - ${'width overflows'} | ${101} | ${100} - ${'height overflows'} | ${100} | ${101} - ${'width and height overflows'} | ${200} | ${200} - `('sets lastDragPosition when design $scenario', ({ width, height }) => { - createComponent(); - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 100, height: 100 }, - { width, height }, - ); - - const newLastDragPosition = { x: 2, y: 2 }; - wrapper.vm.onPresentationMousedown({ - clientX: newLastDragPosition.x, - clientY: newLastDragPosition.y, - }); - - expect(wrapper.vm.lastDragPosition).toStrictEqual(newLastDragPosition); - }); - - it('does not set lastDragPosition if design does not overflow', () => { - const lastDragPosition = { x: 1, y: 1 }; - - createComponent({}, { lastDragPosition }); - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 100, height: 100 }, - { width: 50, height: 50 }, - ); - - wrapper.vm.onPresentationMousedown({ clientX: 2, clientY: 2 }); - - // check lastDragPosition is unchanged - expect(wrapper.vm.lastDragPosition).toStrictEqual(lastDragPosition); - }); - }); - - describe('getAnnotationPositon', () => { - it.each` - coordinates | overlayDimensions | position - ${{ x: 100, y: 100 }} | ${{ width: 50, height: 50 }} | ${{ x: 100, y: 100, width: 50, height: 50 }} - ${{ x: 100.2, y: 100.5 }} | ${{ width: 50.6, height: 50.0 }} | ${{ x: 100, y: 101, width: 51, height: 50 }} - `('returns correct annotation position', ({ coordinates, overlayDimensions, position }) => { - createComponent(undefined, { - overlayDimensions: { - width: overlayDimensions.width, - height: overlayDimensions.height, - }, - }); - - expect(wrapper.vm.getAnnotationPositon(coordinates)).toStrictEqual(position); - }); - }); - - describe('when design is overflowing', () => { - beforeEach(() => { - createComponent( - { - image: 'test.jpg', - imageName: 'test', - }, - mockOverlayData, - { - 'design-overlay': DesignOverlay, - }, - ); - - // mock a design that overflows - mockRefDimensions( - wrapper.vm.$refs.presentationViewport, - { width: 10, height: 10 }, - { width: 20, height: 20 }, - 0, - 0, - ); - }); - - it('opens a comment form if design was not dragged', () => { - const addCommentOverlay = findOverlayCommentButton(); - const startCoords = { - clientX: 1, - clientY: 1, - }; - - addCommentOverlay.trigger('mousedown', { - clientX: startCoords.clientX, - clientY: startCoords.clientY, - }); - - return wrapper.vm - .$nextTick() - .then(() => { - addCommentOverlay.trigger('mouseup'); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(wrapper.emitted('openCommentForm')).toBeDefined(); - }); - }); - - describe('when clicking and dragging', () => { - it.each` - description | useTouchEvents - ${'with touch events'} | ${true} - ${'without touch events'} | ${false} - `('calls scrollTo with correct arguments $description', ({ useTouchEvents }) => { - return clickDragExplore( - { clientX: 0, clientY: 0 }, - { clientX: 10, clientY: 10 }, - { useTouchEvents }, - ).then(() => { - expect(wrapper.element.scrollTo).toHaveBeenCalledTimes(1); - expect(wrapper.element.scrollTo).toHaveBeenCalledWith(-10, -10); - }); - }); - - it('does not open a comment form when drag position exceeds buffer', () => { - return clickDragExplore( - { clientX: 0, clientY: 0 }, - { clientX: 10, clientY: 10 }, - { mouseup: true }, - ).then(() => { - expect(wrapper.emitted('openCommentForm')).toBeFalsy(); - }); - }); - - it('opens a comment form when drag position is within buffer', () => { - return clickDragExplore( - { clientX: 0, clientY: 0 }, - { clientX: 1, clientY: 0 }, - { mouseup: true }, - ).then(() => { - expect(wrapper.emitted('openCommentForm')).toBeDefined(); - }); - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_scaler_spec.js b/spec/frontend/design_management_legacy/components/design_scaler_spec.js deleted file mode 100644 index 30ef5ab159b..00000000000 --- a/spec/frontend/design_management_legacy/components/design_scaler_spec.js +++ /dev/null @@ -1,67 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import DesignScaler from '~/design_management_legacy/components/design_scaler.vue'; - -describe('Design management design scaler component', () => { - let wrapper; - - function createComponent(propsData, data = {}) { - wrapper = shallowMount(DesignScaler, { - propsData, - }); - wrapper.setData(data); - } - - afterEach(() => { - wrapper.destroy(); - }); - - const getButton = type => { - const buttonTypeOrder = ['minus', 'reset', 'plus']; - const buttons = wrapper.findAll('button'); - return buttons.at(buttonTypeOrder.indexOf(type)); - }; - - it('emits @scale event when "plus" button clicked', () => { - createComponent(); - - getButton('plus').trigger('click'); - expect(wrapper.emitted('scale')).toEqual([[1.2]]); - }); - - it('emits @scale event when "reset" button clicked (scale > 1)', () => { - createComponent({}, { scale: 1.6 }); - return wrapper.vm.$nextTick().then(() => { - getButton('reset').trigger('click'); - expect(wrapper.emitted('scale')).toEqual([[1]]); - }); - }); - - it('emits @scale event when "minus" button clicked (scale > 1)', () => { - createComponent({}, { scale: 1.6 }); - - return wrapper.vm.$nextTick().then(() => { - getButton('minus').trigger('click'); - expect(wrapper.emitted('scale')).toEqual([[1.4]]); - }); - }); - - it('minus and reset buttons are disabled when scale === 1', () => { - createComponent(); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('minus and reset buttons are enabled when scale > 1', () => { - createComponent({}, { scale: 1.2 }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('plus button is disabled when scale === 2', () => { - createComponent({}, { scale: 2 }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/design_sidebar_spec.js b/spec/frontend/design_management_legacy/components/design_sidebar_spec.js deleted file mode 100644 index fc0f618c359..00000000000 --- a/spec/frontend/design_management_legacy/components/design_sidebar_spec.js +++ /dev/null @@ -1,236 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlCollapse, GlPopover } from '@gitlab/ui'; -import Cookies from 'js-cookie'; -import DesignSidebar from '~/design_management_legacy/components/design_sidebar.vue'; -import Participants from '~/sidebar/components/participants/participants.vue'; -import DesignDiscussion from '~/design_management_legacy/components/design_notes/design_discussion.vue'; -import design from '../mock_data/design'; -import updateActiveDiscussionMutation from '~/design_management_legacy/graphql/mutations/update_active_discussion.mutation.graphql'; - -const updateActiveDiscussionMutationVariables = { - mutation: updateActiveDiscussionMutation, - variables: { - id: design.discussions.nodes[0].notes.nodes[0].id, - source: 'discussion', - }, -}; - -const $route = { - params: { - id: '1', - }, -}; - -const cookieKey = 'hide_design_resolved_comments_popover'; - -const mutate = jest.fn().mockResolvedValue(); - -describe('Design management design sidebar component', () => { - let wrapper; - - const findDiscussions = () => wrapper.findAll(DesignDiscussion); - const findFirstDiscussion = () => findDiscussions().at(0); - const findUnresolvedDiscussions = () => wrapper.findAll('[data-testid="unresolved-discussion"]'); - const findResolvedDiscussions = () => wrapper.findAll('[data-testid="resolved-discussion"]'); - const findParticipants = () => wrapper.find(Participants); - const findCollapsible = () => wrapper.find(GlCollapse); - const findToggleResolvedCommentsButton = () => wrapper.find('[data-testid="resolved-comments"]'); - const findPopover = () => wrapper.find(GlPopover); - const findNewDiscussionDisclaimer = () => - wrapper.find('[data-testid="new-discussion-disclaimer"]'); - - function createComponent(props = {}) { - wrapper = shallowMount(DesignSidebar, { - propsData: { - design, - resolvedDiscussionsExpanded: false, - markdownPreviewPath: '', - ...props, - }, - mocks: { - $route, - $apollo: { - mutate, - }, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders participants', () => { - createComponent(); - - expect(findParticipants().exists()).toBe(true); - }); - - it('passes the correct amount of participants to the Participants component', () => { - createComponent(); - - expect(findParticipants().props('participants')).toHaveLength(1); - }); - - describe('when has no discussions', () => { - beforeEach(() => { - createComponent({ - design: { - ...design, - discussions: { - nodes: [], - }, - }, - }); - }); - - it('does not render discussions', () => { - expect(findDiscussions().exists()).toBe(false); - }); - - it('renders a message about possibility to create a new discussion', () => { - expect(findNewDiscussionDisclaimer().exists()).toBe(true); - }); - }); - - describe('when has discussions', () => { - beforeEach(() => { - Cookies.set(cookieKey, true); - createComponent(); - }); - - it('renders correct amount of unresolved discussions', () => { - expect(findUnresolvedDiscussions()).toHaveLength(1); - }); - - it('renders correct amount of resolved discussions', () => { - expect(findResolvedDiscussions()).toHaveLength(1); - }); - - it('has resolved comments collapsible collapsed', () => { - expect(findCollapsible().attributes('visible')).toBeUndefined(); - }); - - it('emits toggleResolveComments event on resolve comments button click', () => { - findToggleResolvedCommentsButton().vm.$emit('click'); - expect(wrapper.emitted('toggleResolvedComments')).toHaveLength(1); - }); - - it('opens a collapsible when resolvedDiscussionsExpanded prop changes to true', () => { - expect(findCollapsible().attributes('visible')).toBeUndefined(); - wrapper.setProps({ - resolvedDiscussionsExpanded: true, - }); - return wrapper.vm.$nextTick().then(() => { - expect(findCollapsible().attributes('visible')).toBe('true'); - }); - }); - - it('does not popover about resolved comments', () => { - expect(findPopover().exists()).toBe(false); - }); - - it('sends a mutation to set an active discussion when clicking on a discussion', () => { - findFirstDiscussion().trigger('click'); - - expect(mutate).toHaveBeenCalledWith(updateActiveDiscussionMutationVariables); - }); - - it('sends a mutation to reset an active discussion when clicking outside of discussion', () => { - wrapper.trigger('click'); - - expect(mutate).toHaveBeenCalledWith({ - ...updateActiveDiscussionMutationVariables, - variables: { id: undefined, source: 'discussion' }, - }); - }); - - it('emits correct event on discussion create note error', () => { - findFirstDiscussion().vm.$emit('createNoteError', 'payload'); - expect(wrapper.emitted('onDesignDiscussionError')).toEqual([['payload']]); - }); - - it('emits correct event on discussion update note error', () => { - findFirstDiscussion().vm.$emit('updateNoteError', 'payload'); - expect(wrapper.emitted('updateNoteError')).toEqual([['payload']]); - }); - - it('emits correct event on discussion resolve error', () => { - findFirstDiscussion().vm.$emit('resolveDiscussionError', 'payload'); - expect(wrapper.emitted('resolveDiscussionError')).toEqual([['payload']]); - }); - - it('changes prop correctly on opening discussion form', () => { - findFirstDiscussion().vm.$emit('openForm', 'some-id'); - - return wrapper.vm.$nextTick().then(() => { - expect(findFirstDiscussion().props('discussionWithOpenForm')).toBe('some-id'); - }); - }); - }); - - describe('when all discussions are resolved', () => { - beforeEach(() => { - createComponent({ - design: { - ...design, - discussions: { - nodes: [ - { - id: 'discussion-id', - replyId: 'discussion-reply-id', - resolved: true, - notes: { - nodes: [ - { - id: 'note-id', - body: '123', - author: { - name: 'Administrator', - username: 'root', - webUrl: 'link-to-author', - avatarUrl: 'link-to-avatar', - }, - }, - ], - }, - }, - ], - }, - }, - }); - }); - - it('renders a message about possibility to create a new discussion', () => { - expect(findNewDiscussionDisclaimer().exists()).toBe(true); - }); - - it('does not render unresolved discussions', () => { - expect(findUnresolvedDiscussions()).toHaveLength(0); - }); - }); - - describe('when showing resolved discussions for the first time', () => { - beforeEach(() => { - Cookies.set(cookieKey, false); - createComponent(); - }); - - it('renders a popover if we show resolved comments collapsible for the first time', () => { - expect(findPopover().exists()).toBe(true); - }); - - it('dismisses a popover on the outside click', () => { - wrapper.trigger('click'); - return wrapper.vm.$nextTick(() => { - expect(findPopover().exists()).toBe(false); - }); - }); - - it(`sets a ${cookieKey} cookie on clicking outside the popover`, () => { - jest.spyOn(Cookies, 'set'); - wrapper.trigger('click'); - expect(Cookies.set).toHaveBeenCalledWith(cookieKey, 'true', { expires: 365 * 10 }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/image_spec.js b/spec/frontend/design_management_legacy/components/image_spec.js deleted file mode 100644 index 265c91abb4e..00000000000 --- a/spec/frontend/design_management_legacy/components/image_spec.js +++ /dev/null @@ -1,133 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlIcon } from '@gitlab/ui'; -import DesignImage from '~/design_management_legacy/components/image.vue'; - -describe('Design management large image component', () => { - let wrapper; - - function createComponent(propsData, data = {}) { - wrapper = shallowMount(DesignImage, { - propsData, - }); - wrapper.setData(data); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders loading state', () => { - createComponent({ - isLoading: true, - }); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders image', () => { - createComponent({ - isLoading: false, - image: 'test.jpg', - name: 'test', - }); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('sets correct classes and styles if imageStyle is set', () => { - createComponent( - { - isLoading: false, - image: 'test.jpg', - name: 'test', - }, - { - imageStyle: { - width: '100px', - height: '100px', - }, - }, - ); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('renders media broken icon on error', () => { - createComponent({ - isLoading: false, - image: 'test.jpg', - name: 'test', - }); - - const image = wrapper.find('img'); - image.trigger('error'); - return wrapper.vm.$nextTick().then(() => { - expect(image.isVisible()).toBe(false); - expect(wrapper.find(GlIcon).element).toMatchSnapshot(); - }); - }); - - describe('zoom', () => { - const baseImageWidth = 100; - const baseImageHeight = 100; - - beforeEach(() => { - createComponent( - { - isLoading: false, - image: 'test.jpg', - name: 'test', - }, - { - imageStyle: { - width: `${baseImageWidth}px`, - height: `${baseImageHeight}px`, - }, - baseImageSize: { - width: baseImageWidth, - height: baseImageHeight, - }, - }, - ); - - jest.spyOn(wrapper.vm.$refs.contentImg, 'offsetWidth', 'get').mockReturnValue(baseImageWidth); - jest - .spyOn(wrapper.vm.$refs.contentImg, 'offsetHeight', 'get') - .mockReturnValue(baseImageHeight); - }); - - it('emits @resize event on zoom', () => { - const zoomAmount = 2; - wrapper.vm.zoom(zoomAmount); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('resize')).toEqual([ - [{ width: baseImageWidth * zoomAmount, height: baseImageHeight * zoomAmount }], - ]); - }); - }); - - it('emits @resize event with base image size when scale=1', () => { - wrapper.vm.zoom(1); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('resize')).toEqual([ - [{ width: baseImageWidth, height: baseImageHeight }], - ]); - }); - }); - - it('sets image style when zoomed', () => { - const zoomAmount = 2; - wrapper.vm.zoom(zoomAmount); - expect(wrapper.vm.imageStyle).toEqual({ - width: `${baseImageWidth * zoomAmount}px`, - height: `${baseImageHeight * zoomAmount}px`, - }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/list/__snapshots__/item_spec.js.snap b/spec/frontend/design_management_legacy/components/list/__snapshots__/item_spec.js.snap deleted file mode 100644 index 168b9424006..00000000000 --- a/spec/frontend/design_management_legacy/components/list/__snapshots__/item_spec.js.snap +++ /dev/null @@ -1,149 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management list item component when item appears in view after image is loaded renders media broken icon when image onerror triggered 1`] = ` -<gl-icon-stub - class="text-secondary" - name="media-broken" - size="32" -/> -`; - -exports[`Design management list item component with notes renders item with multiple comments 1`] = ` -<router-link-stub - class="card cursor-pointer text-plain js-design-list-item design-list-item" - to="[object Object]" -> - <div - class="card-body p-0 d-flex-center overflow-hidden position-relative" - > - <!----> - - <gl-intersection-observer-stub> - <!----> - - <img - alt="test" - class="block mx-auto mw-100 mh-100 design-img" - data-qa-selector="design_image" - src="" - /> - </gl-intersection-observer-stub> - </div> - - <div - class="card-footer d-flex w-100" - > - <div - class="d-flex flex-column str-truncated-100" - > - <span - class="bold str-truncated-100" - data-qa-selector="design_file_name" - > - test - </span> - - <span - class="str-truncated-100" - > - - Updated - <timeago-stub - cssclass="" - time="01-01-2019" - tooltipplacement="bottom" - /> - </span> - </div> - - <div - class="ml-auto d-flex align-items-center text-secondary" - > - <icon-stub - class="ml-1" - name="comments" - size="16" - /> - - <span - aria-label="2 comments" - class="ml-1" - > - - 2 - - </span> - </div> - </div> -</router-link-stub> -`; - -exports[`Design management list item component with notes renders item with single comment 1`] = ` -<router-link-stub - class="card cursor-pointer text-plain js-design-list-item design-list-item" - to="[object Object]" -> - <div - class="card-body p-0 d-flex-center overflow-hidden position-relative" - > - <!----> - - <gl-intersection-observer-stub> - <!----> - - <img - alt="test" - class="block mx-auto mw-100 mh-100 design-img" - data-qa-selector="design_image" - src="" - /> - </gl-intersection-observer-stub> - </div> - - <div - class="card-footer d-flex w-100" - > - <div - class="d-flex flex-column str-truncated-100" - > - <span - class="bold str-truncated-100" - data-qa-selector="design_file_name" - > - test - </span> - - <span - class="str-truncated-100" - > - - Updated - <timeago-stub - cssclass="" - time="01-01-2019" - tooltipplacement="bottom" - /> - </span> - </div> - - <div - class="ml-auto d-flex align-items-center text-secondary" - > - <icon-stub - class="ml-1" - name="comments" - size="16" - /> - - <span - aria-label="1 comment" - class="ml-1" - > - - 1 - - </span> - </div> - </div> -</router-link-stub> -`; diff --git a/spec/frontend/design_management_legacy/components/list/item_spec.js b/spec/frontend/design_management_legacy/components/list/item_spec.js deleted file mode 100644 index e9bb0fc3f29..00000000000 --- a/spec/frontend/design_management_legacy/components/list/item_spec.js +++ /dev/null @@ -1,169 +0,0 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import { GlIcon, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; -import VueRouter from 'vue-router'; -import Icon from '~/vue_shared/components/icon.vue'; -import Item from '~/design_management_legacy/components/list/item.vue'; - -const localVue = createLocalVue(); -localVue.use(VueRouter); -const router = new VueRouter(); - -// Referenced from: doc/api/graphql/reference/gitlab_schema.graphql:DesignVersionEvent -const DESIGN_VERSION_EVENT = { - CREATION: 'CREATION', - DELETION: 'DELETION', - MODIFICATION: 'MODIFICATION', - NO_CHANGE: 'NONE', -}; - -describe('Design management list item component', () => { - let wrapper; - - const findDesignEvent = () => wrapper.find('[data-testid="designEvent"]'); - const findEventIcon = () => findDesignEvent().find(Icon); - const findLoadingIcon = () => wrapper.find(GlLoadingIcon); - - function createComponent({ - notesCount = 0, - event = DESIGN_VERSION_EVENT.NO_CHANGE, - isUploading = false, - imageLoading = false, - } = {}) { - wrapper = shallowMount(Item, { - localVue, - router, - propsData: { - id: 1, - filename: 'test', - image: 'http://via.placeholder.com/300', - isUploading, - event, - notesCount, - updatedAt: '01-01-2019', - }, - data() { - return { - imageLoading, - }; - }, - stubs: ['router-link'], - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when item is not in view', () => { - it('image is not rendered', () => { - createComponent(); - - const image = wrapper.find('img'); - expect(image.attributes('src')).toBe(''); - }); - }); - - describe('when item appears in view', () => { - let image; - let glIntersectionObserver; - - beforeEach(() => { - createComponent(); - image = wrapper.find('img'); - glIntersectionObserver = wrapper.find(GlIntersectionObserver); - - glIntersectionObserver.vm.$emit('appear'); - return wrapper.vm.$nextTick(); - }); - - describe('before image is loaded', () => { - it('renders loading spinner', () => { - expect(wrapper.find(GlLoadingIcon)).toExist(); - }); - }); - - describe('after image is loaded', () => { - beforeEach(() => { - image.trigger('load'); - return wrapper.vm.$nextTick(); - }); - - it('renders an image', () => { - expect(image.attributes('src')).toBe('http://via.placeholder.com/300'); - expect(image.isVisible()).toBe(true); - }); - - it('renders media broken icon when image onerror triggered', () => { - image.trigger('error'); - return wrapper.vm.$nextTick().then(() => { - expect(image.isVisible()).toBe(false); - expect(wrapper.find(GlIcon).element).toMatchSnapshot(); - }); - }); - - describe('when imageV432x230 and image provided', () => { - it('renders imageV432x230 image', () => { - const mockSrc = 'mock-imageV432x230-url'; - wrapper.setProps({ imageV432x230: mockSrc }); - - return wrapper.vm.$nextTick().then(() => { - expect(image.attributes('src')).toBe(mockSrc); - }); - }); - }); - - describe('when image disappears from view and then reappears', () => { - beforeEach(() => { - glIntersectionObserver.vm.$emit('appear'); - return wrapper.vm.$nextTick(); - }); - - it('renders an image', () => { - expect(image.isVisible()).toBe(true); - }); - }); - }); - }); - - describe('with notes', () => { - it('renders item with single comment', () => { - createComponent({ notesCount: 1 }); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders item with multiple comments', () => { - createComponent({ notesCount: 2 }); - - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('renders loading spinner when isUploading is true', () => { - createComponent({ isUploading: true }); - - expect(findLoadingIcon().exists()).toBe(true); - }); - - it('renders item with no status icon for none event', () => { - createComponent(); - - expect(findDesignEvent().exists()).toBe(false); - }); - - describe('with associated event', () => { - it.each` - event | icon | className - ${DESIGN_VERSION_EVENT.MODIFICATION} | ${'file-modified-solid'} | ${'text-primary-500'} - ${DESIGN_VERSION_EVENT.DELETION} | ${'file-deletion-solid'} | ${'text-danger-500'} - ${DESIGN_VERSION_EVENT.CREATION} | ${'file-addition-solid'} | ${'text-success-500'} - `('renders item with correct status icon for $event event', ({ event, icon, className }) => { - createComponent({ event }); - const eventIcon = findEventIcon(); - - expect(eventIcon.exists()).toBe(true); - expect(eventIcon.props('name')).toBe(icon); - expect(eventIcon.classes()).toContain(className); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/index_spec.js.snap b/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/index_spec.js.snap deleted file mode 100644 index e55cff8de3d..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/index_spec.js.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management toolbar component renders design and updated data 1`] = ` -<header - class="d-flex p-2 bg-white align-items-center js-design-header" -> - <a - aria-label="Go back to designs" - class="mr-3 text-plain d-flex justify-content-center align-items-center" - > - <icon-stub - name="close" - size="18" - /> - </a> - - <div - class="overflow-hidden d-flex align-items-center" - > - <h2 - class="m-0 str-truncated-100 gl-font-base" - > - test.jpg - </h2> - - <small - class="text-secondary" - > - Updated 1 hour ago by Test Name - </small> - </div> - - <pagination-stub - class="ml-auto flex-shrink-0" - id="1" - /> - - <gl-deprecated-button-stub - class="mr-2" - href="/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d" - size="md" - variant="secondary" - > - <icon-stub - name="download" - size="18" - /> - </gl-deprecated-button-stub> - - <delete-button-stub - buttonclass="" - buttonvariant="danger" - hasselecteddesigns="true" - > - <icon-stub - name="remove" - size="18" - /> - </delete-button-stub> -</header> -`; diff --git a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_button_spec.js.snap b/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_button_spec.js.snap deleted file mode 100644 index 08662a04f15..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_button_spec.js.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management pagination button component disables button when no design is passed 1`] = ` -<router-link-stub - aria-label="Test title" - class="btn btn-default disabled" - disabled="true" - to="[object Object]" -> - <icon-stub - name="angle-right" - size="16" - /> -</router-link-stub> -`; - -exports[`Design management pagination button component renders router-link 1`] = ` -<router-link-stub - aria-label="Test title" - class="btn btn-default" - to="[object Object]" -> - <icon-stub - name="angle-right" - size="16" - /> -</router-link-stub> -`; diff --git a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_spec.js.snap b/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_spec.js.snap deleted file mode 100644 index 0197b4bff79..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/__snapshots__/pagination_spec.js.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management pagination component hides components when designs are empty 1`] = `<!---->`; - -exports[`Design management pagination component renders pagination buttons 1`] = ` -<div - class="d-flex align-items-center" -> - - 0 of 2 - - <div - class="btn-group ml-3 mr-3" - > - <pagination-button-stub - class="js-previous-design" - iconname="angle-left" - title="Go to previous design" - /> - - <pagination-button-stub - class="js-next-design" - design="[object Object]" - iconname="angle-right" - title="Go to next design" - /> - </div> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/toolbar/index_spec.js b/spec/frontend/design_management_legacy/components/toolbar/index_spec.js deleted file mode 100644 index 8207cad4136..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/index_spec.js +++ /dev/null @@ -1,123 +0,0 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import VueRouter from 'vue-router'; -import { GlDeprecatedButton } from '@gitlab/ui'; -import Toolbar from '~/design_management_legacy/components/toolbar/index.vue'; -import DeleteButton from '~/design_management_legacy/components/delete_button.vue'; -import { DESIGNS_ROUTE_NAME } from '~/design_management_legacy/router/constants'; - -const localVue = createLocalVue(); -localVue.use(VueRouter); -const router = new VueRouter(); - -const RouterLinkStub = { - props: { - to: { - type: Object, - }, - }, - render(createElement) { - return createElement('a', {}, this.$slots.default); - }, -}; - -describe('Design management toolbar component', () => { - let wrapper; - - function createComponent(isLoading = false, createDesign = true, props) { - const updatedAt = new Date(); - updatedAt.setHours(updatedAt.getHours() - 1); - - wrapper = shallowMount(Toolbar, { - localVue, - router, - propsData: { - id: '1', - isLatestVersion: true, - isLoading, - isDeleting: false, - filename: 'test.jpg', - updatedAt: updatedAt.toString(), - updatedBy: { - name: 'Test Name', - }, - image: '/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d', - ...props, - }, - stubs: { - 'router-link': RouterLinkStub, - }, - }); - - wrapper.setData({ - permissions: { - createDesign, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders design and updated data', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('links back to designs list', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - const link = wrapper.find('a'); - - expect(link.props('to')).toEqual({ - name: DESIGNS_ROUTE_NAME, - query: { - version: undefined, - }, - }); - }); - }); - - it('renders delete button on latest designs version with logged in user', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(DeleteButton).exists()).toBe(true); - }); - }); - - it('does not render delete button on non-latest version', () => { - createComponent(false, true, { isLatestVersion: false }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(DeleteButton).exists()).toBe(false); - }); - }); - - it('does not render delete button when user is not logged in', () => { - createComponent(false, false); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(DeleteButton).exists()).toBe(false); - }); - }); - - it('emits `delete` event on deleteButton `deleteSelectedDesigns` event', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - wrapper.find(DeleteButton).vm.$emit('deleteSelectedDesigns'); - expect(wrapper.emitted().delete).toBeTruthy(); - }); - }); - - it('renders download button with correct link', () => { - expect(wrapper.find(GlDeprecatedButton).attributes('href')).toBe( - '/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d', - ); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/toolbar/pagination_button_spec.js b/spec/frontend/design_management_legacy/components/toolbar/pagination_button_spec.js deleted file mode 100644 index d2153adca45..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/pagination_button_spec.js +++ /dev/null @@ -1,61 +0,0 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import VueRouter from 'vue-router'; -import PaginationButton from '~/design_management_legacy/components/toolbar/pagination_button.vue'; -import { DESIGN_ROUTE_NAME } from '~/design_management_legacy/router/constants'; - -const localVue = createLocalVue(); -localVue.use(VueRouter); -const router = new VueRouter(); - -describe('Design management pagination button component', () => { - let wrapper; - - function createComponent(design = null) { - wrapper = shallowMount(PaginationButton, { - localVue, - router, - propsData: { - design, - title: 'Test title', - iconName: 'angle-right', - }, - stubs: ['router-link'], - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('disables button when no design is passed', () => { - createComponent(); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders router-link', () => { - createComponent({ id: '2' }); - - expect(wrapper.element).toMatchSnapshot(); - }); - - describe('designLink', () => { - it('returns empty link when design is null', () => { - createComponent(); - - expect(wrapper.vm.designLink).toEqual({}); - }); - - it('returns design link', () => { - createComponent({ id: '2', filename: 'test' }); - - wrapper.vm.$router.replace('/root/test-project/issues/1/designs/test?version=1'); - - expect(wrapper.vm.designLink).toEqual({ - name: DESIGN_ROUTE_NAME, - params: { id: 'test' }, - query: { version: '1' }, - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/toolbar/pagination_spec.js b/spec/frontend/design_management_legacy/components/toolbar/pagination_spec.js deleted file mode 100644 index 21b55113a6e..00000000000 --- a/spec/frontend/design_management_legacy/components/toolbar/pagination_spec.js +++ /dev/null @@ -1,79 +0,0 @@ -/* global Mousetrap */ -import 'mousetrap'; -import { shallowMount } from '@vue/test-utils'; -import Pagination from '~/design_management_legacy/components/toolbar/pagination.vue'; -import { DESIGN_ROUTE_NAME } from '~/design_management_legacy/router/constants'; - -const push = jest.fn(); -const $router = { - push, -}; - -const $route = { - path: '/designs/design-2', - query: {}, -}; - -describe('Design management pagination component', () => { - let wrapper; - - function createComponent() { - wrapper = shallowMount(Pagination, { - propsData: { - id: '2', - }, - mocks: { - $router, - $route, - }, - }); - } - - beforeEach(() => { - createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('hides components when designs are empty', () => { - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders pagination buttons', () => { - wrapper.setData({ - designs: [{ id: '1' }, { id: '2' }], - }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - describe('keyboard buttons navigation', () => { - beforeEach(() => { - wrapper.setData({ - designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }], - }); - }); - - it('routes to previous design on Left button', () => { - Mousetrap.trigger('left'); - expect(push).toHaveBeenCalledWith({ - name: DESIGN_ROUTE_NAME, - params: { id: '1' }, - query: {}, - }); - }); - - it('routes to next design on Right button', () => { - Mousetrap.trigger('right'); - expect(push).toHaveBeenCalledWith({ - name: DESIGN_ROUTE_NAME, - params: { id: '3' }, - query: {}, - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/upload/__snapshots__/button_spec.js.snap b/spec/frontend/design_management_legacy/components/upload/__snapshots__/button_spec.js.snap deleted file mode 100644 index 27c0ba589e6..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/__snapshots__/button_spec.js.snap +++ /dev/null @@ -1,79 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management upload button component renders inverted upload design button 1`] = ` -<div - isinverted="true" -> - <gl-deprecated-button-stub - size="md" - title="Adding a design with the same filename replaces the file in a new version." - variant="success" - > - - Upload designs - - <!----> - </gl-deprecated-button-stub> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> -</div> -`; - -exports[`Design management upload button component renders loading icon 1`] = ` -<div> - <gl-deprecated-button-stub - disabled="true" - size="md" - title="Adding a design with the same filename replaces the file in a new version." - variant="success" - > - - Upload designs - - <gl-loading-icon-stub - class="ml-1" - color="orange" - inline="true" - label="Loading" - size="sm" - /> - </gl-deprecated-button-stub> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> -</div> -`; - -exports[`Design management upload button component renders upload design button 1`] = ` -<div> - <gl-deprecated-button-stub - size="md" - title="Adding a design with the same filename replaces the file in a new version." - variant="success" - > - - Upload designs - - <!----> - </gl-deprecated-button-stub> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_dropzone_spec.js.snap b/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_dropzone_spec.js.snap deleted file mode 100644 index 0737b9729a2..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_dropzone_spec.js.snap +++ /dev/null @@ -1,455 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management dropzone component when dragging renders correct template when drag event contains files 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="" - > - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when dragging renders correct template when drag event contains files and text 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="" - > - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when dragging renders correct template when drag event contains text 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="" - > - <div - class="mw-50 text-center" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when dragging renders correct template when drag event is empty 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="" - > - <div - class="mw-50 text-center" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when dragging renders correct template when dragging stops 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="display: none;" - > - <div - class="mw-50 text-center" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when no slot provided renders default dropzone card 1`] = ` -<div - class="w-100 position-relative" -> - <button - class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3" - > - <div - class="d-flex-center flex-column text-center" - > - <gl-icon-stub - class="mb-4" - name="doc-new" - size="48" - /> - - <p> - <gl-sprintf-stub - message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}." - /> - </p> - </div> - </button> - - <input - accept="image/*" - class="hide" - multiple="multiple" - name="design_file" - type="file" - /> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="display: none;" - > - <div - class="mw-50 text-center" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; - -exports[`Design management dropzone component when slot provided renders dropzone with slot content 1`] = ` -<div - class="w-100 position-relative" -> - <div> - dropzone slot - </div> - - <transition-stub - name="design-dropzone-fade" - > - <div - class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white" - style="display: none;" - > - <div - class="mw-50 text-center" - > - <h3> - Oh no! - </h3> - - <span> - You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico. - </span> - </div> - - <div - class="mw-50 text-center" - style="display: none;" - > - <h3> - Incoming! - </h3> - - <span> - Drop your designs to start your upload. - </span> - </div> - </div> - </transition-stub> -</div> -`; diff --git a/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_version_dropdown_spec.js.snap b/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_version_dropdown_spec.js.snap deleted file mode 100644 index d34b925f33d..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/__snapshots__/design_version_dropdown_spec.js.snap +++ /dev/null @@ -1,111 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Design management design version dropdown component renders design version dropdown button 1`] = ` -<gl-deprecated-dropdown-stub - class="design-version-dropdown" - issueiid="" - projectpath="" - text="Showing Latest Version" - variant="link" -> - <gl-deprecated-dropdown-item-stub> - <router-link-stub - class="d-flex js-version-link" - to="[object Object]" - > - <div - class="flex-grow-1 ml-2" - > - <div> - <strong> - Version 2 - - <span> - (latest) - </span> - </strong> - </div> - </div> - - <i - class="fa fa-check float-right gl-mr-2" - /> - </router-link-stub> - </gl-deprecated-dropdown-item-stub> - <gl-deprecated-dropdown-item-stub> - <router-link-stub - class="d-flex js-version-link" - to="[object Object]" - > - <div - class="flex-grow-1 ml-2" - > - <div> - <strong> - Version 1 - - <!----> - </strong> - </div> - </div> - - <!----> - </router-link-stub> - </gl-deprecated-dropdown-item-stub> -</gl-deprecated-dropdown-stub> -`; - -exports[`Design management design version dropdown component renders design version list 1`] = ` -<gl-deprecated-dropdown-stub - class="design-version-dropdown" - issueiid="" - projectpath="" - text="Showing Latest Version" - variant="link" -> - <gl-deprecated-dropdown-item-stub> - <router-link-stub - class="d-flex js-version-link" - to="[object Object]" - > - <div - class="flex-grow-1 ml-2" - > - <div> - <strong> - Version 2 - - <span> - (latest) - </span> - </strong> - </div> - </div> - - <i - class="fa fa-check float-right gl-mr-2" - /> - </router-link-stub> - </gl-deprecated-dropdown-item-stub> - <gl-deprecated-dropdown-item-stub> - <router-link-stub - class="d-flex js-version-link" - to="[object Object]" - > - <div - class="flex-grow-1 ml-2" - > - <div> - <strong> - Version 1 - - <!----> - </strong> - </div> - </div> - - <!----> - </router-link-stub> - </gl-deprecated-dropdown-item-stub> -</gl-deprecated-dropdown-stub> -`; diff --git a/spec/frontend/design_management_legacy/components/upload/button_spec.js b/spec/frontend/design_management_legacy/components/upload/button_spec.js deleted file mode 100644 index dde5c694194..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/button_spec.js +++ /dev/null @@ -1,59 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import UploadButton from '~/design_management_legacy/components/upload/button.vue'; - -describe('Design management upload button component', () => { - let wrapper; - - function createComponent(isSaving = false, isInverted = false) { - wrapper = shallowMount(UploadButton, { - propsData: { - isSaving, - isInverted, - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders upload design button', () => { - createComponent(); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders inverted upload design button', () => { - createComponent(false, true); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders loading icon', () => { - createComponent(true); - - expect(wrapper.element).toMatchSnapshot(); - }); - - describe('onFileUploadChange', () => { - it('emits upload event', () => { - createComponent(); - - wrapper.vm.onFileUploadChange({ target: { files: 'test' } }); - - expect(wrapper.emitted().upload[0]).toEqual(['test']); - }); - }); - - describe('openFileUpload', () => { - it('triggers click on input', () => { - createComponent(); - - const clickSpy = jest.spyOn(wrapper.find('input').element, 'click'); - - wrapper.vm.openFileUpload(); - - expect(clickSpy).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/upload/design_dropzone_spec.js b/spec/frontend/design_management_legacy/components/upload/design_dropzone_spec.js deleted file mode 100644 index 1907a3124a6..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/design_dropzone_spec.js +++ /dev/null @@ -1,132 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import DesignDropzone from '~/design_management_legacy/components/upload/design_dropzone.vue'; -import { deprecatedCreateFlash as createFlash } from '~/flash'; - -jest.mock('~/flash'); - -describe('Design management dropzone component', () => { - let wrapper; - - const mockDragEvent = ({ types = ['Files'], files = [] }) => { - return { dataTransfer: { types, files } }; - }; - - const findDropzoneCard = () => wrapper.find('.design-dropzone-card'); - - function createComponent({ slots = {}, data = {} } = {}) { - wrapper = shallowMount(DesignDropzone, { - slots, - data() { - return data; - }, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when slot provided', () => { - it('renders dropzone with slot content', () => { - createComponent({ - slots: { - default: ['<div>dropzone slot</div>'], - }, - }); - - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - describe('when no slot provided', () => { - it('renders default dropzone card', () => { - createComponent(); - - expect(wrapper.element).toMatchSnapshot(); - }); - - it('triggers click event on file input element when clicked', () => { - createComponent(); - const clickSpy = jest.spyOn(wrapper.find('input').element, 'click'); - - findDropzoneCard().trigger('click'); - expect(clickSpy).toHaveBeenCalled(); - }); - }); - - describe('when dragging', () => { - it.each` - description | eventPayload - ${'is empty'} | ${{}} - ${'contains text'} | ${mockDragEvent({ types: ['text'] })} - ${'contains files and text'} | ${mockDragEvent({ types: ['Files', 'text'] })} - ${'contains files'} | ${mockDragEvent({ types: ['Files'] })} - `('renders correct template when drag event $description', ({ eventPayload }) => { - createComponent(); - - wrapper.trigger('dragenter', eventPayload); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('renders correct template when dragging stops', () => { - createComponent(); - - wrapper.trigger('dragenter'); - return wrapper.vm - .$nextTick() - .then(() => { - wrapper.trigger('dragleave'); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - }); - - describe('when dropping', () => { - it('emits upload event', () => { - createComponent(); - const mockFile = { name: 'test', type: 'image/jpg' }; - const mockEvent = mockDragEvent({ files: [mockFile] }); - - wrapper.trigger('dragenter', mockEvent); - return wrapper.vm - .$nextTick() - .then(() => { - wrapper.trigger('drop', mockEvent); - return wrapper.vm.$nextTick(); - }) - .then(() => { - expect(wrapper.emitted().change[0]).toEqual([[mockFile]]); - }); - }); - }); - - describe('ondrop', () => { - const mockData = { dragCounter: 1, isDragDataValid: true }; - - describe('when drag data is valid', () => { - it('emits upload event for valid files', () => { - createComponent({ data: mockData }); - - const mockFile = { type: 'image/jpg' }; - const mockEvent = mockDragEvent({ files: [mockFile] }); - - wrapper.vm.ondrop(mockEvent); - expect(wrapper.emitted().change[0]).toEqual([[mockFile]]); - }); - - it('calls createFlash when files are invalid', () => { - createComponent({ data: mockData }); - - const mockEvent = mockDragEvent({ files: [{ type: 'audio/midi' }] }); - - wrapper.vm.ondrop(mockEvent); - expect(createFlash).toHaveBeenCalledTimes(1); - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/upload/design_version_dropdown_spec.js b/spec/frontend/design_management_legacy/components/upload/design_version_dropdown_spec.js deleted file mode 100644 index 7fb85f357c7..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/design_version_dropdown_spec.js +++ /dev/null @@ -1,122 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui'; -import DesignVersionDropdown from '~/design_management_legacy/components/upload/design_version_dropdown.vue'; -import mockAllVersions from './mock_data/all_versions'; - -const LATEST_VERSION_ID = 3; -const PREVIOUS_VERSION_ID = 2; - -const designRouteFactory = versionId => ({ - path: `/designs?version=${versionId}`, - query: { - version: `${versionId}`, - }, -}); - -const MOCK_ROUTE = { - path: '/designs', - query: {}, -}; - -describe('Design management design version dropdown component', () => { - let wrapper; - - function createComponent({ maxVersions = -1, $route = MOCK_ROUTE } = {}) { - wrapper = shallowMount(DesignVersionDropdown, { - propsData: { - projectPath: '', - issueIid: '', - }, - mocks: { - $route, - }, - stubs: ['router-link'], - }); - - wrapper.setData({ - allVersions: maxVersions > -1 ? mockAllVersions.slice(0, maxVersions) : mockAllVersions, - }); - } - - afterEach(() => { - wrapper.destroy(); - }); - - const findVersionLink = index => wrapper.findAll('.js-version-link').at(index); - - it('renders design version dropdown button', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - it('renders design version list', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - describe('selected version name', () => { - it('has "latest" on most recent version item', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(findVersionLink(0).text()).toContain('latest'); - }); - }); - }); - - describe('versions list', () => { - it('displays latest version text by default', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(GlDeprecatedDropdown).attributes('text')).toBe( - 'Showing Latest Version', - ); - }); - }); - - it('displays latest version text when only 1 version is present', () => { - createComponent({ maxVersions: 1 }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(GlDeprecatedDropdown).attributes('text')).toBe( - 'Showing Latest Version', - ); - }); - }); - - it('displays version text when the current version is not the latest', () => { - createComponent({ $route: designRouteFactory(PREVIOUS_VERSION_ID) }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(GlDeprecatedDropdown).attributes('text')).toBe(`Showing Version #1`); - }); - }); - - it('displays latest version text when the current version is the latest', () => { - createComponent({ $route: designRouteFactory(LATEST_VERSION_ID) }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(GlDeprecatedDropdown).attributes('text')).toBe( - 'Showing Latest Version', - ); - }); - }); - - it('should have the same length as apollo query', () => { - createComponent(); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.findAll(GlDeprecatedDropdownItem)).toHaveLength( - wrapper.vm.allVersions.length, - ); - }); - }); - }); -}); diff --git a/spec/frontend/design_management_legacy/components/upload/mock_data/all_versions.js b/spec/frontend/design_management_legacy/components/upload/mock_data/all_versions.js deleted file mode 100644 index e76bbd261bd..00000000000 --- a/spec/frontend/design_management_legacy/components/upload/mock_data/all_versions.js +++ /dev/null @@ -1,14 +0,0 @@ -export default [ - { - node: { - id: 'gid://gitlab/DesignManagement::Version/3', - sha: '0945756378e0b1588b9dd40d5a6b99e8b7198f55', - }, - }, - { - node: { - id: 'gid://gitlab/DesignManagement::Version/2', - sha: '5b063fef0cd7213b312db65b30e24f057df21b20', - }, - }, -]; |