2020-06-03 14:08:28 -04:00
|
|
|
import { shallowMount } from '@vue/test-utils';
|
|
|
|
import { GlCollapse, GlPopover } from '@gitlab/ui';
|
|
|
|
import Cookies from 'js-cookie';
|
|
|
|
import DesignSidebar from '~/design_management/components/design_sidebar.vue';
|
|
|
|
import Participants from '~/sidebar/components/participants/participants.vue';
|
|
|
|
import DesignDiscussion from '~/design_management/components/design_notes/design_discussion.vue';
|
|
|
|
import updateActiveDiscussionMutation from '~/design_management/graphql/mutations/update_active_discussion.mutation.graphql';
|
2020-09-09 05:08:40 -04:00
|
|
|
import DesignTodoButton from '~/design_management/components/design_todo_button.vue';
|
2021-02-01 10:08:56 -05:00
|
|
|
import design from '../mock_data/design';
|
2020-06-03 14:08:28 -04:00
|
|
|
|
2020-08-27 02:10:37 -04:00
|
|
|
const scrollIntoViewMock = jest.fn();
|
|
|
|
HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
|
|
|
|
|
2020-06-03 14:08:28 -04:00
|
|
|
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"]');
|
|
|
|
|
2020-10-12 17:08:56 -04:00
|
|
|
function createComponent(props = {}) {
|
2020-06-03 14:08:28 -04:00
|
|
|
wrapper = shallowMount(DesignSidebar, {
|
|
|
|
propsData: {
|
|
|
|
design,
|
|
|
|
resolvedDiscussionsExpanded: false,
|
|
|
|
markdownPreviewPath: '',
|
|
|
|
...props,
|
|
|
|
},
|
|
|
|
mocks: {
|
|
|
|
$route,
|
|
|
|
$apollo: {
|
|
|
|
mutate,
|
|
|
|
},
|
|
|
|
},
|
2020-08-27 02:10:37 -04:00
|
|
|
stubs: { GlPopover },
|
2020-06-03 14:08:28 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
2020-10-12 17:08:56 -04:00
|
|
|
it('renders To-Do button', () => {
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
expect(wrapper.find(DesignTodoButton).exists()).toBe(true);
|
|
|
|
});
|
|
|
|
|
2020-06-03 14:08:28 -04:00
|
|
|
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', () => {
|
2020-09-09 17:08:33 -04:00
|
|
|
findFirstDiscussion().vm.$emit('create-note-error', 'payload');
|
2020-06-03 14:08:28 -04:00
|
|
|
expect(wrapper.emitted('onDesignDiscussionError')).toEqual([['payload']]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits correct event on discussion update note error', () => {
|
2020-09-09 17:08:33 -04:00
|
|
|
findFirstDiscussion().vm.$emit('update-note-error', 'payload');
|
2020-06-03 14:08:28 -04:00
|
|
|
expect(wrapper.emitted('updateNoteError')).toEqual([['payload']]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits correct event on discussion resolve error', () => {
|
2020-09-09 17:08:33 -04:00
|
|
|
findFirstDiscussion().vm.$emit('resolve-discussion-error', 'payload');
|
2020-06-03 14:08:28 -04:00
|
|
|
expect(wrapper.emitted('resolveDiscussionError')).toEqual([['payload']]);
|
|
|
|
});
|
2020-06-04 11:08:21 -04:00
|
|
|
|
|
|
|
it('changes prop correctly on opening discussion form', () => {
|
2020-09-09 17:08:33 -04:00
|
|
|
findFirstDiscussion().vm.$emit('open-form', 'some-id');
|
2020-06-04 11:08:21 -04:00
|
|
|
|
|
|
|
return wrapper.vm.$nextTick().then(() => {
|
|
|
|
expect(findFirstDiscussion().props('discussionWithOpenForm')).toBe('some-id');
|
|
|
|
});
|
|
|
|
});
|
2020-06-03 14:08:28 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
2020-08-27 02:10:37 -04:00
|
|
|
it('scrolls to resolved threads link', () => {
|
|
|
|
expect(scrollIntoViewMock).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2020-06-03 14:08:28 -04:00
|
|
|
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 });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|