summaryrefslogtreecommitdiff
path: root/spec/frontend/work_items
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/work_items')
-rw-r--r--spec/frontend/work_items/components/work_item_assignees_spec.js8
-rw-r--r--spec/frontend/work_items/components/work_item_description_spec.js31
-rw-r--r--spec/frontend/work_items/components/work_item_detail_spec.js100
-rw-r--r--spec/frontend/work_items/components/work_item_due_date_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_labels_spec.js98
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js2
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_spec.js31
-rw-r--r--spec/frontend/work_items/components/work_item_milestone_spec.js247
-rw-r--r--spec/frontend/work_items/components/work_item_type_icon_spec.js2
-rw-r--r--spec/frontend/work_items/mock_data.js273
-rw-r--r--spec/frontend/work_items/router_spec.js10
12 files changed, 734 insertions, 76 deletions
diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js
index 28231fad108..1b204b6fd60 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -157,6 +157,14 @@ describe('WorkItemAssignees component', () => {
expect(findTokenSelector().props('viewOnly')).toBe(true);
});
+ it('has a label', () => {
+ createComponent();
+
+ expect(findTokenSelector().props('ariaLabelledby')).toEqual(
+ findAssigneesTitle().attributes('id'),
+ );
+ });
+
describe('when clicking outside the token selector', () => {
function arrange(args) {
createComponent(args);
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 d3165d8dc26..0691fe25e0d 100644
--- a/spec/frontend/work_items/components/work_item_description_spec.js
+++ b/spec/frontend/work_items/components/work_item_description_spec.js
@@ -4,6 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
+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';
@@ -35,6 +36,7 @@ describe('WorkItemDescription', () => {
const findEditButton = () => wrapper.find('[data-testid="edit-description"]');
const findMarkdownField = () => wrapper.findComponent(MarkdownField);
+ const findEditedAt = () => wrapper.findComponent(EditedAt);
const editDescription = (newText) => wrapper.find('textarea').setValue(newText);
@@ -44,9 +46,9 @@ describe('WorkItemDescription', () => {
const createComponent = async ({
mutationHandler = mutationSuccessHandler,
canUpdate = true,
+ workItemResponse = workItemResponseFactory({ canUpdate }),
isEditing = false,
} = {}) => {
- const workItemResponse = workItemResponseFactory({ canUpdate });
const workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse);
const { id } = workItemQueryResponse.data.workItem;
@@ -100,6 +102,33 @@ describe('WorkItemDescription', () => {
});
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,
+ }),
+ });
+
+ expect(findEditedAt().props()).toEqual({
+ updatedAt: lastEditedAt,
+ updatedByName: lastEditedBy.name,
+ updatedByPath: lastEditedBy.webPath,
+ });
+ });
+
+ it('does not show edited by text', async () => {
+ await createComponent();
+
+ expect(findEditedAt().exists()).toBe(false);
+ });
+
it('cancels when clicking cancel', async () => {
await createComponent({
isEditing: true,
diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js
index b047e0dc8d7..aae61b11196 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -1,8 +1,14 @@
-import { GlAlert, GlBadge, GlLoadingIcon, GlSkeletonLoader, GlButton } from '@gitlab/ui';
+import {
+ GlAlert,
+ GlBadge,
+ GlLoadingIcon,
+ GlSkeletonLoader,
+ GlButton,
+ GlEmptyState,
+} from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-import workItemWeightSubscription from 'ee_component/work_items/graphql/work_item_weight.subscription.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
@@ -14,11 +20,13 @@ import WorkItemState from '~/work_items/components/work_item_state.vue';
import WorkItemTitle from '~/work_items/components/work_item_title.vue';
import WorkItemAssignees from '~/work_items/components/work_item_assignees.vue';
import WorkItemLabels from '~/work_items/components/work_item_labels.vue';
+import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
import WorkItemInformation from '~/work_items/components/work_item_information.vue';
import { i18n } from '~/work_items/constants';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subscription.graphql';
import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql';
+import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import updateWorkItemTaskMutation from '~/work_items/graphql/update_work_item_task.mutation.graphql';
import { temporaryConfig } from '~/graphql_shared/issuable_client';
@@ -28,7 +36,7 @@ import {
workItemDatesSubscriptionResponse,
workItemResponseFactory,
workItemTitleSubscriptionResponse,
- workItemWeightSubscriptionResponse,
+ workItemAssigneesSubscriptionResponse,
} from '../mock_data';
describe('WorkItemDetail component', () => {
@@ -46,9 +54,12 @@ describe('WorkItemDetail component', () => {
const successHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse);
const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse);
- const weightSubscriptionHandler = jest.fn().mockResolvedValue(workItemWeightSubscriptionResponse);
+ const assigneesSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemAssigneesSubscriptionResponse);
const findAlert = () => wrapper.findComponent(GlAlert);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findWorkItemActions = () => wrapper.findComponent(WorkItemActions);
@@ -58,6 +69,7 @@ describe('WorkItemDetail component', () => {
const findWorkItemDueDate = () => wrapper.findComponent(WorkItemDueDate);
const findWorkItemAssignees = () => wrapper.findComponent(WorkItemAssignees);
const findWorkItemLabels = () => wrapper.findComponent(WorkItemLabels);
+ const findWorkItemMilestone = () => wrapper.findComponent(WorkItemMilestone);
const findParent = () => wrapper.find('[data-testid="work-item-parent"]');
const findParentButton = () => findParent().findComponent(GlButton);
const findCloseButton = () => wrapper.find('[data-testid="work-item-close"]');
@@ -72,21 +84,18 @@ describe('WorkItemDetail component', () => {
handler = successHandler,
subscriptionHandler = titleSubscriptionHandler,
confidentialityMock = [updateWorkItemMutation, jest.fn()],
- workItemsMvc2Enabled = false,
- includeWidgets = false,
error = undefined,
+ includeWidgets = false,
+ workItemsMvc2Enabled = false,
} = {}) => {
const handlers = [
[workItemQuery, handler],
[workItemTitleSubscription, subscriptionHandler],
[workItemDatesSubscription, datesSubscriptionHandler],
+ [workItemAssigneesSubscription, assigneesSubscriptionHandler],
confidentialityMock,
];
- if (IS_EE) {
- handlers.push([workItemWeightSubscription, weightSubscriptionHandler]);
- }
-
wrapper = shallowMount(WorkItemDetail, {
apolloProvider: createMockApollo(
handlers,
@@ -107,6 +116,12 @@ describe('WorkItemDetail component', () => {
workItemsMvc2: workItemsMvc2Enabled,
},
hasIssueWeightsFeature: true,
+ hasIterationsFeature: true,
+ projectNamespace: 'namespace',
+ },
+ stubs: {
+ WorkItemWeight: true,
+ WorkItemIteration: true,
},
});
};
@@ -384,13 +399,14 @@ describe('WorkItemDetail component', () => {
});
});
- it('shows an error message when the work item query was unsuccessful', async () => {
+ it('shows empty state with an error message when the work item query was unsuccessful', async () => {
const errorHandler = jest.fn().mockRejectedValue('Oops');
createComponent({ handler: errorHandler });
await waitForPromises();
expect(errorHandler).toHaveBeenCalled();
- expect(findAlert().text()).toBe(i18n.fetchError);
+ expect(findEmptyState().props('description')).toBe(i18n.fetchError);
+ expect(findWorkItemTitle().exists()).toBe(false);
});
it('shows an error message when WorkItemTitle emits an `error` event', async () => {
@@ -413,6 +429,30 @@ describe('WorkItemDetail component', () => {
});
});
+ describe('assignees subscription', () => {
+ describe('when the assignees widget exists', () => {
+ it('calls the assignees subscription', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(assigneesSubscriptionHandler).toHaveBeenCalledWith({
+ issuableId: workItemQueryResponse.data.workItem.id,
+ });
+ });
+ });
+
+ describe('when the assignees widget does not exist', () => {
+ it('does not call the assignees subscription', async () => {
+ const response = workItemResponseFactory({ assigneesWidgetPresent: false });
+ const handler = jest.fn().mockResolvedValue(response);
+ createComponent({ handler });
+ await waitForPromises();
+
+ expect(assigneesSubscriptionHandler).not.toHaveBeenCalled();
+ });
+ });
+ });
+
describe('dates subscription', () => {
describe('when the due date widget exists', () => {
it('calls the dates subscription', async () => {
@@ -429,7 +469,7 @@ describe('WorkItemDetail component', () => {
it('does not call the dates subscription', async () => {
const response = workItemResponseFactory({ datesWidgetPresent: false });
const handler = jest.fn().mockResolvedValue(response);
- createComponent({ handler, workItemsMvc2Enabled: true });
+ createComponent({ handler });
await waitForPromises();
expect(datesSubscriptionHandler).not.toHaveBeenCalled();
@@ -440,9 +480,7 @@ describe('WorkItemDetail component', () => {
describe('assignees widget', () => {
it('renders assignees component when widget is returned from the API', async () => {
- createComponent({
- workItemsMvc2Enabled: true,
- });
+ createComponent();
await waitForPromises();
expect(findWorkItemAssignees().exists()).toBe(true);
@@ -450,7 +488,6 @@ describe('WorkItemDetail component', () => {
it('does not render assignees component when widget is not returned from the API', async () => {
createComponent({
- workItemsMvc2Enabled: true,
handler: jest
.fn()
.mockResolvedValue(workItemResponseFactory({ assigneesWidgetPresent: false })),
@@ -463,11 +500,13 @@ describe('WorkItemDetail component', () => {
describe('labels widget', () => {
it.each`
- description | includeWidgets | exists
- ${'renders when widget is returned from API'} | ${true} | ${true}
- ${'does not render when widget is not returned from API'} | ${false} | ${false}
- `('$description', async ({ includeWidgets, exists }) => {
- createComponent({ includeWidgets, workItemsMvc2Enabled: true });
+ description | labelsWidgetPresent | exists
+ ${'renders when widget is returned from API'} | ${true} | ${true}
+ ${'does not render when widget is not returned from API'} | ${false} | ${false}
+ `('$description', async ({ labelsWidgetPresent, exists }) => {
+ const response = workItemResponseFactory({ labelsWidgetPresent });
+ const handler = jest.fn().mockResolvedValue(response);
+ createComponent({ handler });
await waitForPromises();
expect(findWorkItemLabels().exists()).toBe(exists);
@@ -483,7 +522,7 @@ describe('WorkItemDetail component', () => {
it(`${datesWidgetPresent ? 'renders' : 'does not render'} due date component`, async () => {
const response = workItemResponseFactory({ datesWidgetPresent });
const handler = jest.fn().mockResolvedValue(response);
- createComponent({ handler, workItemsMvc2Enabled: true });
+ createComponent({ handler });
await waitForPromises();
expect(findWorkItemDueDate().exists()).toBe(exists);
@@ -491,7 +530,7 @@ describe('WorkItemDetail component', () => {
});
it('shows an error message when it emits an `error` event', async () => {
- createComponent({ workItemsMvc2Enabled: true });
+ createComponent();
await waitForPromises();
const updateError = 'Failed to update';
@@ -502,6 +541,19 @@ describe('WorkItemDetail component', () => {
});
});
+ describe('milestone widget', () => {
+ it.each`
+ description | includeWidgets | exists
+ ${'renders when widget is returned from API'} | ${true} | ${true}
+ ${'does not render when widget is not returned from API'} | ${false} | ${false}
+ `('$description', async ({ includeWidgets, exists }) => {
+ createComponent({ includeWidgets, workItemsMvc2Enabled: true });
+ await waitForPromises();
+
+ expect(findWorkItemMilestone().exists()).toBe(exists);
+ });
+ });
+
describe('work item information', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_due_date_spec.js b/spec/frontend/work_items/components/work_item_due_date_spec.js
index 1d76154a1f0..701406b9588 100644
--- a/spec/frontend/work_items/components/work_item_due_date_spec.js
+++ b/spec/frontend/work_items/components/work_item_due_date_spec.js
@@ -62,7 +62,7 @@ describe('WorkItemDueDate component', () => {
createComponent({ canUpdate: true, startDate });
});
- it(exists ? 'renders' : 'does not render', () => {
+ it(`${exists ? 'renders' : 'does not render'}`, () => {
expect(findStartDateButton().exists()).toBe(exists);
});
});
@@ -172,7 +172,7 @@ describe('WorkItemDueDate component', () => {
createComponent({ canUpdate: true, dueDate });
});
- it(exists ? 'renders' : 'does not render', () => {
+ it(`${exists ? 'renders' : 'does not render'}`, () => {
expect(findDueDateButton().exists()).toBe(exists);
});
});
diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js
index 1d976897c15..e6ff7e8502d 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -7,10 +7,18 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import labelSearchQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import workItemLabelsSubscription from 'ee_else_ce/work_items/graphql/work_item_labels.subscription.graphql';
+import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import WorkItemLabels from '~/work_items/components/work_item_labels.vue';
-import { i18n } from '~/work_items/constants';
-import { temporaryConfig, resolvers } from '~/graphql_shared/issuable_client';
-import { projectLabelsResponse, mockLabels, workItemQueryResponse } from '../mock_data';
+import { i18n, I18N_WORK_ITEM_ERROR_FETCHING_LABELS } from '~/work_items/constants';
+import {
+ projectLabelsResponse,
+ mockLabels,
+ workItemQueryResponse,
+ workItemResponseFactory,
+ updateWorkItemMutationResponse,
+ workItemLabelsSubscriptionResponse,
+} from '../mock_data';
Vue.use(VueApollo);
@@ -21,32 +29,32 @@ describe('WorkItemLabels component', () => {
const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
-
const findEmptyState = () => wrapper.findByTestId('empty-state');
+ const findLabelsTitle = () => wrapper.findByTestId('labels-title');
+ const workItemQuerySuccess = jest.fn().mockResolvedValue(workItemQueryResponse);
const successSearchQueryHandler = jest.fn().mockResolvedValue(projectLabelsResponse);
+ const successUpdateWorkItemMutationHandler = jest
+ .fn()
+ .mockResolvedValue(updateWorkItemMutationResponse);
+ const subscriptionHandler = jest.fn().mockResolvedValue(workItemLabelsSubscriptionResponse);
const errorHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
const createComponent = ({
- labels = mockLabels,
canUpdate = true,
+ workItemQueryHandler = workItemQuerySuccess,
searchQueryHandler = successSearchQueryHandler,
+ updateWorkItemMutationHandler = successUpdateWorkItemMutationHandler,
} = {}) => {
- const apolloProvider = createMockApollo([[labelSearchQuery, searchQueryHandler]], resolvers, {
- typePolicies: temporaryConfig.cacheConfig.typePolicies,
- });
-
- apolloProvider.clients.defaultClient.writeQuery({
- query: workItemQuery,
- variables: {
- id: workItemId,
- },
- data: workItemQueryResponse.data,
- });
+ const apolloProvider = createMockApollo([
+ [workItemQuery, workItemQueryHandler],
+ [labelSearchQuery, searchQueryHandler],
+ [updateWorkItemMutation, updateWorkItemMutationHandler],
+ [workItemLabelsSubscription, subscriptionHandler],
+ ]);
wrapper = mountExtended(WorkItemLabels, {
propsData: {
- labels,
workItemId,
canUpdate,
fullPath: 'test-project-path',
@@ -60,6 +68,12 @@ describe('WorkItemLabels component', () => {
wrapper.destroy();
});
+ it('has a label', () => {
+ createComponent();
+
+ expect(findTokenSelector().props('ariaLabelledby')).toEqual(findLabelsTitle().attributes('id'));
+ });
+
it('focuses token selector on token selector input event', async () => {
createComponent();
findTokenSelector().vm.$emit('input', [mockLabels[0]]);
@@ -151,7 +165,7 @@ describe('WorkItemLabels component', () => {
findTokenSelector().vm.$emit('focus');
await waitForPromises();
- expect(wrapper.emitted('error')).toEqual([[i18n.fetchError]]);
+ expect(wrapper.emitted('error')).toEqual([[I18N_WORK_ITEM_ERROR_FETCHING_LABELS]]);
});
it('should search for with correct key after text input', async () => {
@@ -163,7 +177,53 @@ describe('WorkItemLabels component', () => {
await waitForPromises();
expect(successSearchQueryHandler).toHaveBeenCalledWith(
- expect.objectContaining({ search: searchKey }),
+ expect.objectContaining({ searchTerm: searchKey }),
);
});
+
+ describe('when clicking outside the token selector', () => {
+ it('calls a mutation with correct variables', () => {
+ createComponent();
+
+ findTokenSelector().vm.$emit('input', [mockLabels[0]]);
+ findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null }));
+
+ expect(successUpdateWorkItemMutationHandler).toHaveBeenCalledWith({
+ input: {
+ labelsWidget: { addLabelIds: [mockLabels[0].id], removeLabelIds: [] },
+ id: 'gid://gitlab/WorkItem/1',
+ },
+ });
+ });
+
+ it('emits an error and resets labels if mutation was rejected', async () => {
+ const workItemQueryHandler = jest.fn().mockResolvedValue(workItemResponseFactory());
+
+ createComponent({ updateWorkItemMutationHandler: errorHandler, workItemQueryHandler });
+
+ await waitForPromises();
+
+ const initialLabels = findTokenSelector().props('selectedTokens');
+
+ findTokenSelector().vm.$emit('input', [mockLabels[0]]);
+ findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null }));
+
+ await waitForPromises();
+
+ const updatedLabels = findTokenSelector().props('selectedTokens');
+
+ expect(wrapper.emitted('error')).toEqual([[i18n.updateError]]);
+ expect(updatedLabels).toEqual(initialLabels);
+ });
+
+ it('has a subscription', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(subscriptionHandler).toHaveBeenCalledWith({
+ issuableId: workItemId,
+ });
+ });
+ });
});
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 434c1db8a2c..ab3ea623e3e 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
@@ -28,6 +28,7 @@ describe('WorkItemLinksForm', () => {
listResponse = availableWorkItemsResponse,
typesResponse = projectWorkItemTypesQueryResponse,
parentConfidential = false,
+ hasIterationsFeature = false,
} = {}) => {
wrapper = shallowMountExtended(WorkItemLinksForm, {
apolloProvider: createMockApollo([
@@ -39,6 +40,7 @@ describe('WorkItemLinksForm', () => {
propsData: { issuableGid: 'gid://gitlab/WorkItem/1', parentConfidential },
provide: {
projectPath: 'project/path',
+ hasIterationsFeature,
},
});
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
index 287ec022d3f..e3f3b74f296 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_menu_spec.js
@@ -10,8 +10,8 @@ describe('WorkItemLinksMenu', () => {
wrapper = shallowMountExtended(WorkItemLinksMenu);
};
- const findDropdown = () => wrapper.find(GlDropdown);
- const findRemoveDropdownItem = () => wrapper.find(GlDropdownItem);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findRemoveDropdownItem = () => wrapper.findComponent(GlDropdownItem);
beforeEach(async () => {
createComponent();
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 876aedff08b..6961996f912 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
@@ -5,7 +5,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import issueConfidentialQuery from '~/sidebar/queries/issue_confidential.query.graphql';
+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 workItemQuery from '~/work_items/graphql/work_item.query.graphql';
@@ -21,16 +21,29 @@ import {
Vue.use(VueApollo);
-const issueConfidentialityResponse = (confidential = false) => ({
+const issueDetailsResponse = (confidential = false) => ({
data: {
workspace: {
- id: '1',
- __typename: 'Project',
+ id: 'gid://gitlab/Project/1',
issuable: {
- __typename: 'Issue',
id: 'gid://gitlab/Issue/4',
confidential,
+ iteration: {
+ id: 'gid://gitlab/Iteration/1124',
+ title: null,
+ startDate: '2022-06-22',
+ dueDate: '2022-07-19',
+ webUrl: 'http://127.0.0.1:3000/groups/gitlab-org/-/iterations/1124',
+ iterationCadence: {
+ id: 'gid://gitlab/Iterations::Cadence/1101',
+ title: 'Quod voluptates quidem ea eaque eligendi ex corporis.',
+ __typename: 'IterationCadence',
+ },
+ __typename: 'Iteration',
+ },
+ __typename: 'Issue',
},
+ __typename: 'Project',
},
},
});
@@ -55,14 +68,15 @@ describe('WorkItemLinks', () => {
data = {},
fetchHandler = jest.fn().mockResolvedValue(workItemHierarchyResponse),
mutationHandler = mutationChangeParentHandler,
- confidentialQueryHandler = jest.fn().mockResolvedValue(issueConfidentialityResponse()),
+ issueDetailsQueryHandler = jest.fn().mockResolvedValue(issueDetailsResponse()),
+ hasIterationsFeature = false,
} = {}) => {
mockApollo = createMockApollo(
[
[getWorkItemLinksQuery, fetchHandler],
[changeWorkItemParentMutation, mutationHandler],
[workItemQuery, childWorkItemQueryHandler],
- [issueConfidentialQuery, confidentialQueryHandler],
+ [issueDetailsQuery, issueDetailsQueryHandler],
],
{},
{ addTypename: true },
@@ -77,6 +91,7 @@ describe('WorkItemLinks', () => {
provide: {
projectPath: 'project/path',
iid: '1',
+ hasIterationsFeature,
},
propsData: { issuableId: 1 },
apolloProvider: mockApollo,
@@ -266,7 +281,7 @@ describe('WorkItemLinks', () => {
describe('when parent item is confidential', () => {
it('passes correct confidentiality status to form', async () => {
await createComponent({
- confidentialQueryHandler: jest.fn().mockResolvedValue(issueConfidentialityResponse(true)),
+ issueDetailsQueryHandler: jest.fn().mockResolvedValue(issueDetailsResponse(true)),
});
findToggleAddFormButton().vm.$emit('click');
await nextTick();
diff --git a/spec/frontend/work_items/components/work_item_milestone_spec.js b/spec/frontend/work_items/components/work_item_milestone_spec.js
new file mode 100644
index 00000000000..08cdf62ae52
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_milestone_spec.js
@@ -0,0 +1,247 @@
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlSearchBoxByType,
+ GlSkeletonLoader,
+ GlFormGroup,
+ GlDropdownText,
+} from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
+import { resolvers, temporaryConfig } from '~/graphql_shared/issuable_client';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mockTracking } from 'helpers/tracking_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
+import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql';
+import {
+ projectMilestonesResponse,
+ projectMilestonesResponseWithNoMilestones,
+ mockMilestoneWidgetResponse,
+ workItemResponseFactory,
+ updateWorkItemMutationErrorResponse,
+} from 'jest/work_items/mock_data';
+import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+
+describe('WorkItemMilestone component', () => {
+ Vue.use(VueApollo);
+
+ let wrapper;
+
+ const workItemId = 'gid://gitlab/WorkItem/1';
+ const workItemType = 'Task';
+ const fullPath = 'full-path';
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findNoMilestoneDropdownItem = () => wrapper.findByTestId('no-milestone');
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findFirstDropdownItem = () => findDropdownItems().at(0);
+ const findDropdownTexts = () => wrapper.findAllComponents(GlDropdownText);
+ const findDropdownItemAtIndex = (index) => findDropdownItems().at(index);
+ const findDisabledTextSpan = () => wrapper.findByTestId('disabled-text');
+ const findDropdownTextAtIndex = (index) => findDropdownTexts().at(index);
+ const findInputGroup = () => wrapper.findComponent(GlFormGroup);
+
+ const workItemQueryResponse = workItemResponseFactory({ canUpdate: true, canDelete: true });
+
+ const networkResolvedValue = new Error();
+
+ const successSearchQueryHandler = jest.fn().mockResolvedValue(projectMilestonesResponse);
+ const successSearchWithNoMatchingMilestones = jest
+ .fn()
+ .mockResolvedValue(projectMilestonesResponseWithNoMilestones);
+
+ const showDropdown = () => {
+ findDropdown().vm.$emit('shown');
+ };
+
+ const hideDropdown = () => {
+ findDropdown().vm.$emit('hide');
+ };
+
+ const createComponent = ({
+ canUpdate = true,
+ milestone = mockMilestoneWidgetResponse,
+ searchQueryHandler = successSearchQueryHandler,
+ } = {}) => {
+ const apolloProvider = createMockApollo(
+ [[projectMilestonesQuery, searchQueryHandler]],
+ resolvers,
+ {
+ typePolicies: temporaryConfig.cacheConfig.typePolicies,
+ },
+ );
+
+ apolloProvider.clients.defaultClient.writeQuery({
+ query: workItemQuery,
+ variables: {
+ id: workItemId,
+ },
+ data: workItemQueryResponse.data,
+ });
+
+ wrapper = shallowMountExtended(WorkItemMilestone, {
+ apolloProvider,
+ propsData: {
+ canUpdate,
+ workItemMilestone: milestone,
+ workItemId,
+ workItemType,
+ fullPath,
+ },
+ stubs: {
+ GlDropdown,
+ GlSearchBoxByType,
+ },
+ });
+ };
+
+ it('has "Milestone" label', () => {
+ createComponent();
+
+ expect(findInputGroup().exists()).toBe(true);
+ expect(findInputGroup().attributes('label')).toBe(WorkItemMilestone.i18n.MILESTONE);
+ });
+
+ describe('Default text with canUpdate false and milestone value', () => {
+ describe.each`
+ description | milestone | value
+ ${'when no milestone'} | ${null} | ${WorkItemMilestone.i18n.NONE}
+ ${'when milestone set'} | ${mockMilestoneWidgetResponse} | ${mockMilestoneWidgetResponse.title}
+ `('$description', ({ milestone, value }) => {
+ it(`has a value of "${value}"`, () => {
+ createComponent({ canUpdate: false, milestone });
+
+ expect(findDisabledTextSpan().text()).toBe(value);
+ expect(findDropdown().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Default text value when canUpdate true and no milestone set', () => {
+ it(`has a value of "Add to milestone"`, () => {
+ createComponent({ canUpdate: true, milestone: null });
+
+ expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ });
+ });
+
+ describe('Dropdown search', () => {
+ it('has the search box', () => {
+ createComponent();
+
+ expect(findSearchBox().exists()).toBe(true);
+ });
+
+ it('shows no matching results when no items', () => {
+ createComponent({
+ searchQueryHandler: successSearchWithNoMatchingMilestones,
+ });
+
+ expect(findDropdownTextAtIndex(0).text()).toBe(WorkItemMilestone.i18n.NO_MATCHING_RESULTS);
+ expect(findDropdownItems()).toHaveLength(1);
+ expect(findDropdownTexts()).toHaveLength(1);
+ });
+ });
+
+ describe('Dropdown options', () => {
+ beforeEach(() => {
+ createComponent({ canUpdate: true });
+ });
+
+ it('shows the skeleton loader when the items are being fetched on click', async () => {
+ showDropdown();
+ await nextTick();
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('shows the milestones in dropdown when the items have finished fetching', async () => {
+ showDropdown();
+ await waitForPromises();
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ expect(findNoMilestoneDropdownItem().exists()).toBe(true);
+ expect(findDropdownItems()).toHaveLength(
+ projectMilestonesResponse.data.workspace.attributes.nodes.length + 1,
+ );
+ });
+
+ it('changes the milestone to null when clicked on no milestone', async () => {
+ showDropdown();
+ findFirstDropdownItem().vm.$emit('click');
+
+ hideDropdown();
+ await nextTick();
+ expect(findDropdown().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findDropdown().props('loading')).toBe(false);
+ expect(findDropdown().props('text')).toBe(WorkItemMilestone.i18n.MILESTONE_PLACEHOLDER);
+ });
+
+ it('changes the milestone to the selected milestone', async () => {
+ const milestoneIndex = 1;
+ /** the index is -1 since no matching results is also a dropdown item */
+ const milestoneAtIndex =
+ projectMilestonesResponse.data.workspace.attributes.nodes[milestoneIndex - 1];
+ showDropdown();
+
+ await waitForPromises();
+ findDropdownItemAtIndex(milestoneIndex).vm.$emit('click');
+
+ hideDropdown();
+ await waitForPromises();
+
+ expect(findDropdown().props('text')).toBe(milestoneAtIndex.title);
+ });
+ });
+
+ describe('Error handlers', () => {
+ it.each`
+ errorType | expectedErrorMessage | mockValue | resolveFunction
+ ${'graphql error'} | ${'Something went wrong while updating the task. Please try again.'} | ${updateWorkItemMutationErrorResponse} | ${'mockResolvedValue'}
+ ${'network error'} | ${'Something went wrong while updating the task. Please try again.'} | ${networkResolvedValue} | ${'mockRejectedValue'}
+ `(
+ 'emits an error when there is a $errorType',
+ async ({ mockValue, expectedErrorMessage, resolveFunction }) => {
+ createComponent({
+ mutationHandler: jest.fn()[resolveFunction](mockValue),
+ canUpdate: true,
+ });
+
+ showDropdown();
+ findFirstDropdownItem().vm.$emit('click');
+ hideDropdown();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[expectedErrorMessage]]);
+ },
+ );
+ });
+
+ describe('Tracking event', () => {
+ it('tracks updating the milestone', async () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ createComponent({ canUpdate: true });
+
+ showDropdown();
+ findFirstDropdownItem().vm.$emit('click');
+ hideDropdown();
+
+ await waitForPromises();
+
+ expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_milestone', {
+ category: TRACKING_CATEGORY_SHOW,
+ label: 'item_milestone',
+ property: 'type_Task',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/work_items/components/work_item_type_icon_spec.js b/spec/frontend/work_items/components/work_item_type_icon_spec.js
index 95ddfc3980e..182fb0f8cb6 100644
--- a/spec/frontend/work_items/components/work_item_type_icon_spec.js
+++ b/spec/frontend/work_items/components/work_item_type_icon_spec.js
@@ -51,7 +51,7 @@ describe('Work Item type component', () => {
});
it('renders the icon in gray color', () => {
- expect(findIcon().classes()).toContain('gl-text-gray-500');
+ expect(findIcon().classes()).toContain('gl-text-secondary');
});
it('shows tooltip on hover when props passed', () => {
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index e1bc8d2f6b7..ed90b11222a 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -17,6 +17,25 @@ export const mockAssignees = [
},
];
+export const mockLabels = [
+ {
+ __typename: 'Label',
+ id: 'gid://gitlab/Label/1',
+ title: 'Label 1',
+ description: '',
+ color: '#f00',
+ textColor: '#00f',
+ },
+ {
+ __typename: 'Label',
+ id: 'gid://gitlab/Label/2',
+ title: 'Label::2',
+ description: '',
+ color: '#b00',
+ textColor: '#00b',
+ },
+];
+
export const workItemQueryResponse = {
data: {
workItem: {
@@ -50,6 +69,8 @@ export const workItemQueryResponse = {
description: 'some **great** text',
descriptionHtml:
'<p data-sourcepos="1:1-1:19" dir="auto">some <strong>great</strong> text</p>',
+ lastEditedAt: null,
+ lastEditedBy: null,
},
{
__typename: 'WorkItemWidgetAssignees',
@@ -163,9 +184,15 @@ export const workItemResponseFactory = ({
allowsMultipleAssignees = true,
assigneesWidgetPresent = true,
datesWidgetPresent = true,
+ labelsWidgetPresent = true,
weightWidgetPresent = true,
+ milestoneWidgetPresent = true,
+ iterationWidgetPresent = true,
confidential = false,
canInviteMembers = false,
+ allowsScopedLabels = false,
+ lastEditedAt = null,
+ lastEditedBy = null,
parent = mockParent.parent,
} = {}) => ({
data: {
@@ -200,6 +227,8 @@ export const workItemResponseFactory = ({
description: 'some **great** text',
descriptionHtml:
'<p data-sourcepos="1:1-1:19" dir="auto">some <strong>great</strong> text</p>',
+ lastEditedAt,
+ lastEditedBy,
},
assigneesWidgetPresent
? {
@@ -212,6 +241,16 @@ export const workItemResponseFactory = ({
},
}
: { type: 'MOCK TYPE' },
+ labelsWidgetPresent
+ ? {
+ __typename: 'WorkItemWidgetLabels',
+ type: 'LABELS',
+ allowsScopedLabels,
+ labels: {
+ nodes: mockLabels,
+ },
+ }
+ : { type: 'MOCK TYPE' },
datesWidgetPresent
? {
__typename: 'WorkItemWidgetStartAndDueDate',
@@ -227,6 +266,30 @@ export const workItemResponseFactory = ({
weight: 0,
}
: { type: 'MOCK TYPE' },
+ iterationWidgetPresent
+ ? {
+ __typename: 'WorkItemWidgetIteration',
+ type: 'ITERATION',
+ iteration: {
+ description: null,
+ id: 'gid://gitlab/Iteration/1215',
+ iid: '182',
+ title: 'Iteration default title',
+ startDate: '2022-09-22',
+ dueDate: '2022-09-30',
+ },
+ }
+ : { type: 'MOCK TYPE' },
+ milestoneWidgetPresent
+ ? {
+ __typename: 'WorkItemWidgetMilestone',
+ dueDate: null,
+ expired: false,
+ id: 'gid://gitlab/Milestone/30',
+ title: 'v4.0',
+ type: 'MILESTONE',
+ }
+ : { type: 'MOCK TYPE' },
{
__typename: 'WorkItemWidgetHierarchy',
type: 'HIERARCHY',
@@ -331,6 +394,11 @@ export const createWorkItemFromTaskMutationResponse = {
type: 'DESCRIPTION',
description: 'New description',
descriptionHtml: '<p>New description</p>',
+ lastEditedAt: '2022-09-21T06:18:42Z',
+ lastEditedBy: {
+ name: 'Administrator',
+ webPath: '/root',
+ },
},
],
},
@@ -444,6 +512,61 @@ export const workItemWeightSubscriptionResponse = {
},
};
+export const workItemAssigneesSubscriptionResponse = {
+ data: {
+ issuableAssigneesUpdated: {
+ id: 'gid://gitlab/WorkItem/1',
+ widgets: [
+ {
+ __typename: 'WorkItemAssigneesWeight',
+ assignees: {
+ nodes: [mockAssignees[0]],
+ },
+ },
+ ],
+ },
+ },
+};
+
+export const workItemLabelsSubscriptionResponse = {
+ data: {
+ issuableLabelsUpdated: {
+ id: 'gid://gitlab/WorkItem/1',
+ widgets: [
+ {
+ __typename: 'WorkItemWidgetLabels',
+ type: 'LABELS',
+ allowsScopedLabels: false,
+ labels: {
+ nodes: mockLabels,
+ },
+ },
+ ],
+ },
+ },
+};
+
+export const workItemIterationSubscriptionResponse = {
+ data: {
+ issuableIterationUpdated: {
+ id: 'gid://gitlab/WorkItem/1',
+ widgets: [
+ {
+ __typename: 'WorkItemWidgetIteration',
+ iteration: {
+ description: 'Iteration description',
+ dueDate: '2022-07-29',
+ id: 'gid://gitlab/Iteration/1125',
+ iid: '95',
+ startDate: '2022-06-22',
+ title: 'Iteration subcription title',
+ },
+ },
+ ],
+ },
+ },
+};
+
export const workItemHierarchyEmptyResponse = {
data: {
workItem: {
@@ -857,25 +980,6 @@ export const currentUserNullResponse = {
},
};
-export const mockLabels = [
- {
- __typename: 'Label',
- id: 'gid://gitlab/Label/1',
- title: 'Label 1',
- description: '',
- color: '#f00',
- textColor: '#00f',
- },
- {
- __typename: 'Label',
- id: 'gid://gitlab/Label/2',
- title: 'Label 2',
- description: '',
- color: '#b00',
- textColor: '#00b',
- },
-];
-
export const projectLabelsResponse = {
data: {
workspace: {
@@ -887,3 +991,134 @@ export const projectLabelsResponse = {
},
},
};
+
+export const mockIterationWidgetResponse = {
+ description: 'Iteration description',
+ dueDate: '2022-07-19',
+ id: 'gid://gitlab/Iteration/1124',
+ iid: '91',
+ startDate: '2022-06-22',
+ title: 'Iteration title widget',
+};
+
+export const groupIterationsResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Group/22',
+ attributes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Iteration/1124',
+ title: null,
+ startDate: '2022-06-22',
+ dueDate: '2022-07-19',
+ webUrl: 'http://127.0.0.1:3000/groups/gitlab-org/-/iterations/1124',
+ iterationCadence: {
+ id: 'gid://gitlab/Iterations::Cadence/1101',
+ title: 'Quod voluptates quidem ea eaque eligendi ex corporis.',
+ __typename: 'IterationCadence',
+ },
+ __typename: 'Iteration',
+ state: 'current',
+ },
+ {
+ id: 'gid://gitlab/Iteration/1185',
+ title: null,
+ startDate: '2022-07-06',
+ dueDate: '2022-07-19',
+ webUrl: 'http://127.0.0.1:3000/groups/gitlab-org/-/iterations/1185',
+ iterationCadence: {
+ id: 'gid://gitlab/Iterations::Cadence/1144',
+ title: 'Quo velit perspiciatis saepe aut omnis voluptas ab eos.',
+ __typename: 'IterationCadence',
+ },
+ __typename: 'Iteration',
+ state: 'current',
+ },
+ {
+ id: 'gid://gitlab/Iteration/1194',
+ title: null,
+ startDate: '2022-07-06',
+ dueDate: '2022-07-19',
+ webUrl: 'http://127.0.0.1:3000/groups/gitlab-org/-/iterations/1194',
+ iterationCadence: {
+ id: 'gid://gitlab/Iterations::Cadence/1152',
+ title:
+ 'Minima aut consequatur magnam vero doloremque accusamus maxime repellat voluptatem qui.',
+ __typename: 'IterationCadence',
+ },
+ __typename: 'Iteration',
+ state: 'current',
+ },
+ ],
+ __typename: 'IterationConnection',
+ },
+ __typename: 'Group',
+ },
+ },
+};
+
+export const groupIterationsResponseWithNoIterations = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Group/22',
+ attributes: {
+ nodes: [],
+ __typename: 'IterationConnection',
+ },
+ __typename: 'Group',
+ },
+ },
+};
+
+export const mockMilestoneWidgetResponse = {
+ dueDate: null,
+ expired: false,
+ id: 'gid://gitlab/Milestone/30',
+ title: 'v4.0',
+};
+
+export const projectMilestonesResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Project/1',
+ attributes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Milestone/5',
+ title: 'v4.0',
+ webUrl: '/gitlab-org/gitlab-test/-/milestones/5',
+ dueDate: null,
+ expired: false,
+ __typename: 'Milestone',
+ state: 'active',
+ },
+ {
+ id: 'gid://gitlab/Milestone/4',
+ title: 'v3.0',
+ webUrl: '/gitlab-org/gitlab-test/-/milestones/4',
+ dueDate: null,
+ expired: false,
+ __typename: 'Milestone',
+ state: 'active',
+ },
+ ],
+ __typename: 'MilestoneConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const projectMilestonesResponseWithNoMilestones = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Project/1',
+ attributes: {
+ nodes: [],
+ __typename: 'MilestoneConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js
index ab370e2ca8b..66a917d8052 100644
--- a/spec/frontend/work_items/router_spec.js
+++ b/spec/frontend/work_items/router_spec.js
@@ -4,15 +4,19 @@ import VueApollo from 'vue-apollo';
import workItemWeightSubscription from 'ee_component/work_items/graphql/work_item_weight.subscription.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import {
+ workItemAssigneesSubscriptionResponse,
workItemDatesSubscriptionResponse,
workItemResponseFactory,
workItemTitleSubscriptionResponse,
workItemWeightSubscriptionResponse,
+ workItemLabelsSubscriptionResponse,
} from 'jest/work_items/mock_data';
import App from '~/work_items/components/app.vue';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subscription.graphql';
import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql';
+import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql';
+import workItemLabelsSubscription from 'ee_else_ce/work_items/graphql/work_item_labels.subscription.graphql';
import CreateWorkItem from '~/work_items/pages/create_work_item.vue';
import WorkItemsRoot from '~/work_items/pages/work_item_root.vue';
import { createRouter } from '~/work_items/router';
@@ -26,6 +30,10 @@ describe('Work items router', () => {
const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse);
const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse);
const weightSubscriptionHandler = jest.fn().mockResolvedValue(workItemWeightSubscriptionResponse);
+ const assigneesSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemAssigneesSubscriptionResponse);
+ const labelsSubscriptionHandler = jest.fn().mockResolvedValue(workItemLabelsSubscriptionResponse);
const createComponent = async (routeArg) => {
const router = createRouter('/work_item');
@@ -37,6 +45,8 @@ describe('Work items router', () => {
[workItemQuery, workItemQueryHandler],
[workItemDatesSubscription, datesSubscriptionHandler],
[workItemTitleSubscription, titleSubscriptionHandler],
+ [workItemAssigneesSubscription, assigneesSubscriptionHandler],
+ [workItemLabelsSubscription, labelsSubscriptionHandler],
];
if (IS_EE) {