diff options
Diffstat (limited to 'spec/frontend/work_items/components/work_item_links')
-rw-r--r-- | spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js | 205 | ||||
-rw-r--r-- | spec/frontend/work_items/components/work_item_links/work_item_links_spec.js | 31 |
2 files changed, 172 insertions, 64 deletions
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js index ab3ea623e3e..071d5fb715a 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js @@ -1,10 +1,11 @@ import Vue from 'vue'; -import { GlForm, GlFormInput, GlFormCombobox } from '@gitlab/ui'; +import { GlForm, GlFormInput, GlTokenSelector } from '@gitlab/ui'; import VueApollo from 'vue-apollo'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import WorkItemLinksForm from '~/work_items/components/work_item_links/work_item_links_form.vue'; +import { FORM_TYPES } from '~/work_items/constants'; import projectWorkItemsQuery from '~/work_items/graphql/project_work_items.query.graphql'; import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql'; import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql'; @@ -14,6 +15,7 @@ import { projectWorkItemTypesQueryResponse, createWorkItemMutationResponse, updateWorkItemMutationResponse, + mockIterationWidgetResponse, } from '../../mock_data'; Vue.use(VueApollo); @@ -23,22 +25,35 @@ describe('WorkItemLinksForm', () => { const updateMutationResolver = jest.fn().mockResolvedValue(updateWorkItemMutationResponse); const createMutationResolver = jest.fn().mockResolvedValue(createWorkItemMutationResponse); + const availableWorkItemsResolver = jest.fn().mockResolvedValue(availableWorkItemsResponse); + + const mockParentIteration = mockIterationWidgetResponse; const createComponent = async ({ - listResponse = availableWorkItemsResponse, typesResponse = projectWorkItemTypesQueryResponse, parentConfidential = false, hasIterationsFeature = false, + workItemsMvc2Enabled = false, + parentIteration = null, + formType = FORM_TYPES.create, } = {}) => { wrapper = shallowMountExtended(WorkItemLinksForm, { apolloProvider: createMockApollo([ - [projectWorkItemsQuery, jest.fn().mockResolvedValue(listResponse)], + [projectWorkItemsQuery, availableWorkItemsResolver], [projectWorkItemTypesQuery, jest.fn().mockResolvedValue(typesResponse)], [updateWorkItemMutation, updateMutationResolver], [createWorkItemMutation, createMutationResolver], ]), - propsData: { issuableGid: 'gid://gitlab/WorkItem/1', parentConfidential }, + propsData: { + issuableGid: 'gid://gitlab/WorkItem/1', + parentConfidential, + parentIteration, + formType, + }, provide: { + glFeatures: { + workItemsMvc2: workItemsMvc2Enabled, + }, projectPath: 'project/path', hasIterationsFeature, }, @@ -48,89 +63,155 @@ describe('WorkItemLinksForm', () => { }; const findForm = () => wrapper.findComponent(GlForm); - const findCombobox = () => wrapper.findComponent(GlFormCombobox); + const findTokenSelector = () => wrapper.findComponent(GlTokenSelector); const findInput = () => wrapper.findComponent(GlFormInput); const findAddChildButton = () => wrapper.findByTestId('add-child-button'); - beforeEach(async () => { - await createComponent(); - }); - afterEach(() => { wrapper.destroy(); }); - it('renders form', () => { - expect(findForm().exists()).toBe(true); - }); - - it('creates child task in non confidential parent', async () => { - findInput().vm.$emit('input', 'Create task test'); + describe('creating a new work item', () => { + beforeEach(async () => { + await createComponent(); + }); - findForm().vm.$emit('submit', { - preventDefault: jest.fn(), + it('renders create form', () => { + expect(findForm().exists()).toBe(true); + expect(findInput().exists()).toBe(true); + expect(findAddChildButton().text()).toBe('Create task'); + expect(findTokenSelector().exists()).toBe(false); }); - await waitForPromises(); - expect(createMutationResolver).toHaveBeenCalledWith({ - input: { - title: 'Create task test', - projectPath: 'project/path', - workItemTypeId: 'gid://gitlab/WorkItems::Type/3', - hierarchyWidget: { - parentId: 'gid://gitlab/WorkItem/1', + + it('creates child task in non confidential parent', async () => { + findInput().vm.$emit('input', 'Create task test'); + + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(createMutationResolver).toHaveBeenCalledWith({ + input: { + title: 'Create task test', + projectPath: 'project/path', + workItemTypeId: 'gid://gitlab/WorkItems::Type/3', + hierarchyWidget: { + parentId: 'gid://gitlab/WorkItem/1', + }, + confidential: false, }, - confidential: false, - }, + }); }); - }); - it('creates child task in confidential parent', async () => { - await createComponent({ parentConfidential: true }); + it('creates child task in confidential parent', async () => { + await createComponent({ parentConfidential: true }); - findInput().vm.$emit('input', 'Create confidential task'); + findInput().vm.$emit('input', 'Create confidential task'); - findForm().vm.$emit('submit', { - preventDefault: jest.fn(), - }); - await waitForPromises(); - expect(createMutationResolver).toHaveBeenCalledWith({ - input: { - title: 'Create confidential task', - projectPath: 'project/path', - workItemTypeId: 'gid://gitlab/WorkItems::Type/3', - hierarchyWidget: { - parentId: 'gid://gitlab/WorkItem/1', + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(createMutationResolver).toHaveBeenCalledWith({ + input: { + title: 'Create confidential task', + projectPath: 'project/path', + workItemTypeId: 'gid://gitlab/WorkItems::Type/3', + hierarchyWidget: { + parentId: 'gid://gitlab/WorkItem/1', + }, + confidential: true, }, - confidential: true, - }, + }); }); }); - // Follow up issue to turn this functionality back on https://gitlab.com/gitlab-org/gitlab/-/issues/368757 - // eslint-disable-next-line jest/no-disabled-tests - it.skip('selects and add child', async () => { - findCombobox().vm.$emit('input', availableWorkItemsResponse.data.workspace.workItems.edges[0]); + describe('adding an existing work item', () => { + beforeEach(async () => { + await createComponent({ formType: FORM_TYPES.add }); + }); - findAddChildButton().vm.$emit('click'); - await waitForPromises(); - expect(updateMutationResolver).toHaveBeenCalled(); - }); + it('renders add form', () => { + expect(findForm().exists()).toBe(true); + expect(findTokenSelector().exists()).toBe(true); + expect(findAddChildButton().text()).toBe('Add task'); + expect(findInput().exists()).toBe(false); + }); - // eslint-disable-next-line jest/no-disabled-tests - describe.skip('when typing in combobox', () => { - beforeEach(async () => { - findCombobox().vm.$emit('input', 'Task'); + it('searches for available work items as prop when typing in input', async () => { + findTokenSelector().vm.$emit('focus'); + findTokenSelector().vm.$emit('text-input', 'Task'); await waitForPromises(); - await jest.runOnlyPendingTimers(); + + expect(availableWorkItemsResolver).toHaveBeenCalled(); }); - it('passes available work items as prop', () => { - expect(findCombobox().exists()).toBe(true); - expect(findCombobox().props('tokenList').length).toBe(2); + it('selects and adds children', async () => { + findTokenSelector().vm.$emit( + 'input', + availableWorkItemsResponse.data.workspace.workItems.nodes, + ); + findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null })); + + await waitForPromises(); + + expect(findAddChildButton().text()).toBe('Add tasks'); + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(updateMutationResolver).toHaveBeenCalled(); }); + }); + + describe('associate iteration with task', () => { + it('does not update iteration when mvc2 feature flag is not enabled', async () => { + await createComponent({ + hasIterationsFeature: true, + parentIteration: mockParentIteration, + }); - it('passes action to create task', () => { - expect(findCombobox().props('actionList').length).toBe(1); + findInput().vm.$emit('input', 'Create task test'); + + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(updateMutationResolver).not.toHaveBeenCalled(); + }); + it('updates when parent has an iteration associated', async () => { + await createComponent({ + workItemsMvc2Enabled: true, + hasIterationsFeature: true, + parentIteration: mockParentIteration, + }); + findInput().vm.$emit('input', 'Create task test'); + + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(updateMutationResolver).toHaveBeenCalledWith({ + input: { + id: 'gid://gitlab/WorkItem/1', + iterationWidget: { + iterationId: mockParentIteration.id, + }, + }, + }); + }); + it('does not update when parent has no iteration associated', async () => { + await createComponent({ + workItemsMvc2Enabled: true, + hasIterationsFeature: true, + }); + findInput().vm.$emit('input', 'Create task test'); + + findForm().vm.$emit('submit', { + preventDefault: jest.fn(), + }); + await waitForPromises(); + expect(updateMutationResolver).not.toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js index 6961996f912..66ce2c1becf 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js @@ -8,6 +8,7 @@ import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import issueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql'; import WorkItemLinks from '~/work_items/components/work_item_links/work_item_links.vue'; import WorkItemLinkChild from '~/work_items/components/work_item_links/work_item_link_child.vue'; +import { FORM_TYPES } from '~/work_items/constants'; import workItemQuery from '~/work_items/graphql/work_item.query.graphql'; import changeWorkItemParentMutation from '~/work_items/graphql/update_work_item.mutation.graphql'; import getWorkItemLinksQuery from '~/work_items/graphql/work_item_links.query.graphql'; @@ -41,6 +42,13 @@ const issueDetailsResponse = (confidential = false) => ({ }, __typename: 'Iteration', }, + milestone: { + dueDate: null, + expired: false, + id: 'gid://gitlab/Milestone/28', + title: 'v2.0', + __typename: 'Milestone', + }, __typename: 'Issue', }, __typename: 'Project', @@ -107,7 +115,9 @@ describe('WorkItemLinks', () => { const findToggleButton = () => wrapper.findByTestId('toggle-links'); const findLinksBody = () => wrapper.findByTestId('links-body'); const findEmptyState = () => wrapper.findByTestId('links-empty'); + const findToggleFormDropdown = () => wrapper.findByTestId('toggle-form'); const findToggleAddFormButton = () => wrapper.findByTestId('toggle-add-form'); + const findToggleCreateFormButton = () => wrapper.findByTestId('toggle-create-form'); const findWorkItemLinkChildItems = () => wrapper.findAllComponents(WorkItemLinkChild); const findFirstWorkItemLinkChild = () => findWorkItemLinkChildItems().at(0); const findAddLinksForm = () => wrapper.findByTestId('add-links-form'); @@ -136,11 +146,27 @@ describe('WorkItemLinks', () => { }); describe('add link form', () => { - it('displays form on click add button and hides form on cancel', async () => { + it('displays add work item form on click add dropdown then add existing button and hides form on cancel', async () => { + findToggleFormDropdown().vm.$emit('click'); findToggleAddFormButton().vm.$emit('click'); await nextTick(); expect(findAddLinksForm().exists()).toBe(true); + expect(findAddLinksForm().props('formType')).toBe(FORM_TYPES.add); + + findAddLinksForm().vm.$emit('cancel'); + await nextTick(); + + expect(findAddLinksForm().exists()).toBe(false); + }); + + it('displays create work item form on click add dropdown then create button and hides form on cancel', async () => { + findToggleFormDropdown().vm.$emit('click'); + findToggleCreateFormButton().vm.$emit('click'); + await nextTick(); + + expect(findAddLinksForm().exists()).toBe(true); + expect(findAddLinksForm().props('formType')).toBe(FORM_TYPES.create); findAddLinksForm().vm.$emit('cancel'); await nextTick(); @@ -193,7 +219,7 @@ describe('WorkItemLinks', () => { }); it('does not display button to toggle Add form', () => { - expect(findToggleAddFormButton().exists()).toBe(false); + expect(findToggleFormDropdown().exists()).toBe(false); }); it('does not display link menu on children', () => { @@ -283,6 +309,7 @@ describe('WorkItemLinks', () => { await createComponent({ issueDetailsQueryHandler: jest.fn().mockResolvedValue(issueDetailsResponse(true)), }); + findToggleFormDropdown().vm.$emit('click'); findToggleAddFormButton().vm.$emit('click'); await nextTick(); |