summaryrefslogtreecommitdiff
path: root/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/work_items/components/notes/work_item_discussion_spec.js')
-rw-r--r--spec/frontend/work_items/components/notes/work_item_discussion_spec.js149
1 files changed, 149 insertions, 0 deletions
diff --git a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
new file mode 100644
index 00000000000..bb65b75c4d8
--- /dev/null
+++ b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
@@ -0,0 +1,149 @@
+import { GlAvatarLink, GlAvatar } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
+import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
+import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
+import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
+import WorkItemNoteReplying from '~/work_items/components/notes/work_item_note_replying.vue';
+import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
+import {
+ mockWorkItemCommentNote,
+ mockWorkItemNotesResponseWithComments,
+} from 'jest/work_items/mock_data';
+import { WIDGET_TYPE_NOTES } from '~/work_items/constants';
+
+const mockWorkItemNotesWidgetResponseWithComments = mockWorkItemNotesResponseWithComments.data.workItem.widgets.find(
+ (widget) => widget.type === WIDGET_TYPE_NOTES,
+);
+
+describe('Work Item Discussion', () => {
+ let wrapper;
+ const mockWorkItemId = 'gid://gitlab/WorkItem/625';
+
+ const findTimelineEntryItem = () => wrapper.findComponent(TimelineEntryItem);
+ const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
+ const findAvatar = () => wrapper.findComponent(GlAvatar);
+ const findToggleRepliesWidget = () => wrapper.findComponent(ToggleRepliesWidget);
+ const findAllThreads = () => wrapper.findAllComponents(WorkItemNote);
+ const findThreadAtIndex = (index) => findAllThreads().at(index);
+ const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
+ const findWorkItemNoteReplying = () => wrapper.findComponent(WorkItemNoteReplying);
+
+ const createComponent = ({
+ discussion = [mockWorkItemCommentNote],
+ workItemId = mockWorkItemId,
+ queryVariables = { id: workItemId },
+ fetchByIid = false,
+ fullPath = 'gitlab-org',
+ workItemType = 'Task',
+ } = {}) => {
+ wrapper = shallowMount(WorkItemDiscussion, {
+ propsData: {
+ discussion,
+ workItemId,
+ queryVariables,
+ fetchByIid,
+ fullPath,
+ workItemType,
+ },
+ });
+ };
+
+ describe('Default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('Should be wrapped inside the timeline entry item', () => {
+ expect(findTimelineEntryItem().exists()).toBe(true);
+ });
+
+ it('should have the author avatar of the work item note', () => {
+ expect(findAvatarLink().exists()).toBe(true);
+ expect(findAvatarLink().attributes('href')).toBe(mockWorkItemCommentNote.author.webUrl);
+
+ expect(findAvatar().exists()).toBe(true);
+ expect(findAvatar().props('src')).toBe(mockWorkItemCommentNote.author.avatarUrl);
+ expect(findAvatar().props('entityName')).toBe(mockWorkItemCommentNote.author.username);
+ });
+
+ it('should not show the the toggle replies widget wrapper when no replies', () => {
+ expect(findToggleRepliesWidget().exists()).toBe(false);
+ });
+
+ it('should not show the comment form by default', () => {
+ expect(findWorkItemAddNote().exists()).toBe(false);
+ });
+ });
+
+ describe('When the main comments has threads', () => {
+ beforeEach(() => {
+ createComponent({
+ discussion: mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[0].notes.nodes,
+ });
+ });
+
+ it('should show the toggle replies widget', () => {
+ expect(findToggleRepliesWidget().exists()).toBe(true);
+ });
+
+ it('the number of threads should be equal to the response length', async () => {
+ findToggleRepliesWidget().vm.$emit('toggle');
+ await nextTick();
+ expect(findAllThreads()).toHaveLength(
+ mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[0].notes.nodes.length,
+ );
+ });
+
+ it('should autofocus when we click expand replies', async () => {
+ const mainComment = findThreadAtIndex(0);
+
+ mainComment.vm.$emit('startReplying');
+ await nextTick();
+ expect(findWorkItemAddNote().exists()).toBe(true);
+ expect(findWorkItemAddNote().props('autofocus')).toBe(true);
+ });
+ });
+
+ describe('When replying to any comment', () => {
+ beforeEach(async () => {
+ createComponent({
+ discussion: mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[0].notes.nodes,
+ });
+ const mainComment = findThreadAtIndex(0);
+
+ mainComment.vm.$emit('startReplying');
+ await nextTick();
+ await findWorkItemAddNote().vm.$emit('replying', 'reply text');
+ });
+
+ it('should show optimistic behavior when replying', async () => {
+ expect(findAllThreads()).toHaveLength(2);
+ expect(findWorkItemNoteReplying().exists()).toBe(true);
+ });
+
+ it('should be expanded when the reply is successful', async () => {
+ findWorkItemAddNote().vm.$emit('replied');
+ await nextTick();
+ expect(findToggleRepliesWidget().exists()).toBe(true);
+ expect(findToggleRepliesWidget().props('collapsed')).toBe(false);
+ });
+ });
+
+ it('emits `deleteNote` event with correct parameter when child note component emits `deleteNote` event', () => {
+ createComponent();
+ findThreadAtIndex(0).vm.$emit('deleteNote');
+
+ expect(wrapper.emitted('deleteNote')).toEqual([[mockWorkItemCommentNote]]);
+ });
+
+ it('emits `error` event when child note emits an `error`', () => {
+ const mockErrorText = 'Houston, we have a problem';
+
+ createComponent();
+ findThreadAtIndex(0).vm.$emit('error', mockErrorText);
+
+ expect(wrapper.emitted('error')).toEqual([[mockErrorText]]);
+ });
+});