diff options
Diffstat (limited to 'spec/frontend/work_items/components/work_item_description_spec.js')
-rw-r--r-- | spec/frontend/work_items/components/work_item_description_spec.js | 295 |
1 files changed, 163 insertions, 132 deletions
diff --git a/spec/frontend/work_items/components/work_item_description_spec.js b/spec/frontend/work_items/components/work_item_description_spec.js index 0691fe25e0d..c79b049442d 100644 --- a/spec/frontend/work_items/components/work_item_description_spec.js +++ b/spec/frontend/work_items/components/work_item_description_spec.js @@ -8,21 +8,23 @@ import EditedAt from '~/issues/show/components/edited.vue'; import { updateDraft } from '~/lib/utils/autosave'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; import MarkdownField from '~/vue_shared/components/markdown/field.vue'; +import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; import WorkItemDescription from '~/work_items/components/work_item_description.vue'; +import WorkItemDescriptionRendered from '~/work_items/components/work_item_description_rendered.vue'; import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants'; import workItemQuery from '~/work_items/graphql/work_item.query.graphql'; +import workItemDescriptionSubscription from '~/work_items/graphql/work_item_description.subscription.graphql'; import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql'; +import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql'; import { updateWorkItemMutationResponse, + workItemDescriptionSubscriptionResponse, workItemResponseFactory, workItemQueryResponse, + projectWorkItemResponse, } from '../mock_data'; -jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => { - return { - confirmAction: jest.fn(), - }; -}); +jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'); jest.mock('~/lib/utils/autosave'); const workItemId = workItemQueryResponse.data.workItem.id; @@ -33,12 +35,22 @@ describe('WorkItemDescription', () => { Vue.use(VueApollo); const mutationSuccessHandler = jest.fn().mockResolvedValue(updateWorkItemMutationResponse); + const subscriptionHandler = jest.fn().mockResolvedValue(workItemDescriptionSubscriptionResponse); + const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse); + let workItemResponseHandler; + let workItemsMvc2; - const findEditButton = () => wrapper.find('[data-testid="edit-description"]'); const findMarkdownField = () => wrapper.findComponent(MarkdownField); + const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor); + const findRenderedDescription = () => wrapper.findComponent(WorkItemDescriptionRendered); const findEditedAt = () => wrapper.findComponent(EditedAt); - const editDescription = (newText) => wrapper.find('textarea').setValue(newText); + const editDescription = (newText) => { + if (workItemsMvc2) { + return findMarkdownEditor().vm.$emit('input', newText); + } + return wrapper.find('textarea').setValue(newText); + }; const clickCancel = () => wrapper.find('[data-testid="cancel"]').vm.$emit('click'); const clickSave = () => wrapper.find('[data-testid="save-description"]').vm.$emit('click', {}); @@ -48,18 +60,30 @@ describe('WorkItemDescription', () => { canUpdate = true, workItemResponse = workItemResponseFactory({ canUpdate }), isEditing = false, + fetchByIid = false, } = {}) => { - const workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse); + workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse); const { id } = workItemQueryResponse.data.workItem; wrapper = shallowMount(WorkItemDescription, { apolloProvider: createMockApollo([ [workItemQuery, workItemResponseHandler], [updateWorkItemMutation, mutationHandler], + [workItemDescriptionSubscription, subscriptionHandler], + [workItemByIidQuery, workItemByIidResponseHandler], ]), propsData: { workItemId: id, fullPath: 'test-project-path', + queryVariables: { + id: workItemId, + }, + fetchByIid, + }, + provide: { + glFeatures: { + workItemsMvc2, + }, }, stubs: { MarkdownField, @@ -69,7 +93,7 @@ describe('WorkItemDescription', () => { await waitForPromises(); if (isEditing) { - findEditButton().vm.$emit('click'); + findRenderedDescription().vm.$emit('startEditing'); await nextTick(); } @@ -79,171 +103,178 @@ describe('WorkItemDescription', () => { wrapper.destroy(); }); - describe('Edit button', () => { - it('is not visible when canUpdate = false', async () => { - await createComponent({ - canUpdate: false, + describe.each([true, false])( + 'editing description with workItemsMvc2 %workItemsMvc2Enabled', + (workItemsMvc2Enabled) => { + beforeEach(() => { + beforeEach(() => { + workItemsMvc2 = workItemsMvc2Enabled; + }); }); - expect(findEditButton().exists()).toBe(false); - }); + describe('editing description', () => { + it('shows edited by text', async () => { + const lastEditedAt = '2022-09-21T06:18:42Z'; + const lastEditedBy = { + name: 'Administrator', + webPath: '/root', + }; - it('toggles edit mode', async () => { - await createComponent({ - canUpdate: true, - }); + await createComponent({ + workItemResponse: workItemResponseFactory({ + lastEditedAt, + lastEditedBy, + }), + }); - findEditButton().vm.$emit('click'); + expect(findEditedAt().props()).toEqual({ + updatedAt: lastEditedAt, + updatedByName: lastEditedBy.name, + updatedByPath: lastEditedBy.webPath, + }); + }); - await nextTick(); + it('does not show edited by text', async () => { + await createComponent(); - expect(findMarkdownField().exists()).toBe(true); - }); - }); + expect(findEditedAt().exists()).toBe(false); + }); - describe('editing description', () => { - it('shows edited by text', async () => { - const lastEditedAt = '2022-09-21T06:18:42Z'; - const lastEditedBy = { - name: 'Administrator', - webPath: '/root', - }; - - await createComponent({ - workItemResponse: workItemResponseFactory({ - lastEditedAt, - lastEditedBy, - }), - }); + it('cancels when clicking cancel', async () => { + await createComponent({ + isEditing: true, + }); - expect(findEditedAt().props()).toEqual({ - updatedAt: lastEditedAt, - updatedByName: lastEditedBy.name, - updatedByPath: lastEditedBy.webPath, - }); - }); + clickCancel(); - it('does not show edited by text', async () => { - await createComponent(); + await nextTick(); - expect(findEditedAt().exists()).toBe(false); - }); + expect(confirmAction).not.toHaveBeenCalled(); + expect(findMarkdownField().exists()).toBe(false); + }); - it('cancels when clicking cancel', async () => { - await createComponent({ - isEditing: true, - }); + it('prompts for confirmation when clicking cancel after changes', async () => { + await createComponent({ + isEditing: true, + }); - clickCancel(); + editDescription('updated desc'); - await nextTick(); + clickCancel(); - expect(confirmAction).not.toHaveBeenCalled(); - expect(findMarkdownField().exists()).toBe(false); - }); + await nextTick(); - it('prompts for confirmation when clicking cancel after changes', async () => { - await createComponent({ - isEditing: true, - }); + expect(confirmAction).toHaveBeenCalled(); + }); - editDescription('updated desc'); + it('calls update widgets mutation', async () => { + const updatedDesc = 'updated desc'; - clickCancel(); + await createComponent({ + isEditing: true, + }); - await nextTick(); + editDescription(updatedDesc); - expect(confirmAction).toHaveBeenCalled(); - }); + clickSave(); - it('calls update widgets mutation', async () => { - await createComponent({ - isEditing: true, - }); + await waitForPromises(); - editDescription('updated desc'); + expect(mutationSuccessHandler).toHaveBeenCalledWith({ + input: { + id: workItemId, + descriptionWidget: { + description: updatedDesc, + }, + }, + }); + }); - clickSave(); + it('tracks editing description', async () => { + await createComponent({ + isEditing: true, + markdownPreviewPath: '/preview', + }); + const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); - await waitForPromises(); + clickSave(); - expect(mutationSuccessHandler).toHaveBeenCalledWith({ - input: { - id: workItemId, - descriptionWidget: { - description: 'updated desc', - }, - }, - }); - }); + await waitForPromises(); - it('tracks editing description', async () => { - await createComponent({ - isEditing: true, - markdownPreviewPath: '/preview', - }); - const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_description', { + category: TRACKING_CATEGORY_SHOW, + label: 'item_description', + property: 'type_Task', + }); + }); - clickSave(); + it('emits error when mutation returns error', async () => { + const error = 'eror'; - await waitForPromises(); + await createComponent({ + isEditing: true, + mutationHandler: jest.fn().mockResolvedValue({ + data: { + workItemUpdate: { + workItem: {}, + errors: [error], + }, + }, + }), + }); - expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_description', { - category: TRACKING_CATEGORY_SHOW, - label: 'item_description', - property: 'type_Task', - }); - }); + editDescription('updated desc'); - it('emits error when mutation returns error', async () => { - const error = 'eror'; + clickSave(); - await createComponent({ - isEditing: true, - mutationHandler: jest.fn().mockResolvedValue({ - data: { - workItemUpdate: { - workItem: {}, - errors: [error], - }, - }, - }), - }); + await waitForPromises(); - editDescription('updated desc'); + expect(wrapper.emitted('error')).toEqual([[error]]); + }); - clickSave(); + it('emits error when mutation fails', async () => { + const error = 'eror'; - await waitForPromises(); + await createComponent({ + isEditing: true, + mutationHandler: jest.fn().mockRejectedValue(new Error(error)), + }); - expect(wrapper.emitted('error')).toEqual([[error]]); - }); + editDescription('updated desc'); - it('emits error when mutation fails', async () => { - const error = 'eror'; + clickSave(); - await createComponent({ - isEditing: true, - mutationHandler: jest.fn().mockRejectedValue(new Error(error)), - }); + await waitForPromises(); - editDescription('updated desc'); + expect(wrapper.emitted('error')).toEqual([[error]]); + }); - clickSave(); + it('autosaves description', async () => { + await createComponent({ + isEditing: true, + }); - await waitForPromises(); + editDescription('updated desc'); - expect(wrapper.emitted('error')).toEqual([[error]]); - }); + expect(updateDraft).toHaveBeenCalled(); + }); + }); + + it('calls the global ID work item query when `fetchByIid` prop is false', async () => { + createComponent({ fetchByIid: false }); + await waitForPromises(); - it('autosaves description', async () => { - await createComponent({ - isEditing: true, + expect(workItemResponseHandler).toHaveBeenCalled(); + expect(workItemByIidResponseHandler).not.toHaveBeenCalled(); }); - editDescription('updated desc'); + it('calls the IID work item query when when `fetchByIid` prop is true', async () => { + createComponent({ fetchByIid: true }); + await waitForPromises(); - expect(updateDraft).toHaveBeenCalled(); - }); - }); + expect(workItemResponseHandler).not.toHaveBeenCalled(); + expect(workItemByIidResponseHandler).toHaveBeenCalled(); + }); + }, + ); }); |