diff options
Diffstat (limited to 'spec/frontend/issues/show')
-rw-r--r-- | spec/frontend/issues/show/components/app_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/description_spec.js | 14 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/edit_actions_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js | 189 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/mock_data.js | 28 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js | 117 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js (renamed from spec/frontend/issues/show/components/incidents/timeline_events_list_item_spec.js) | 4 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js | 14 | ||||
-rw-r--r-- | spec/frontend/issues/show/components/incidents/utils_spec.js | 2 |
10 files changed, 254 insertions, 122 deletions
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js index 27604b8ccf3..12f9707da04 100644 --- a/spec/frontend/issues/show/components/app_spec.js +++ b/spec/frontend/issues/show/components/app_spec.js @@ -119,7 +119,7 @@ describe('Issuable output', () => { expect(findEdited().exists()).toBe(true); expect(findEdited().props('updatedByPath')).toMatch(/\/some_user$/); - expect(findEdited().props('updatedAt')).toBeTruthy(); + expect(findEdited().props('updatedAt')).toBe(initialRequest.updated_at); expect(wrapper.vm.state.lock_version).toBe(initialRequest.lock_version); }) .then(() => { @@ -133,7 +133,7 @@ describe('Issuable output', () => { expect(findEdited().exists()).toBe(true); expect(findEdited().props('updatedByName')).toBe('Other User'); expect(findEdited().props('updatedByPath')).toMatch(/\/other_user$/); - expect(findEdited().props('updatedAt')).toBeTruthy(); + expect(findEdited().props('updatedAt')).toBe(secondRequest.updated_at); }); }); diff --git a/spec/frontend/issues/show/components/description_spec.js b/spec/frontend/issues/show/components/description_spec.js index 8ee57f97754..bdb1448148e 100644 --- a/spec/frontend/issues/show/components/description_spec.js +++ b/spec/frontend/issues/show/components/description_spec.js @@ -249,7 +249,7 @@ describe('Description component', () => { await nextTick(); expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe( - '1/1 task', + '1/1 checklist item', ); }); @@ -266,7 +266,7 @@ describe('Description component', () => { }); }); - describe('with work items feature flag is enabled', () => { + describe('with work_items_create_from_markdown feature flag enabled', () => { describe('empty description', () => { beforeEach(() => { createComponent({ @@ -275,7 +275,7 @@ describe('Description component', () => { }, provide: { glFeatures: { - workItems: true, + workItemsCreateFromMarkdown: true, }, }, }); @@ -295,7 +295,7 @@ describe('Description component', () => { }, provide: { glFeatures: { - workItems: true, + workItemsCreateFromMarkdown: true, }, }, }); @@ -344,7 +344,7 @@ describe('Description component', () => { descriptionHtml: descriptionHtmlWithTask, }, provide: { - glFeatures: { workItems: true }, + glFeatures: { workItemsCreateFromMarkdown: true }, }, }); return nextTick(); @@ -406,7 +406,7 @@ describe('Description component', () => { createComponent({ props: { descriptionHtml: descriptionHtmlWithTask }, - provide: { glFeatures: { workItems: true } }, + provide: { glFeatures: { workItemsCreateFromMarkdown: true } }, }); expect(showDetailsModal).toHaveBeenCalledTimes(modalOpened); @@ -422,7 +422,7 @@ describe('Description component', () => { descriptionHtml: descriptionHtmlWithTask, }, provide: { - glFeatures: { workItems: true }, + glFeatures: { workItemsCreateFromMarkdown: true }, }, }); return nextTick(); diff --git a/spec/frontend/issues/show/components/edit_actions_spec.js b/spec/frontend/issues/show/components/edit_actions_spec.js index 79368023d76..d58bf1be812 100644 --- a/spec/frontend/issues/show/components/edit_actions_spec.js +++ b/spec/frontend/issues/show/components/edit_actions_spec.js @@ -75,7 +75,7 @@ describe('Edit Actions component', () => { it('renders all buttons as enabled', () => { const buttons = findEditButtons().wrappers; buttons.forEach((button) => { - expect(button.attributes('disabled')).toBeFalsy(); + expect(button.attributes('disabled')).toBeUndefined(); }); }); diff --git a/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js b/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js new file mode 100644 index 00000000000..3ab2bb3460b --- /dev/null +++ b/spec/frontend/issues/show/components/incidents/create_timeline_events_form_spec.js @@ -0,0 +1,189 @@ +import VueApollo from 'vue-apollo'; +import Vue from 'vue'; +import { GlDatepicker } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import CreateTimelineEvent from '~/issues/show/components/incidents/create_timeline_event.vue'; +import TimelineEventsForm from '~/issues/show/components/incidents/timeline_events_form.vue'; +import createTimelineEventMutation from '~/issues/show/components/incidents/graphql/queries/create_timeline_event.mutation.graphql'; +import getTimelineEvents from '~/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import { createAlert } from '~/flash'; +import { useFakeDate } from 'helpers/fake_date'; +import { + timelineEventsCreateEventResponse, + timelineEventsCreateEventError, + mockGetTimelineData, +} from './mock_data'; + +Vue.use(VueApollo); + +jest.mock('~/flash'); + +const fakeDate = '2020-07-08T00:00:00.000Z'; + +const mockInputData = { + incidentId: 'gid://gitlab/Issue/1', + note: 'test', + occurredAt: '2020-07-08T00:00:00.000Z', +}; + +describe('Create Timeline events', () => { + useFakeDate(fakeDate); + let wrapper; + let responseSpy; + let apolloProvider; + + const findSubmitButton = () => wrapper.findByText(__('Save')); + const findSubmitAndAddButton = () => + wrapper.findByText(s__('Incident|Save and add another event')); + const findCancelButton = () => wrapper.findByText(__('Cancel')); + const findDatePicker = () => wrapper.findComponent(GlDatepicker); + const findNoteInput = () => wrapper.findByTestId('input-note'); + const setNoteInput = () => { + const textarea = findNoteInput().element; + textarea.value = mockInputData.note; + textarea.dispatchEvent(new Event('input')); + }; + const findHourInput = () => wrapper.findByTestId('input-hours'); + const findMinuteInput = () => wrapper.findByTestId('input-minutes'); + const setDatetime = () => { + const inputDate = new Date(mockInputData.occurredAt); + findDatePicker().vm.$emit('input', inputDate); + findHourInput().vm.$emit('input', inputDate.getHours()); + findMinuteInput().vm.$emit('input', inputDate.getMinutes()); + }; + const fillForm = () => { + setDatetime(); + setNoteInput(); + }; + + function createMockApolloProvider() { + const requestHandlers = [[createTimelineEventMutation, responseSpy]]; + const mockApollo = createMockApollo(requestHandlers); + + mockApollo.clients.defaultClient.cache.writeQuery({ + query: getTimelineEvents, + data: mockGetTimelineData, + variables: { + fullPath: 'group/project', + incidentId: 'gid://gitlab/Issue/1', + }, + }); + + return mockApollo; + } + + const mountComponent = () => { + wrapper = mountExtended(CreateTimelineEvent, { + propsData: { + hasTimelineEvents: true, + }, + provide: { + fullPath: 'group/project', + issuableId: '1', + }, + apolloProvider, + }); + }; + + beforeEach(() => { + responseSpy = jest.fn().mockResolvedValue(timelineEventsCreateEventResponse); + apolloProvider = createMockApolloProvider(); + }); + + afterEach(() => { + createAlert.mockReset(); + wrapper.destroy(); + }); + + describe('createIncidentTimelineEvent', () => { + const closeFormEvent = { 'hide-new-timeline-events-form': [[]] }; + + const expectedData = { + input: mockInputData, + }; + + beforeEach(() => { + mountComponent(); + fillForm(); + }); + + describe('on submit', () => { + beforeEach(async () => { + findSubmitButton().trigger('click'); + await waitForPromises(); + }); + + it('should call the mutation with the right variables', () => { + expect(responseSpy).toHaveBeenCalledWith(expectedData); + }); + + it('should close the form on successful addition', () => { + expect(wrapper.emitted()).toEqual(closeFormEvent); + }); + }); + + describe('on submit and add', () => { + beforeEach(async () => { + findSubmitAndAddButton().trigger('click'); + await waitForPromises(); + }); + + it('should keep the form open for save and add another', () => { + expect(wrapper.emitted()).toEqual({}); + }); + }); + + describe('on cancel', () => { + beforeEach(async () => { + findCancelButton().trigger('click'); + await waitForPromises(); + }); + + it('should close the form', () => { + expect(wrapper.emitted()).toEqual(closeFormEvent); + }); + }); + }); + + describe('error handling', () => { + it('should show an error when submission returns an error', async () => { + const expectedAlertArgs = { + message: `Error creating incident timeline event: ${timelineEventsCreateEventError.data.timelineEventCreate.errors[0]}`, + }; + responseSpy.mockResolvedValueOnce(timelineEventsCreateEventError); + mountComponent(); + + findSubmitButton().trigger('click'); + await waitForPromises(); + + expect(createAlert).toHaveBeenCalledWith(expectedAlertArgs); + }); + + it('should show an error when submission fails', async () => { + const expectedAlertArgs = { + captureError: true, + error: new Error(), + message: 'Something went wrong while creating the incident timeline event.', + }; + responseSpy.mockRejectedValueOnce(); + mountComponent(); + + findSubmitButton().trigger('click'); + await waitForPromises(); + + expect(createAlert).toHaveBeenCalledWith(expectedAlertArgs); + }); + + it('should keep the form open on failed addition', async () => { + responseSpy.mockResolvedValueOnce(timelineEventsCreateEventError); + mountComponent(); + + await wrapper.findComponent(TimelineEventsForm).vm.$emit('save-event', mockInputData); + await waitForPromises; + expect(wrapper.emitted()).toEqual({}); + }); + }); +}); diff --git a/spec/frontend/issues/show/components/incidents/mock_data.js b/spec/frontend/issues/show/components/incidents/mock_data.js index afc6099caf4..75c0a7350ae 100644 --- a/spec/frontend/issues/show/components/incidents/mock_data.js +++ b/spec/frontend/issues/show/components/incidents/mock_data.js @@ -72,10 +72,14 @@ export const timelineEventsQueryEmptyResponse = { }; export const timelineEventsCreateEventResponse = { - timelineEvent: { - ...mockEvents[0], + data: { + timelineEventCreate: { + timelineEvent: { + ...mockEvents[0], + }, + errors: [], + }, }, - errors: [], }; export const timelineEventsCreateEventError = { @@ -103,3 +107,21 @@ const timelineEventDeleteData = (errors = []) => { export const timelineEventsDeleteEventResponse = timelineEventDeleteData(); export const timelineEventsDeleteEventError = timelineEventDeleteData(['Item does not exist']); + +export const mockGetTimelineData = { + project: { + id: 'gid://gitlab/Project/19', + incidentManagementTimelineEvents: { + nodes: [ + { + id: 'gid://gitlab/IncidentManagement::TimelineEvent/8', + note: 'another one2', + noteHtml: '<p>another one2</p>', + action: 'comment', + occurredAt: '2022-07-01T12:47:00Z', + createdAt: '2022-07-20T12:47:40Z', + }, + ], + }, + }, +}; diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js index 620cdfc53b0..cd2cbb63246 100644 --- a/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js +++ b/spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js @@ -3,49 +3,33 @@ import Vue, { nextTick } from 'vue'; import { GlDatepicker } from '@gitlab/ui'; import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import IncidentTimelineEventForm from '~/issues/show/components/incidents/timeline_events_form.vue'; -import createTimelineEventMutation from '~/issues/show/components/incidents/graphql/queries/create_timeline_event.mutation.graphql'; -import createMockApollo from 'helpers/mock_apollo_helper'; +import TimelineEventsForm from '~/issues/show/components/incidents/timeline_events_form.vue'; import { createAlert } from '~/flash'; import { useFakeDate } from 'helpers/fake_date'; -import { timelineEventsCreateEventResponse, timelineEventsCreateEventError } from './mock_data'; Vue.use(VueApollo); jest.mock('~/flash'); -const addEventResponse = jest.fn().mockResolvedValue(timelineEventsCreateEventResponse); - -function createMockApolloProvider(response = addEventResponse) { - const requestHandlers = [[createTimelineEventMutation, response]]; - return createMockApollo(requestHandlers); -} +const fakeDate = '2020-07-08T00:00:00.000Z'; describe('Timeline events form', () => { // July 8 2020 - useFakeDate(2020, 6, 8); + useFakeDate(fakeDate); let wrapper; - const mountComponent = ({ mockApollo, mountMethod = shallowMountExtended, stubs }) => { - wrapper = mountMethod(IncidentTimelineEventForm, { + const mountComponent = ({ mountMethod = shallowMountExtended }) => { + wrapper = mountMethod(TimelineEventsForm, { propsData: { hasTimelineEvents: true, + isEventProcessed: false, }, - provide: { - fullPath: 'group/project', - issuableId: '1', - }, - apolloProvider: mockApollo, - stubs, }); }; afterEach(() => { - addEventResponse.mockReset(); createAlert.mockReset(); - if (wrapper) { - wrapper.destroy(); - } + wrapper.destroy(); }); const findSubmitButton = () => wrapper.findByText('Save'); @@ -75,24 +59,28 @@ describe('Timeline events form', () => { }; describe('form button behaviour', () => { - const closeFormEvent = { 'hide-incident-timeline-event-form': [[]] }; beforeEach(() => { - mountComponent({ mockApollo: createMockApolloProvider(), mountMethod: mountExtended }); + mountComponent({ mountMethod: mountExtended }); }); - it('should close the form on submit', async () => { + it('should save event on submit', async () => { await submitForm(); - expect(wrapper.emitted()).toEqual(closeFormEvent); + + expect(wrapper.emitted()).toEqual({ + 'save-event': [[{ note: '', occurredAt: fakeDate }, false]], + }); }); - it('should not close the form on "submit and add another"', async () => { + it('should save event on "submit and add another"', async () => { await submitFormAndAddAnother(); - expect(wrapper.emitted()).toEqual({}); + expect(wrapper.emitted()).toEqual({ + 'save-event': [[{ note: '', occurredAt: fakeDate }, true]], + }); }); - it('should close the form on cancel', async () => { + it('should emit cancel on cancel', async () => { await cancelForm(); - expect(wrapper.emitted()).toEqual(closeFormEvent); + expect(wrapper.emitted()).toEqual({ cancel: [[]] }); }); it('should clear the form', async () => { @@ -111,71 +99,4 @@ describe('Timeline events form', () => { expect(findMinuteInput().element.value).toBe('0'); }); }); - - describe('addTimelineEventQuery', () => { - const expectedData = { - input: { - incidentId: 'gid://gitlab/Issue/1', - note: '', - occurredAt: '2020-07-08T00:00:00.000Z', - }, - }; - - let mockApollo; - - beforeEach(() => { - mockApollo = createMockApolloProvider(); - mountComponent({ mockApollo, mountMethod: mountExtended }); - }); - - it('should call the mutation with the right variables', async () => { - await submitForm(); - - expect(addEventResponse).toHaveBeenCalledWith(expectedData); - }); - - it('should call the mutation with user selected variables', async () => { - const expectedUserSelectedData = { - input: { - ...expectedData.input, - occurredAt: '2021-08-12T05:45:00.000Z', - }, - }; - - setDatetime(); - - await nextTick(); - await submitForm(); - - expect(addEventResponse).toHaveBeenCalledWith(expectedUserSelectedData); - }); - }); - - describe('error handling', () => { - it('should show an error when submission returns an error', async () => { - const expectedAlertArgs = { - message: 'Error creating incident timeline event: Create error', - }; - addEventResponse.mockResolvedValueOnce(timelineEventsCreateEventError); - mountComponent({ mockApollo: createMockApolloProvider(), mountMethod: mountExtended }); - - await submitForm(); - - expect(createAlert).toHaveBeenCalledWith(expectedAlertArgs); - }); - - it('should show an error when submission fails', async () => { - const expectedAlertArgs = { - captureError: true, - error: new Error(), - message: 'Something went wrong while creating the incident timeline event.', - }; - addEventResponse.mockRejectedValueOnce(); - mountComponent({ mockApollo: createMockApolloProvider(), mountMethod: mountExtended }); - - await submitForm(); - - expect(createAlert).toHaveBeenCalledWith(expectedAlertArgs); - }); - }); }); diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_list_item_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js index e686f2eb4ec..90e55003ab3 100644 --- a/spec/frontend/issues/show/components/incidents/timeline_events_list_item_spec.js +++ b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js @@ -2,7 +2,7 @@ import timezoneMock from 'timezone-mock'; import { GlIcon, GlDropdown } from '@gitlab/ui'; import { nextTick } from 'vue'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import IncidentTimelineEventListItem from '~/issues/show/components/incidents/timeline_events_list_item.vue'; +import IncidentTimelineEventItem from '~/issues/show/components/incidents/timeline_events_item.vue'; import { mockEvents } from './mock_data'; describe('IncidentTimelineEventList', () => { @@ -10,7 +10,7 @@ describe('IncidentTimelineEventList', () => { const mountComponent = ({ propsData, provide } = {}) => { const { action, noteHtml, occurredAt } = mockEvents[0]; - wrapper = mountExtended(IncidentTimelineEventListItem, { + wrapper = mountExtended(IncidentTimelineEventItem, { propsData: { action, noteHtml, diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js index ae07237cf7d..4d2d53c990e 100644 --- a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js +++ b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js @@ -3,7 +3,7 @@ import VueApollo from 'vue-apollo'; import Vue from 'vue'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; import IncidentTimelineEventList from '~/issues/show/components/incidents/timeline_events_list.vue'; -import IncidentTimelineEventListItem from '~/issues/show/components/incidents/timeline_events_list_item.vue'; +import IncidentTimelineEventListItem from '~/issues/show/components/incidents/timeline_events_item.vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import deleteTimelineEventMutation from '~/issues/show/components/incidents/graphql/queries/delete_timeline_event.mutation.graphql'; diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js index 2d87851a761..2cdb971395d 100644 --- a/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js +++ b/spec/frontend/issues/show/components/incidents/timeline_events_tab_spec.js @@ -5,7 +5,7 @@ import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_help import waitForPromises from 'helpers/wait_for_promises'; import TimelineEventsTab from '~/issues/show/components/incidents/timeline_events_tab.vue'; import IncidentTimelineEventsList from '~/issues/show/components/incidents/timeline_events_list.vue'; -import IncidentTimelineEventForm from '~/issues/show/components/incidents/timeline_events_form.vue'; +import CreateTimelineEvent from '~/issues/show/components/incidents/create_timeline_event.vue'; import timelineEventsQuery from '~/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import { createAlert } from '~/flash'; @@ -53,7 +53,7 @@ describe('TimelineEventsTab', () => { const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon); const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findTimelineEventsList = () => wrapper.findComponent(IncidentTimelineEventsList); - const findTimelineEventForm = () => wrapper.findComponent(IncidentTimelineEventForm); + const findCreateTimelineEvent = () => wrapper.findComponent(CreateTimelineEvent); const findAddEventButton = () => wrapper.findByText(timelineTabI18n.addEventButton); describe('Timeline events tab', () => { @@ -143,18 +143,18 @@ describe('TimelineEventsTab', () => { }); it('should not show a form by default', () => { - expect(findTimelineEventForm().isVisible()).toBe(false); + expect(findCreateTimelineEvent().isVisible()).toBe(false); }); it('should show a form when button is clicked', async () => { await findAddEventButton().trigger('click'); - expect(findTimelineEventForm().isVisible()).toBe(true); + expect(findCreateTimelineEvent().isVisible()).toBe(true); }); it('should clear the form when button is clicked', async () => { const mockClear = jest.fn(); - wrapper.vm.$refs.eventForm.clear = mockClear; + wrapper.vm.$refs.createEventForm.clearForm = mockClear; await findAddEventButton().trigger('click'); @@ -165,9 +165,9 @@ describe('TimelineEventsTab', () => { // open the form await findAddEventButton().trigger('click'); - await findTimelineEventForm().vm.$emit('hide-incident-timeline-event-form'); + await findCreateTimelineEvent().vm.$emit('hide-new-timeline-events-form'); - expect(findTimelineEventForm().isVisible()).toBe(false); + expect(findCreateTimelineEvent().isVisible()).toBe(false); }); }); }); diff --git a/spec/frontend/issues/show/components/incidents/utils_spec.js b/spec/frontend/issues/show/components/incidents/utils_spec.js index 0da0114c654..d3a86680f14 100644 --- a/spec/frontend/issues/show/components/incidents/utils_spec.js +++ b/spec/frontend/issues/show/components/incidents/utils_spec.js @@ -24,7 +24,7 @@ describe('incident utils', () => { describe('get event icon', () => { it('should display a matching event icon name', () => { - ['comment', 'issues', 'status'].forEach((name) => { + ['comment', 'issues', 'label', 'status'].forEach((name) => { expect(getEventIcon(name)).toBe(name); }); }); |