diff --git a/app/assets/javascripts/notes/components/discussion_notes.vue b/app/assets/javascripts/notes/components/discussion_notes.vue
new file mode 100644
index 00000000000..5b6163a6214
--- /dev/null
+++ b/app/assets/javascripts/notes/components/discussion_notes.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
showReplies:{{showReplies}}
', + }, + slots: { + 'avatar-badge': '', + }, + sync: false, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('rendering', () => { + it('renders an element for each note in the discussion', () => { + createComponent(); + const notesCount = discussionMock.notes.length; + const els = wrapper.findAll(TimelineEntryItem); + expect(els.length).toBe(notesCount); + }); + + it('renders one element if replies groupping is enabled', () => { + createComponent({ shouldGroupReplies: true }); + const els = wrapper.findAll(TimelineEntryItem); + expect(els.length).toBe(1); + }); + + it('uses proper component to render each note type', () => { + const discussion = { ...discussionMock }; + const notesData = [ + // PlaceholderSystemNote + { + id: 1, + isPlaceholderNote: true, + placeholderType: SYSTEM_NOTE, + notes: [{ body: 'PlaceholderSystemNote' }], + }, + // PlaceholderNote + { + id: 2, + isPlaceholderNote: true, + notes: [{ body: 'PlaceholderNote' }], + }, + // SystemNote + { + id: 3, + system: true, + note: 'SystemNote', + }, + // NoteableNote + discussion.notes[0], + ]; + discussion.notes = notesData; + createComponent({ discussion }); + const notes = wrapper.findAll('.notes > li'); + + expect(notes.at(0).is(PlaceholderSystemNote)).toBe(true); + expect(notes.at(1).is(PlaceholderNote)).toBe(true); + expect(notes.at(2).is(SystemNote)).toBe(true); + expect(notes.at(3).is(NoteableNote)).toBe(true); + }); + + it('renders footer scoped slot with showReplies === true when expanded', () => { + createComponent({ isExpanded: true }); + expect(wrapper.text()).toMatch('showReplies:true'); + }); + + it('renders footer scoped slot with showReplies === false when collapsed', () => { + createComponent({ isExpanded: false }); + expect(wrapper.text()).toMatch('showReplies:false'); + }); + + it('passes down avatar-badge slot content', () => { + createComponent(); + expect(wrapper.find('.avatar-badge-slot-content').exists()).toBe(true); + }); + }); + + describe('componentData', () => { + beforeEach(() => { + createComponent(); + }); + + it('should return first note object for placeholder note', () => { + const data = { + isPlaceholderNote: true, + notes: [{ body: 'hello world!' }], + }; + const note = wrapper.vm.componentData(data); + + expect(note).toEqual(data.notes[0]); + }); + + it('should return given note for nonplaceholder notes', () => { + const data = { + notes: [{ id: 12 }], + }; + const note = wrapper.vm.componentData(data); + + expect(note).toEqual(data); + }); + }); +}); diff --git a/spec/javascripts/diffs/components/diff_discussions_spec.js b/spec/javascripts/diffs/components/diff_discussions_spec.js index 0bc9da5ad0f..f7f0ab83c21 100644 --- a/spec/javascripts/diffs/components/diff_discussions_spec.js +++ b/spec/javascripts/diffs/components/diff_discussions_spec.js @@ -1,90 +1,103 @@ -import Vue from 'vue'; +import { mount, createLocalVue } from '@vue/test-utils'; import DiffDiscussions from '~/diffs/components/diff_discussions.vue'; +import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; +import NoteableDiscussion from '~/notes/components/noteable_discussion.vue'; +import DiscussionNotes from '~/notes/components/discussion_notes.vue'; +import Icon from '~/vue_shared/components/icon.vue'; import { createStore } from '~/mr_notes/stores'; -import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import '~/behaviors/markdown/render_gfm'; import discussionsMockData from '../mock_data/diff_discussions'; +const localVue = createLocalVue(); + describe('DiffDiscussions', () => { - let vm; + let store; + let wrapper; const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)]; - function createComponent(props = {}) { - const store = createStore(); - - vm = createComponentWithStore(Vue.extend(DiffDiscussions), store, { - discussions: getDiscussionsMockData(), - ...props, - }).$mount(); - } + const createComponent = props => { + store = createStore(); + wrapper = mount(localVue.extend(DiffDiscussions), { + store, + propsData: { + discussions: getDiscussionsMockData(), + ...props, + }, + localVue, + sync: false, + }); + }; afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); describe('template', () => { it('should have notes list', () => { createComponent(); - expect(vm.$el.querySelectorAll('.discussion .note.timeline-entry').length).toEqual(5); + expect(wrapper.find(NoteableDiscussion).exists()).toBe(true); + expect(wrapper.find(DiscussionNotes).exists()).toBe(true); + expect(wrapper.find(DiscussionNotes).findAll(TimelineEntryItem).length).toBe( + discussionsMockData.notes.length, + ); }); }); describe('image commenting', () => { + const findDiffNotesToggle = () => wrapper.find('.js-diff-notes-toggle'); + it('renders collapsible discussion button', () => { createComponent({ shouldCollapseDiscussions: true }); + const diffNotesToggle = findDiffNotesToggle(); - expect(vm.$el.querySelector('.js-diff-notes-toggle')).not.toBe(null); - expect(vm.$el.querySelector('.js-diff-notes-toggle svg')).not.toBe(null); - expect(vm.$el.querySelector('.js-diff-notes-toggle').classList).toContain( - 'diff-notes-collapse', - ); + expect(diffNotesToggle.exists()).toBe(true); + expect(diffNotesToggle.find(Icon).exists()).toBe(true); + expect(diffNotesToggle.classes('diff-notes-collapse')).toBe(true); }); it('dispatches toggleDiscussion when clicking collapse button', () => { createComponent({ shouldCollapseDiscussions: true }); + spyOn(wrapper.vm.$store, 'dispatch').and.stub(); + const diffNotesToggle = findDiffNotesToggle(); + diffNotesToggle.trigger('click'); - spyOn(vm.$store, 'dispatch').and.stub(); - - vm.$el.querySelector('.js-diff-notes-toggle').click(); - - expect(vm.$store.dispatch).toHaveBeenCalledWith('toggleDiscussion', { - discussionId: vm.discussions[0].id, + expect(wrapper.vm.$store.dispatch).toHaveBeenCalledWith('toggleDiscussion', { + discussionId: discussionsMockData.id, }); }); - it('renders expand button when discussion is collapsed', done => { - createComponent({ shouldCollapseDiscussions: true }); + it('renders expand button when discussion is collapsed', () => { + const discussions = getDiscussionsMockData(); + discussions[0].expanded = false; + createComponent({ discussions, shouldCollapseDiscussions: true }); + const diffNotesToggle = findDiffNotesToggle(); - vm.discussions[0].expanded = false; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.js-diff-notes-toggle').textContent.trim()).toBe('1'); - expect(vm.$el.querySelector('.js-diff-notes-toggle').className).toContain( - 'btn-transparent badge badge-pill', - ); - - done(); - }); + expect(diffNotesToggle.text().trim()).toBe('1'); + expect(diffNotesToggle.classes()).toEqual( + jasmine.arrayContaining(['btn-transparent', 'badge', 'badge-pill']), + ); }); - it('hides discussion when collapsed', done => { - createComponent({ shouldCollapseDiscussions: true }); + it('hides discussion when collapsed', () => { + const discussions = getDiscussionsMockData(); + discussions[0].expanded = false; + createComponent({ discussions, shouldCollapseDiscussions: true }); - vm.discussions[0].expanded = false; - - vm.$nextTick(() => { - expect(vm.$el.querySelector('.note-discussion').style.display).toBe('none'); - - done(); - }); + expect(wrapper.find(NoteableDiscussion).isVisible()).toBe(false); }); it('renders badge on avatar', () => { - createComponent({ renderAvatarBadge: true, discussions: [{ ...discussionsMockData }] }); + createComponent({ renderAvatarBadge: true }); + const noteableDiscussion = wrapper.find(NoteableDiscussion); - expect(vm.$el.querySelector('.user-avatar-link .badge-pill')).not.toBe(null); - expect(vm.$el.querySelector('.user-avatar-link .badge-pill').textContent.trim()).toBe('1'); + expect(noteableDiscussion.find('.badge-pill').exists()).toBe(true); + expect( + noteableDiscussion + .find('.badge-pill') + .text() + .trim(), + ).toBe('1'); }); }); }); diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js index 3304c79cdb7..efa864e7d00 100644 --- a/spec/javascripts/notes/components/noteable_discussion_spec.js +++ b/spec/javascripts/notes/components/noteable_discussion_spec.js @@ -130,29 +130,6 @@ describe('noteable_discussion component', () => { }); }); - describe('componentData', () => { - it('should return first note object for placeholder note', () => { - const data = { - isPlaceholderNote: true, - notes: [{ body: 'hello world!' }], - }; - - const note = wrapper.vm.componentData(data); - - expect(note).toEqual(data.notes[0]); - }); - - it('should return given note for nonplaceholder notes', () => { - const data = { - notes: [{ id: 12 }], - }; - - const note = wrapper.vm.componentData(data); - - expect(note).toEqual(data); - }); - }); - describe('action text', () => { const commitId = 'razupaltuff'; const truncatedCommitId = commitId.substr(0, 8);