Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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.js222
1 files changed, 222 insertions, 0 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
new file mode 100644
index 00000000000..8017c46dea8
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_description_spec.js
@@ -0,0 +1,222 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+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 { 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 WorkItemDescription from '~/work_items/components/work_item_description.vue';
+import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
+import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import updateWorkItemWidgetsMutation from '~/work_items/graphql/update_work_item_widgets.mutation.graphql';
+import {
+ updateWorkItemWidgetsResponse,
+ workItemResponseFactory,
+ workItemQueryResponse,
+} from '../mock_data';
+
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
+ return {
+ confirmAction: jest.fn(),
+ };
+});
+jest.mock('~/lib/utils/autosave');
+
+const workItemId = workItemQueryResponse.data.workItem.id;
+
+describe('WorkItemDescription', () => {
+ let wrapper;
+
+ Vue.use(VueApollo);
+
+ const mutationSuccessHandler = jest.fn().mockResolvedValue(updateWorkItemWidgetsResponse);
+
+ const findEditButton = () => wrapper.find('[data-testid="edit-description"]');
+ const findMarkdownField = () => wrapper.findComponent(MarkdownField);
+
+ const editDescription = (newText) => 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', {});
+
+ const createComponent = async ({
+ mutationHandler = mutationSuccessHandler,
+ canUpdate = true,
+ isEditing = false,
+ } = {}) => {
+ const workItemResponse = workItemResponseFactory({ canUpdate });
+ const workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse);
+
+ const { id } = workItemQueryResponse.data.workItem;
+ wrapper = shallowMount(WorkItemDescription, {
+ apolloProvider: createMockApollo([
+ [workItemQuery, workItemResponseHandler],
+ [updateWorkItemWidgetsMutation, mutationHandler],
+ ]),
+ propsData: {
+ workItemId: id,
+ },
+ provide: {
+ fullPath: '/group/project',
+ },
+ stubs: {
+ MarkdownField,
+ },
+ });
+
+ await waitForPromises();
+
+ if (isEditing) {
+ findEditButton().vm.$emit('click');
+
+ await nextTick();
+ }
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Edit button', () => {
+ it('is not visible when canUpdate = false', async () => {
+ await createComponent({
+ canUpdate: false,
+ });
+
+ expect(findEditButton().exists()).toBe(false);
+ });
+
+ it('toggles edit mode', async () => {
+ await createComponent({
+ canUpdate: true,
+ });
+
+ findEditButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findMarkdownField().exists()).toBe(true);
+ });
+ });
+
+ describe('editing description', () => {
+ it('cancels when clicking cancel', async () => {
+ await createComponent({
+ isEditing: true,
+ });
+
+ clickCancel();
+
+ await nextTick();
+
+ expect(confirmAction).not.toHaveBeenCalled();
+ expect(findMarkdownField().exists()).toBe(false);
+ });
+
+ it('prompts for confirmation when clicking cancel after changes', async () => {
+ await createComponent({
+ isEditing: true,
+ });
+
+ editDescription('updated desc');
+
+ clickCancel();
+
+ await nextTick();
+
+ expect(confirmAction).toHaveBeenCalled();
+ });
+
+ it('calls update widgets mutation', async () => {
+ await createComponent({
+ isEditing: true,
+ });
+
+ editDescription('updated desc');
+
+ clickSave();
+
+ await waitForPromises();
+
+ expect(mutationSuccessHandler).toHaveBeenCalledWith({
+ input: {
+ id: workItemId,
+ descriptionWidget: {
+ description: 'updated desc',
+ },
+ },
+ });
+ });
+
+ it('tracks editing description', async () => {
+ await createComponent({
+ isEditing: true,
+ markdownPreviewPath: '/preview',
+ });
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ clickSave();
+
+ await waitForPromises();
+
+ expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_description', {
+ category: TRACKING_CATEGORY_SHOW,
+ label: 'item_description',
+ property: 'type_Task',
+ });
+ });
+
+ it('emits error when mutation returns error', async () => {
+ const error = 'eror';
+
+ await createComponent({
+ isEditing: true,
+ mutationHandler: jest.fn().mockResolvedValue({
+ data: {
+ workItemUpdateWidgets: {
+ workItem: {},
+ errors: [error],
+ },
+ },
+ }),
+ });
+
+ editDescription('updated desc');
+
+ clickSave();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[error]]);
+ });
+
+ it('emits error when mutation fails', async () => {
+ const error = 'eror';
+
+ await createComponent({
+ isEditing: true,
+ mutationHandler: jest.fn().mockRejectedValue(new Error(error)),
+ });
+
+ editDescription('updated desc');
+
+ clickSave();
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[error]]);
+ });
+
+ it('autosaves description', async () => {
+ await createComponent({
+ isEditing: true,
+ });
+
+ editDescription('updated desc');
+
+ expect(updateDraft).toHaveBeenCalled();
+ });
+ });
+});