diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/frontend/batch_comments/components | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/frontend/batch_comments/components')
6 files changed, 507 insertions, 0 deletions
diff --git a/spec/frontend/batch_comments/components/diff_file_drafts_spec.js b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js new file mode 100644 index 00000000000..6e0b61db9fa --- /dev/null +++ b/spec/frontend/batch_comments/components/diff_file_drafts_spec.js @@ -0,0 +1,61 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import DiffFileDrafts from '~/batch_comments/components/diff_file_drafts.vue'; +import DraftNote from '~/batch_comments/components/draft_note.vue'; + +const localVue = createLocalVue(); + +localVue.use(Vuex); + +describe('Batch comments diff file drafts component', () => { + let vm; + + function factory() { + const store = new Vuex.Store({ + modules: { + batchComments: { + namespaced: true, + getters: { + draftsForFile: () => () => [{ id: 1 }, { id: 2 }], + }, + }, + }, + }); + + vm = shallowMount(localVue.extend(DiffFileDrafts), { + store, + localVue, + propsData: { fileHash: 'filehash' }, + }); + } + + afterEach(() => { + vm.destroy(); + }); + + it('renders list of draft notes', () => { + factory(); + + expect(vm.findAll(DraftNote).length).toEqual(2); + }); + + it('renders index of draft note', () => { + factory(); + + expect(vm.findAll('.js-diff-notes-index').length).toEqual(2); + + expect( + vm + .findAll('.js-diff-notes-index') + .at(0) + .text(), + ).toEqual('1'); + + expect( + vm + .findAll('.js-diff-notes-index') + .at(1) + .text(), + ).toEqual('2'); + }); +}); diff --git a/spec/frontend/batch_comments/components/draft_note_spec.js b/spec/frontend/batch_comments/components/draft_note_spec.js new file mode 100644 index 00000000000..eea7f25dbc1 --- /dev/null +++ b/spec/frontend/batch_comments/components/draft_note_spec.js @@ -0,0 +1,125 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import DraftNote from '~/batch_comments/components/draft_note.vue'; +import { createStore } from '~/batch_comments/stores'; +import NoteableNote from '~/notes/components/noteable_note.vue'; +import '~/behaviors/markdown/render_gfm'; +import { createDraft } from '../mock_data'; + +const localVue = createLocalVue(); + +describe('Batch comments draft note component', () => { + let wrapper; + let draft; + + beforeEach(() => { + const store = createStore(); + + draft = createDraft(); + + wrapper = shallowMount(localVue.extend(DraftNote), { + store, + propsData: { draft }, + localVue, + }); + + jest.spyOn(wrapper.vm.$store, 'dispatch').mockImplementation(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders template', () => { + expect(wrapper.find('.draft-pending-label').exists()).toBe(true); + + const note = wrapper.find(NoteableNote); + + expect(note.exists()).toBe(true); + expect(note.props().note).toEqual(draft); + }); + + describe('add comment now', () => { + it('dispatches publishSingleDraft when clicking', () => { + const publishNowButton = wrapper.find({ ref: 'publishNowButton' }); + publishNowButton.vm.$emit('click'); + + expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith( + 'batchComments/publishSingleDraft', + 1, + ); + }); + + it('sets as loading when draft is publishing', done => { + wrapper.vm.$store.state.batchComments.currentlyPublishingDrafts.push(1); + + wrapper.vm.$nextTick(() => { + const publishNowButton = wrapper.find({ ref: 'publishNowButton' }); + + expect(publishNowButton.props().loading).toBe(true); + + done(); + }); + }); + }); + + describe('update', () => { + it('dispatches updateDraft', done => { + const note = wrapper.find(NoteableNote); + + note.vm.$emit('handleEdit'); + + wrapper.vm + .$nextTick() + .then(() => { + const formData = { + note: draft, + noteText: 'a', + resolveDiscussion: false, + }; + + note.vm.$emit('handleUpdateNote', formData); + + expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith( + 'batchComments/updateDraft', + formData, + ); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('deleteDraft', () => { + it('dispatches deleteDraft', () => { + jest.spyOn(window, 'confirm').mockImplementation(() => true); + + const note = wrapper.find(NoteableNote); + + note.vm.$emit('handleDeleteNote', draft); + + expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('batchComments/deleteDraft', draft); + }); + }); + + describe('quick actions', () => { + it('renders referenced commands', done => { + wrapper.setProps({ + draft: { + ...draft, + references: { + commands: 'test command', + }, + }, + }); + + wrapper.vm.$nextTick(() => { + const referencedCommands = wrapper.find('.referenced-commands'); + + expect(referencedCommands.exists()).toBe(true); + expect(referencedCommands.text()).toContain('test command'); + + done(); + }); + }); + }); +}); diff --git a/spec/frontend/batch_comments/components/drafts_count_spec.js b/spec/frontend/batch_comments/components/drafts_count_spec.js new file mode 100644 index 00000000000..9d9fffce7e7 --- /dev/null +++ b/spec/frontend/batch_comments/components/drafts_count_spec.js @@ -0,0 +1,43 @@ +import Vue from 'vue'; +import DraftsCount from '~/batch_comments/components/drafts_count.vue'; +import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/batch_comments/stores'; + +describe('Batch comments drafts count component', () => { + let vm; + let Component; + + beforeAll(() => { + Component = Vue.extend(DraftsCount); + }); + + beforeEach(() => { + const store = createStore(); + + store.state.batchComments.drafts.push('comment'); + + vm = mountComponentWithStore(Component, { store }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders count', () => { + expect(vm.$el.querySelector('.drafts-count-number').textContent).toBe('1'); + }); + + it('renders screen reader text', done => { + const el = vm.$el.querySelector('.sr-only'); + + expect(el.textContent).toContain('draft'); + + vm.$store.state.batchComments.drafts.push('comment 2'); + + vm.$nextTick(() => { + expect(el.textContent).toContain('drafts'); + + done(); + }); + }); +}); diff --git a/spec/frontend/batch_comments/components/preview_item_spec.js b/spec/frontend/batch_comments/components/preview_item_spec.js new file mode 100644 index 00000000000..7d951fd7799 --- /dev/null +++ b/spec/frontend/batch_comments/components/preview_item_spec.js @@ -0,0 +1,130 @@ +import Vue from 'vue'; +import PreviewItem from '~/batch_comments/components/preview_item.vue'; +import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/batch_comments/stores'; +import diffsModule from '~/diffs/store/modules'; +import notesModule from '~/notes/stores/modules'; +import '~/behaviors/markdown/render_gfm'; +import { createDraft } from '../mock_data'; + +describe('Batch comments draft preview item component', () => { + let vm; + let Component; + let draft; + + function createComponent(isLast = false, extra = {}, extendStore = () => {}) { + const store = createStore(); + store.registerModule('diffs', diffsModule()); + store.registerModule('notes', notesModule()); + + extendStore(store); + + draft = { + ...createDraft(), + ...extra, + }; + + vm = mountComponentWithStore(Component, { store, props: { draft, isLast } }); + } + + beforeAll(() => { + Component = Vue.extend(PreviewItem); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders text content', () => { + createComponent(false, { note_html: '<img src="" /><p>Hello world</p>' }); + + expect(vm.$el.querySelector('.review-preview-item-content').innerHTML).toEqual( + '<p>Hello world</p>', + ); + }); + + it('adds is last class', () => { + createComponent(true); + + expect(vm.$el.classList).toContain('is-last'); + }); + + it('scrolls to draft on click', () => { + createComponent(); + + jest.spyOn(vm.$store, 'dispatch').mockImplementation(); + + vm.$el.click(); + + expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/scrollToDraft', vm.draft); + }); + + describe('for file', () => { + it('renders file path', () => { + createComponent(false, { file_path: 'index.js', file_hash: 'abc', position: {} }); + + expect(vm.$el.querySelector('.review-preview-item-header-text').textContent).toContain( + 'index.js', + ); + }); + + it('renders new line position', () => { + createComponent(false, { + file_path: 'index.js', + file_hash: 'abc', + position: { new_line: 1 }, + }); + + expect(vm.$el.querySelector('.bold').textContent).toContain(':1'); + }); + + it('renders old line position', () => { + createComponent(false, { + file_path: 'index.js', + file_hash: 'abc', + position: { old_line: 2 }, + }); + + expect(vm.$el.querySelector('.bold').textContent).toContain(':2'); + }); + + it('renders image position', () => { + createComponent(false, { + file_path: 'index.js', + file_hash: 'abc', + position: { position_type: 'image', x: 10, y: 20 }, + }); + + expect(vm.$el.querySelector('.bold').textContent).toContain('10x 20y'); + }); + }); + + describe('for thread', () => { + beforeEach(() => { + createComponent(false, { discussion_id: '1', resolve_discussion: true }, store => { + store.state.notes.discussions.push({ + id: '1', + notes: [ + { + author: { + name: 'Author Name', + }, + }, + ], + }); + }); + }); + + it('renders title', () => { + expect(vm.$el.querySelector('.review-preview-item-header-text').textContent).toContain( + "Author Name's thread", + ); + }); + + it('it renders thread resolved text', () => { + expect(vm.$el.querySelector('.draft-note-resolution').textContent).toContain( + 'Thread will be resolved', + ); + }); + }); +}); diff --git a/spec/frontend/batch_comments/components/publish_button_spec.js b/spec/frontend/batch_comments/components/publish_button_spec.js new file mode 100644 index 00000000000..97f3a1c8939 --- /dev/null +++ b/spec/frontend/batch_comments/components/publish_button_spec.js @@ -0,0 +1,52 @@ +import Vue from 'vue'; +import PublishButton from '~/batch_comments/components/publish_button.vue'; +import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/batch_comments/stores'; + +describe('Batch comments publish button component', () => { + let vm; + let Component; + + beforeAll(() => { + Component = Vue.extend(PublishButton); + }); + + beforeEach(() => { + const store = createStore(); + + vm = mountComponentWithStore(Component, { store, props: { shouldPublish: true } }); + + jest.spyOn(vm.$store, 'dispatch').mockImplementation(); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('dispatches publishReview on click', () => { + vm.$el.click(); + + expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/publishReview', undefined); + }); + + it('dispatches toggleReviewDropdown when shouldPublish is false on click', () => { + vm.shouldPublish = false; + + vm.$el.click(); + + expect(vm.$store.dispatch).toHaveBeenCalledWith( + 'batchComments/toggleReviewDropdown', + undefined, + ); + }); + + it('sets loading when isPublishing is true', done => { + vm.$store.state.batchComments.isPublishing = true; + + vm.$nextTick(() => { + expect(vm.$el.getAttribute('disabled')).toBe('disabled'); + + done(); + }); + }); +}); diff --git a/spec/frontend/batch_comments/components/publish_dropdown_spec.js b/spec/frontend/batch_comments/components/publish_dropdown_spec.js new file mode 100644 index 00000000000..b50ae340691 --- /dev/null +++ b/spec/frontend/batch_comments/components/publish_dropdown_spec.js @@ -0,0 +1,96 @@ +import Vue from 'vue'; +import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue'; +import { mountComponentWithStore } from 'helpers/vue_mount_component_helper'; +import { createStore } from '~/mr_notes/stores'; +import '~/behaviors/markdown/render_gfm'; +import { createDraft } from '../mock_data'; + +describe('Batch comments publish dropdown component', () => { + let vm; + let Component; + + function createComponent(extendStore = () => {}) { + const store = createStore(); + store.state.batchComments.drafts.push(createDraft(), { ...createDraft(), id: 2 }); + + extendStore(store); + + vm = mountComponentWithStore(Component, { store }); + } + + beforeAll(() => { + Component = Vue.extend(PreviewDropdown); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('toggles dropdown when clicking button', done => { + createComponent(); + + jest.spyOn(vm.$store, 'dispatch'); + + vm.$el.querySelector('.review-preview-dropdown-toggle').click(); + + expect(vm.$store.dispatch).toHaveBeenCalledWith( + 'batchComments/toggleReviewDropdown', + expect.anything(), + ); + + setImmediate(() => { + expect(vm.$el.classList).toContain('show'); + + done(); + }); + }); + + it('toggles dropdown when clicking body', () => { + createComponent(); + + vm.$store.state.batchComments.showPreviewDropdown = true; + + jest.spyOn(vm.$store, 'dispatch').mockImplementation(); + + document.body.click(); + + expect(vm.$store.dispatch).toHaveBeenCalledWith( + 'batchComments/toggleReviewDropdown', + undefined, + ); + }); + + it('renders list of drafts', () => { + createComponent(store => { + Object.assign(store.state.notes, { + isNotesFetched: true, + }); + }); + + expect(vm.$el.querySelectorAll('.dropdown-content li').length).toBe(2); + }); + + it('adds is-last class to last item', () => { + createComponent(store => { + Object.assign(store.state.notes, { + isNotesFetched: true, + }); + }); + + expect(vm.$el.querySelectorAll('.dropdown-content li')[1].querySelector('.is-last')).not.toBe( + null, + ); + }); + + it('renders draft count in dropdown title', () => { + createComponent(); + + expect(vm.$el.querySelector('.dropdown-title').textContent).toContain('2 pending comments'); + }); + + it('renders publish button in footer', () => { + createComponent(); + + expect(vm.$el.querySelector('.dropdown-footer .js-publish-draft-button')).not.toBe(null); + }); +}); |