2020-10-24 23:57:45 +05:30
|
|
|
import { getByRole } from '@testing-library/dom';
|
2021-03-11 19:13:27 +05:30
|
|
|
import { shallowMount } from '@vue/test-utils';
|
2019-07-31 22:56:46 +05:30
|
|
|
import '~/behaviors/markdown/render_gfm';
|
|
|
|
import DiscussionNotes from '~/notes/components/discussion_notes.vue';
|
|
|
|
import NoteableNote from '~/notes/components/noteable_note.vue';
|
2021-03-11 19:13:27 +05:30
|
|
|
import { SYSTEM_NOTE } from '~/notes/constants';
|
|
|
|
import createStore from '~/notes/stores';
|
2019-07-31 22:56:46 +05:30
|
|
|
import PlaceholderNote from '~/vue_shared/components/notes/placeholder_note.vue';
|
|
|
|
import PlaceholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue';
|
|
|
|
import SystemNote from '~/vue_shared/components/notes/system_note.vue';
|
2020-05-24 23:13:21 +05:30
|
|
|
import { noteableDataMock, discussionMock, notesDataMock } from '../mock_data';
|
2019-07-31 22:56:46 +05:30
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
const LINE_RANGE = {};
|
|
|
|
const DISCUSSION_WITH_LINE_RANGE = {
|
|
|
|
...discussionMock,
|
|
|
|
position: {
|
|
|
|
line_range: LINE_RANGE,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2019-07-31 22:56:46 +05:30
|
|
|
describe('DiscussionNotes', () => {
|
2020-10-24 23:57:45 +05:30
|
|
|
let store;
|
2019-07-31 22:56:46 +05:30
|
|
|
let wrapper;
|
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
const getList = () => getByRole(wrapper.element, 'list');
|
2021-03-11 19:13:27 +05:30
|
|
|
const createComponent = (props) => {
|
2019-09-04 21:01:54 +05:30
|
|
|
wrapper = shallowMount(DiscussionNotes, {
|
2019-07-31 22:56:46 +05:30
|
|
|
store,
|
|
|
|
propsData: {
|
|
|
|
discussion: discussionMock,
|
|
|
|
isExpanded: false,
|
|
|
|
shouldGroupReplies: false,
|
|
|
|
...props,
|
|
|
|
},
|
|
|
|
scopedSlots: {
|
|
|
|
footer: '<p slot-scope="{ showReplies }">showReplies:{{showReplies}}</p>',
|
|
|
|
},
|
|
|
|
slots: {
|
|
|
|
'avatar-badge': '<span class="avatar-badge-slot-content" />',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
store = createStore();
|
|
|
|
store.dispatch('setNoteableData', noteableDataMock);
|
|
|
|
store.dispatch('setNotesData', notesDataMock);
|
|
|
|
});
|
|
|
|
|
2019-07-31 22:56:46 +05:30
|
|
|
afterEach(() => {
|
|
|
|
wrapper.destroy();
|
2020-10-24 23:57:45 +05:30
|
|
|
wrapper = null;
|
2019-07-31 22:56:46 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
describe('rendering', () => {
|
|
|
|
it('renders an element for each note in the discussion', () => {
|
|
|
|
createComponent();
|
|
|
|
const notesCount = discussionMock.notes.length;
|
2020-03-13 15:44:24 +05:30
|
|
|
const els = wrapper.findAll(NoteableNote);
|
2019-07-31 22:56:46 +05:30
|
|
|
expect(els.length).toBe(notesCount);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders one element if replies groupping is enabled', () => {
|
|
|
|
createComponent({ shouldGroupReplies: true });
|
2020-03-13 15:44:24 +05:30
|
|
|
const els = wrapper.findAll(NoteableNote);
|
2019-07-31 22:56:46 +05:30
|
|
|
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;
|
2019-09-30 21:07:59 +05:30
|
|
|
createComponent({ discussion, shouldRenderDiffs: true });
|
2020-03-13 15:44:24 +05:30
|
|
|
const notes = wrapper.findAll('.notes > *');
|
2019-07-31 22:56:46 +05:30
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-09-30 21:07:59 +05:30
|
|
|
describe('events', () => {
|
|
|
|
describe('with groupped notes and replies expanded', () => {
|
2021-03-08 18:12:59 +05:30
|
|
|
const findNoteAtIndex = (index) => {
|
2020-03-13 15:44:24 +05:30
|
|
|
const noteComponents = [NoteableNote, SystemNote, PlaceholderNote, PlaceholderSystemNote];
|
|
|
|
return wrapper
|
|
|
|
.findAll('.notes *')
|
2021-03-08 18:12:59 +05:30
|
|
|
.filter((w) => noteComponents.some((Component) => w.is(Component)))
|
2020-03-13 15:44:24 +05:30
|
|
|
.at(index);
|
|
|
|
};
|
2019-09-30 21:07:59 +05:30
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({ shouldGroupReplies: true, isExpanded: true });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits deleteNote when first note emits handleDeleteNote', () => {
|
|
|
|
findNoteAtIndex(0).vm.$emit('handleDeleteNote');
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
return wrapper.vm.$nextTick().then(() => {
|
|
|
|
expect(wrapper.emitted().deleteNote).toBeTruthy();
|
|
|
|
});
|
2019-09-30 21:07:59 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
it('emits startReplying when first note emits startReplying', () => {
|
|
|
|
findNoteAtIndex(0).vm.$emit('startReplying');
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
return wrapper.vm.$nextTick().then(() => {
|
|
|
|
expect(wrapper.emitted().startReplying).toBeTruthy();
|
|
|
|
});
|
2019-09-30 21:07:59 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
it('emits deleteNote when second note emits handleDeleteNote', () => {
|
|
|
|
findNoteAtIndex(1).vm.$emit('handleDeleteNote');
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
return wrapper.vm.$nextTick().then(() => {
|
|
|
|
expect(wrapper.emitted().deleteNote).toBeTruthy();
|
|
|
|
});
|
2019-09-30 21:07:59 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with ungroupped notes', () => {
|
|
|
|
let note;
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent();
|
2020-03-13 15:44:24 +05:30
|
|
|
note = wrapper.find('.notes > *');
|
2019-09-30 21:07:59 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
it('emits deleteNote when first note emits handleDeleteNote', () => {
|
|
|
|
note.vm.$emit('handleDeleteNote');
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
return wrapper.vm.$nextTick().then(() => {
|
|
|
|
expect(wrapper.emitted().deleteNote).toBeTruthy();
|
|
|
|
});
|
2019-09-30 21:07:59 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-10-24 23:57:45 +05:30
|
|
|
describe.each`
|
2021-03-11 19:13:27 +05:30
|
|
|
desc | props | event | expectedCalls
|
|
|
|
${'with `discussion.position`'} | ${{ discussion: DISCUSSION_WITH_LINE_RANGE }} | ${'mouseenter'} | ${[['setSelectedCommentPositionHover', LINE_RANGE]]}
|
|
|
|
${'with `discussion.position`'} | ${{ discussion: DISCUSSION_WITH_LINE_RANGE }} | ${'mouseleave'} | ${[['setSelectedCommentPositionHover']]}
|
|
|
|
${'without `discussion.position`'} | ${{}} | ${'mouseenter'} | ${[]}
|
|
|
|
${'without `discussion.position`'} | ${{}} | ${'mouseleave'} | ${[]}
|
|
|
|
`('$desc', ({ props, event, expectedCalls }) => {
|
2020-10-24 23:57:45 +05:30
|
|
|
beforeEach(() => {
|
2021-03-11 19:13:27 +05:30
|
|
|
createComponent(props);
|
2020-10-24 23:57:45 +05:30
|
|
|
jest.spyOn(store, 'dispatch');
|
|
|
|
});
|
|
|
|
|
|
|
|
it(`calls store ${expectedCalls.length} times on ${event}`, () => {
|
|
|
|
getList().dispatchEvent(new MouseEvent(event));
|
|
|
|
expect(store.dispatch.mock.calls).toEqual(expectedCalls);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-07-31 22:56:46 +05:30
|
|
|
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);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|