summaryrefslogtreecommitdiff
path: root/spec/frontend/issue_show
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/issue_show')
-rw-r--r--spec/frontend/issue_show/components/app_spec.js682
-rw-r--r--spec/frontend/issue_show/components/description_spec.js187
-rw-r--r--spec/frontend/issue_show/components/edit_actions_spec.js163
-rw-r--r--spec/frontend/issue_show/components/edited_spec.js49
-rw-r--r--spec/frontend/issue_show/components/fields/description_spec.js70
-rw-r--r--spec/frontend/issue_show/components/fields/description_template_spec.js74
-rw-r--r--spec/frontend/issue_show/components/fields/title_spec.js42
-rw-r--r--spec/frontend/issue_show/components/fields/type_spec.js120
-rw-r--r--spec/frontend/issue_show/components/form_spec.js155
-rw-r--r--spec/frontend/issue_show/components/header_actions_spec.js348
-rw-r--r--spec/frontend/issue_show/components/incidents/highlight_bar_spec.js94
-rw-r--r--spec/frontend/issue_show/components/incidents/incident_tabs_spec.js143
-rw-r--r--spec/frontend/issue_show/components/pinned_links_spec.js48
-rw-r--r--spec/frontend/issue_show/components/title_spec.js95
-rw-r--r--spec/frontend/issue_show/issue_spec.js40
-rw-r--r--spec/frontend/issue_show/mock_data/apollo_mock.js9
-rw-r--r--spec/frontend/issue_show/mock_data/mock_data.js60
-rw-r--r--spec/frontend/issue_show/store_spec.js39
-rw-r--r--spec/frontend/issue_show/utils/update_description_spec.js24
19 files changed, 0 insertions, 2442 deletions
diff --git a/spec/frontend/issue_show/components/app_spec.js b/spec/frontend/issue_show/components/app_spec.js
deleted file mode 100644
index e32215b4aa6..00000000000
--- a/spec/frontend/issue_show/components/app_spec.js
+++ /dev/null
@@ -1,682 +0,0 @@
-import { GlIntersectionObserver } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import '~/behaviors/markdown/render_gfm';
-import IssuableApp from '~/issue_show/components/app.vue';
-import DescriptionComponent from '~/issue_show/components/description.vue';
-import IncidentTabs from '~/issue_show/components/incidents/incident_tabs.vue';
-import PinnedLinks from '~/issue_show/components/pinned_links.vue';
-import { IssuableStatus, IssuableStatusText, POLLING_DELAY } from '~/issue_show/constants';
-import eventHub from '~/issue_show/event_hub';
-import axios from '~/lib/utils/axios_utils';
-import { visitUrl } from '~/lib/utils/url_utility';
-import {
- appProps,
- initialRequest,
- publishedIncidentUrl,
- secondRequest,
- zoomMeetingUrl,
-} from '../mock_data/mock_data';
-
-function formatText(text) {
- return text.trim().replace(/\s\s+/g, ' ');
-}
-
-jest.mock('~/lib/utils/url_utility');
-jest.mock('~/issue_show/event_hub');
-
-const REALTIME_REQUEST_STACK = [initialRequest, secondRequest];
-
-describe('Issuable output', () => {
- let mock;
- let realtimeRequestCount = 0;
- let wrapper;
-
- const findStickyHeader = () => wrapper.findByTestId('issue-sticky-header');
- const findLockedBadge = () => wrapper.findByTestId('locked');
- const findConfidentialBadge = () => wrapper.findByTestId('confidential');
- const findHiddenBadge = () => wrapper.findByTestId('hidden');
- const findAlert = () => wrapper.find('.alert');
-
- const mountComponent = (props = {}, options = {}, data = {}) => {
- wrapper = mountExtended(IssuableApp, {
- directives: {
- GlTooltip: createMockDirective(),
- },
- propsData: { ...appProps, ...props },
- provide: {
- fullPath: 'gitlab-org/incidents',
- iid: '19',
- uploadMetricsFeatureAvailable: false,
- },
- stubs: {
- HighlightBar: true,
- IncidentTabs: true,
- },
- data() {
- return {
- ...data,
- };
- },
- ...options,
- });
- };
-
- beforeEach(() => {
- setFixtures(`
- <div>
- <title>Title</title>
- <div class="detail-page-description content-block">
- <details open>
- <summary>One</summary>
- </details>
- <details>
- <summary>Two</summary>
- </details>
- </div>
- <div class="flash-container"></div>
- <span id="task_status"></span>
- </div>
- `);
-
- mock = new MockAdapter(axios);
- mock
- .onGet('/gitlab-org/gitlab-shell/-/issues/9/realtime_changes/realtime_changes')
- .reply(() => {
- const res = Promise.resolve([200, REALTIME_REQUEST_STACK[realtimeRequestCount]]);
- realtimeRequestCount += 1;
- return res;
- });
-
- mountComponent();
-
- jest.advanceTimersByTime(2);
- });
-
- afterEach(() => {
- mock.restore();
- realtimeRequestCount = 0;
- wrapper.vm.poll.stop();
- wrapper.destroy();
- });
-
- it('should render a title/description/edited and update title/description/edited on update', () => {
- let editedText;
- return axios
- .waitForAll()
- .then(() => {
- editedText = wrapper.find('.edited-text');
- })
- .then(() => {
- expect(document.querySelector('title').innerText).toContain('this is a title (#1)');
- expect(wrapper.find('.title').text()).toContain('this is a title');
- expect(wrapper.find('.md').text()).toContain('this is a description!');
- expect(wrapper.find('.js-task-list-field').element.value).toContain(
- 'this is a description',
- );
-
- expect(formatText(editedText.text())).toMatch(/Edited[\s\S]+?by Some User/);
- expect(editedText.find('.author-link').attributes('href')).toMatch(/\/some_user$/);
- expect(editedText.find('time').text()).toBeTruthy();
- expect(wrapper.vm.state.lock_version).toBe(initialRequest.lock_version);
- })
- .then(() => {
- wrapper.vm.poll.makeRequest();
- return axios.waitForAll();
- })
- .then(() => {
- expect(document.querySelector('title').innerText).toContain('2 (#1)');
- expect(wrapper.find('.title').text()).toContain('2');
- expect(wrapper.find('.md').text()).toContain('42');
- expect(wrapper.find('.js-task-list-field').element.value).toContain('42');
- expect(wrapper.find('.edited-text').text()).toBeTruthy();
- expect(formatText(wrapper.find('.edited-text').text())).toMatch(
- /Edited[\s\S]+?by Other User/,
- );
-
- expect(editedText.find('.author-link').attributes('href')).toMatch(/\/other_user$/);
- expect(editedText.find('time').text()).toBeTruthy();
- // As the lock_version value does not differ from the server,
- // we should not see an alert
- expect(findAlert().exists()).toBe(false);
- });
- });
-
- it('shows actions if permissions are correct', () => {
- wrapper.vm.showForm = true;
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.find('.markdown-selector').exists()).toBe(true);
- });
- });
-
- it('does not show actions if permissions are incorrect', () => {
- wrapper.vm.showForm = true;
- wrapper.setProps({ canUpdate: false });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.find('.markdown-selector').exists()).toBe(false);
- });
- });
-
- it('does not update formState if form is already open', () => {
- wrapper.vm.updateAndShowForm();
-
- wrapper.vm.state.titleText = 'testing 123';
-
- wrapper.vm.updateAndShowForm();
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.store.formState.title).not.toBe('testing 123');
- });
- });
-
- describe('Pinned links propagated', () => {
- it.each`
- prop | value
- ${'zoomMeetingUrl'} | ${zoomMeetingUrl}
- ${'publishedIncidentUrl'} | ${publishedIncidentUrl}
- `('sets the $prop correctly on underlying pinned links', ({ prop, value }) => {
- expect(wrapper.vm[prop]).toBe(value);
- expect(wrapper.find(`[data-testid="${prop}"]`).attributes('href')).toBe(value);
- });
- });
-
- describe('updateIssuable', () => {
- it('fetches new data after update', () => {
- const updateStoreSpy = jest.spyOn(wrapper.vm, 'updateStoreState');
- const getDataSpy = jest.spyOn(wrapper.vm.service, 'getData');
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: { web_url: window.location.pathname },
- });
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(updateStoreSpy).toHaveBeenCalled();
- expect(getDataSpy).toHaveBeenCalled();
- });
- });
-
- it('correctly updates issuable data', () => {
- const spy = jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: { web_url: window.location.pathname },
- });
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(spy).toHaveBeenCalledWith(wrapper.vm.formState);
- expect(eventHub.$emit).toHaveBeenCalledWith('close.form');
- });
- });
-
- it('does not redirect if issue has not moved', () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: window.location.pathname,
- confidential: wrapper.vm.isConfidential,
- },
- });
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(visitUrl).not.toHaveBeenCalled();
- });
- });
-
- it('does not redirect if issue has not moved and user has switched tabs', () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: '',
- confidential: wrapper.vm.isConfidential,
- },
- });
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(visitUrl).not.toHaveBeenCalled();
- });
- });
-
- it('redirects if returned web_url has changed', () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({
- data: {
- web_url: '/testing-issue-move',
- confidential: wrapper.vm.isConfidential,
- },
- });
-
- wrapper.vm.updateIssuable();
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(visitUrl).toHaveBeenCalledWith('/testing-issue-move');
- });
- });
-
- describe('shows dialog when issue has unsaved changed', () => {
- it('confirms on title change', () => {
- wrapper.vm.showForm = true;
- wrapper.vm.state.titleText = 'title has changed';
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
-
- return wrapper.vm.$nextTick().then(() => {
- expect(e.returnValue).not.toBeNull();
- });
- });
-
- it('confirms on description change', () => {
- wrapper.vm.showForm = true;
- wrapper.vm.state.descriptionText = 'description has changed';
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
-
- return wrapper.vm.$nextTick().then(() => {
- expect(e.returnValue).not.toBeNull();
- });
- });
-
- it('does nothing when nothing has changed', () => {
- const e = { returnValue: null };
- wrapper.vm.handleBeforeUnloadEvent(e);
-
- return wrapper.vm.$nextTick().then(() => {
- expect(e.returnValue).toBeNull();
- });
- });
- });
-
- describe('error when updating', () => {
- it('closes form on error', () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockRejectedValue();
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- `Error updating issue`,
- );
- });
- });
-
- it('returns the correct error message for issuableType', () => {
- jest.spyOn(wrapper.vm.service, 'updateIssuable').mockRejectedValue();
- wrapper.setProps({ issuableType: 'merge request' });
-
- return wrapper.vm
- .$nextTick()
- .then(wrapper.vm.updateIssuable)
- .then(() => {
- expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- `Error updating merge request`,
- );
- });
- });
-
- it('shows error message from backend if exists', () => {
- const msg = 'Custom error message from backend';
- jest
- .spyOn(wrapper.vm.service, 'updateIssuable')
- .mockRejectedValue({ response: { data: { errors: [msg] } } });
-
- return wrapper.vm.updateIssuable().then(() => {
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- `${wrapper.vm.defaultErrorMessage}. ${msg}`,
- );
- });
- });
- });
- });
-
- describe('deleteIssuable', () => {
- it('changes URL when deleted', () => {
- jest.spyOn(wrapper.vm.service, 'deleteIssuable').mockResolvedValue({
- data: {
- web_url: '/test',
- },
- });
-
- return wrapper.vm.deleteIssuable().then(() => {
- expect(visitUrl).toHaveBeenCalledWith('/test');
- });
- });
-
- it('stops polling when deleting', () => {
- const spy = jest.spyOn(wrapper.vm.poll, 'stop');
- jest.spyOn(wrapper.vm.service, 'deleteIssuable').mockResolvedValue({
- data: {
- web_url: '/test',
- },
- });
-
- return wrapper.vm.deleteIssuable().then(() => {
- expect(spy).toHaveBeenCalledWith();
- });
- });
-
- it('closes form on error', () => {
- jest.spyOn(wrapper.vm.service, 'deleteIssuable').mockRejectedValue();
-
- return wrapper.vm.deleteIssuable().then(() => {
- expect(eventHub.$emit).not.toHaveBeenCalledWith('close.form');
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- 'Error deleting issue',
- );
- });
- });
- });
-
- describe('updateAndShowForm', () => {
- it('shows locked warning if form is open & data is different', () => {
- return wrapper.vm
- .$nextTick()
- .then(() => {
- wrapper.vm.updateAndShowForm();
-
- wrapper.vm.poll.makeRequest();
-
- return new Promise((resolve) => {
- wrapper.vm.$watch('formState.lockedWarningVisible', (value) => {
- if (value) {
- resolve();
- }
- });
- });
- })
- .then(() => {
- expect(wrapper.vm.formState.lockedWarningVisible).toBe(true);
- expect(wrapper.vm.formState.lock_version).toBe(1);
- expect(findAlert().exists()).toBe(true);
- });
- });
- });
-
- describe('requestTemplatesAndShowForm', () => {
- let formSpy;
-
- beforeEach(() => {
- formSpy = jest.spyOn(wrapper.vm, 'updateAndShowForm');
- });
-
- it('shows the form if template names as hash request is successful', () => {
- const mockData = {
- test: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }],
- };
- mock.onGet('/issuable-templates-path').reply(() => Promise.resolve([200, mockData]));
-
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(formSpy).toHaveBeenCalledWith(mockData);
- });
- });
-
- it('shows the form if template names as array request is successful', () => {
- const mockData = [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }];
- mock.onGet('/issuable-templates-path').reply(() => Promise.resolve([200, mockData]));
-
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(formSpy).toHaveBeenCalledWith(mockData);
- });
- });
-
- it('shows the form if template names request failed', () => {
- mock
- .onGet('/issuable-templates-path')
- .reply(() => Promise.reject(new Error('something went wrong')));
-
- return wrapper.vm.requestTemplatesAndShowForm().then(() => {
- expect(document.querySelector('.flash-container .flash-text').textContent).toContain(
- 'Error updating issue',
- );
-
- expect(formSpy).toHaveBeenCalledWith();
- });
- });
- });
-
- describe('show inline edit button', () => {
- it('should not render by default', () => {
- expect(wrapper.find('.btn-edit').exists()).toBe(true);
- });
-
- it('should render if showInlineEditButton', () => {
- wrapper.setProps({ showInlineEditButton: true });
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.find('.btn-edit').exists()).toBe(true);
- });
- });
- });
-
- describe('updateStoreState', () => {
- it('should make a request and update the state of the store', () => {
- const data = { foo: 1 };
- const getDataSpy = jest.spyOn(wrapper.vm.service, 'getData').mockResolvedValue({ data });
- const updateStateSpy = jest
- .spyOn(wrapper.vm.store, 'updateState')
- .mockImplementation(jest.fn);
-
- return wrapper.vm.updateStoreState().then(() => {
- expect(getDataSpy).toHaveBeenCalled();
- expect(updateStateSpy).toHaveBeenCalledWith(data);
- });
- });
-
- it('should show error message if store update fails', () => {
- jest.spyOn(wrapper.vm.service, 'getData').mockRejectedValue();
- wrapper.setProps({ issuableType: 'merge request' });
-
- return wrapper.vm.updateStoreState().then(() => {
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
- `Error updating ${wrapper.vm.issuableType}`,
- );
- });
- });
- });
-
- describe('issueChanged', () => {
- beforeEach(() => {
- wrapper.vm.store.formState.title = '';
- wrapper.vm.store.formState.description = '';
- wrapper.setProps({
- initialDescriptionText: '',
- initialTitleText: '',
- });
- });
-
- it('returns true when title is changed', () => {
- wrapper.vm.store.formState.title = 'RandomText';
-
- expect(wrapper.vm.issueChanged).toBe(true);
- });
-
- it('returns false when title is empty null', () => {
- wrapper.vm.store.formState.title = null;
-
- expect(wrapper.vm.issueChanged).toBe(false);
- });
-
- it('returns true when description is changed', () => {
- wrapper.vm.store.formState.description = 'RandomText';
-
- expect(wrapper.vm.issueChanged).toBe(true);
- });
-
- it('returns false when description is empty null', () => {
- wrapper.vm.store.formState.description = null;
-
- expect(wrapper.vm.issueChanged).toBe(false);
- });
-
- it('returns false when `initialDescriptionText` is null and `formState.description` is empty string', () => {
- wrapper.vm.store.formState.description = '';
- wrapper.setProps({ initialDescriptionText: null });
-
- expect(wrapper.vm.issueChanged).toBe(false);
- });
- });
-
- describe('sticky header', () => {
- describe('when title is in view', () => {
- it('is not shown', () => {
- expect(findStickyHeader().exists()).toBe(false);
- });
- });
-
- describe('when title is not in view', () => {
- beforeEach(() => {
- wrapper.vm.state.titleText = 'Sticky header title';
- wrapper.find(GlIntersectionObserver).vm.$emit('disappear');
- });
-
- it('shows with title', () => {
- expect(findStickyHeader().text()).toContain('Sticky header title');
- });
-
- it.each`
- title | state
- ${'shows with Open when status is opened'} | ${IssuableStatus.Open}
- ${'shows with Closed when status is closed'} | ${IssuableStatus.Closed}
- ${'shows with Open when status is reopened'} | ${IssuableStatus.Reopened}
- `('$title', async ({ state }) => {
- wrapper.setProps({ issuableStatus: state });
-
- await nextTick();
-
- expect(findStickyHeader().text()).toContain(IssuableStatusText[state]);
- });
-
- it.each`
- title | isConfidential
- ${'does not show confidential badge when issue is not confidential'} | ${false}
- ${'shows confidential badge when issue is confidential'} | ${true}
- `('$title', async ({ isConfidential }) => {
- wrapper.setProps({ isConfidential });
-
- await nextTick();
-
- expect(findConfidentialBadge().exists()).toBe(isConfidential);
- });
-
- it.each`
- title | isLocked
- ${'does not show locked badge when issue is not locked'} | ${false}
- ${'shows locked badge when issue is locked'} | ${true}
- `('$title', async ({ isLocked }) => {
- wrapper.setProps({ isLocked });
-
- await nextTick();
-
- expect(findLockedBadge().exists()).toBe(isLocked);
- });
-
- it.each`
- title | isHidden
- ${'does not show hidden badge when issue is not hidden'} | ${false}
- ${'shows hidden badge when issue is hidden'} | ${true}
- `('$title', async ({ isHidden }) => {
- wrapper.setProps({ isHidden });
-
- await nextTick();
-
- const hiddenBadge = findHiddenBadge();
-
- expect(hiddenBadge.exists()).toBe(isHidden);
-
- if (isHidden) {
- expect(hiddenBadge.attributes('title')).toBe(
- 'This issue is hidden because its author has been banned',
- );
- expect(getBinding(hiddenBadge.element, 'gl-tooltip')).not.toBeUndefined();
- }
- });
- });
- });
-
- describe('Composable description component', () => {
- const findIncidentTabs = () => wrapper.findComponent(IncidentTabs);
- const findDescriptionComponent = () => wrapper.findComponent(DescriptionComponent);
- const findPinnedLinks = () => wrapper.findComponent(PinnedLinks);
- const borderClass = 'gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mb-6';
-
- describe('when using description component', () => {
- it('renders the description component', () => {
- expect(findDescriptionComponent().exists()).toBe(true);
- });
-
- it('does not render incident tabs', () => {
- expect(findIncidentTabs().exists()).toBe(false);
- });
-
- it('adds a border below the header', () => {
- expect(findPinnedLinks().attributes('class')).toContain(borderClass);
- });
- });
-
- describe('when using incident tabs description wrapper', () => {
- beforeEach(() => {
- mountComponent(
- {
- descriptionComponent: IncidentTabs,
- showTitleBorder: false,
- },
- {
- mocks: {
- $apollo: {
- queries: {
- alert: {
- loading: false,
- },
- },
- },
- },
- },
- );
- });
-
- it('renders the description component', () => {
- expect(findDescriptionComponent().exists()).toBe(true);
- });
-
- it('renders incident tabs', () => {
- expect(findIncidentTabs().exists()).toBe(true);
- });
-
- it('does not add a border below the header', () => {
- expect(findPinnedLinks().attributes('class')).not.toContain(borderClass);
- });
- });
- });
-
- describe('taskListUpdateStarted', () => {
- it('stops polling', () => {
- jest.spyOn(wrapper.vm.poll, 'stop');
-
- wrapper.vm.taskListUpdateStarted();
-
- expect(wrapper.vm.poll.stop).toHaveBeenCalled();
- });
- });
-
- describe('taskListUpdateSucceeded', () => {
- it('enables polling', () => {
- jest.spyOn(wrapper.vm.poll, 'enable');
- jest.spyOn(wrapper.vm.poll, 'makeDelayedRequest');
-
- wrapper.vm.taskListUpdateSucceeded();
-
- expect(wrapper.vm.poll.enable).toHaveBeenCalled();
- expect(wrapper.vm.poll.makeDelayedRequest).toHaveBeenCalledWith(POLLING_DELAY);
- });
- });
-
- describe('taskListUpdateFailed', () => {
- it('enables polling and calls updateStoreState', () => {
- jest.spyOn(wrapper.vm.poll, 'enable');
- jest.spyOn(wrapper.vm.poll, 'makeDelayedRequest');
- jest.spyOn(wrapper.vm, 'updateStoreState');
-
- wrapper.vm.taskListUpdateFailed();
-
- expect(wrapper.vm.poll.enable).toHaveBeenCalled();
- expect(wrapper.vm.poll.makeDelayedRequest).toHaveBeenCalledWith(POLLING_DELAY);
- expect(wrapper.vm.updateStoreState).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/description_spec.js b/spec/frontend/issue_show/components/description_spec.js
deleted file mode 100644
index bdcc82cab81..00000000000
--- a/spec/frontend/issue_show/components/description_spec.js
+++ /dev/null
@@ -1,187 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import '~/behaviors/markdown/render_gfm';
-import { TEST_HOST } from 'helpers/test_constants';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import Description from '~/issue_show/components/description.vue';
-import TaskList from '~/task_list';
-import { descriptionProps as props } from '../mock_data/mock_data';
-
-jest.mock('~/task_list');
-
-describe('Description component', () => {
- let vm;
- let DescriptionComponent;
-
- beforeEach(() => {
- DescriptionComponent = Vue.extend(Description);
-
- if (!document.querySelector('.issuable-meta')) {
- const metaData = document.createElement('div');
- metaData.classList.add('issuable-meta');
- metaData.innerHTML =
- '<div class="flash-container"></div><span id="task_status"></span><span id="task_status_short"></span>';
-
- document.body.appendChild(metaData);
- }
-
- vm = mountComponent(DescriptionComponent, props);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- afterAll(() => {
- $('.issuable-meta .flash-container').remove();
- });
-
- it('doesnt animate first description changes', () => {
- vm.descriptionHtml = 'changed';
-
- return vm.$nextTick().then(() => {
- expect(
- vm.$el.querySelector('.md').classList.contains('issue-realtime-pre-pulse'),
- ).toBeFalsy();
- jest.runAllTimers();
- return vm.$nextTick();
- });
- });
-
- it('animates description changes on live update', () => {
- vm.descriptionHtml = 'changed';
- return vm
- .$nextTick()
- .then(() => {
- vm.descriptionHtml = 'changed second time';
- return vm.$nextTick();
- })
- .then(() => {
- expect(
- vm.$el.querySelector('.md').classList.contains('issue-realtime-pre-pulse'),
- ).toBeTruthy();
- jest.runAllTimers();
- return vm.$nextTick();
- })
- .then(() => {
- expect(
- vm.$el.querySelector('.md').classList.contains('issue-realtime-trigger-pulse'),
- ).toBeTruthy();
- });
- });
-
- it('applies syntax highlighting and math when description changed', () => {
- const vmSpy = jest.spyOn(vm, 'renderGFM');
- const prototypeSpy = jest.spyOn($.prototype, 'renderGFM');
- vm.descriptionHtml = 'changed';
-
- return vm.$nextTick().then(() => {
- expect(vm.$refs['gfm-content']).toBeDefined();
- expect(vmSpy).toHaveBeenCalled();
- expect(prototypeSpy).toHaveBeenCalled();
- expect($.prototype.renderGFM).toHaveBeenCalled();
- });
- });
-
- it('sets data-update-url', () => {
- expect(vm.$el.querySelector('textarea').dataset.updateUrl).toEqual(TEST_HOST);
- });
-
- describe('TaskList', () => {
- beforeEach(() => {
- vm.$destroy();
- TaskList.mockClear();
- vm = mountComponent(DescriptionComponent, { ...props, issuableType: 'issuableType' });
- });
-
- it('re-inits the TaskList when description changed', () => {
- vm.descriptionHtml = 'changed';
-
- expect(TaskList).toHaveBeenCalled();
- });
-
- it('does not re-init the TaskList when canUpdate is false', () => {
- vm.canUpdate = false;
- vm.descriptionHtml = 'changed';
-
- expect(TaskList).toHaveBeenCalledTimes(1);
- });
-
- it('calls with issuableType dataType', () => {
- vm.descriptionHtml = 'changed';
-
- expect(TaskList).toHaveBeenCalledWith({
- dataType: 'issuableType',
- fieldName: 'description',
- selector: '.detail-page-description',
- onUpdate: expect.any(Function),
- onSuccess: expect.any(Function),
- onError: expect.any(Function),
- lockVersion: 0,
- });
- });
- });
-
- describe('taskStatus', () => {
- it('adds full taskStatus', () => {
- vm.taskStatus = '1 of 1';
-
- return vm.$nextTick().then(() => {
- expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe(
- '1 of 1',
- );
- });
- });
-
- it('adds short taskStatus', () => {
- vm.taskStatus = '1 of 1';
-
- return vm.$nextTick().then(() => {
- expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe(
- '1/1 task',
- );
- });
- });
-
- it('clears task status text when no tasks are present', () => {
- vm.taskStatus = '0 of 0';
-
- return vm.$nextTick().then(() => {
- expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe('');
- });
- });
- });
-
- describe('taskListUpdateStarted', () => {
- it('emits event to parent', () => {
- const spy = jest.spyOn(vm, '$emit');
-
- vm.taskListUpdateStarted();
-
- expect(spy).toHaveBeenCalledWith('taskListUpdateStarted');
- });
- });
-
- describe('taskListUpdateSuccess', () => {
- it('emits event to parent', () => {
- const spy = jest.spyOn(vm, '$emit');
-
- vm.taskListUpdateSuccess();
-
- expect(spy).toHaveBeenCalledWith('taskListUpdateSucceeded');
- });
- });
-
- describe('taskListUpdateError', () => {
- it('should create flash notification and emit an event to parent', () => {
- const msg =
- 'Someone edited this issue at the same time you did. The description has been updated and you will need to make your changes again.';
- const spy = jest.spyOn(vm, '$emit');
-
- vm.taskListUpdateError();
-
- expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(msg);
- expect(spy).toHaveBeenCalledWith('taskListUpdateFailed');
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/edit_actions_spec.js b/spec/frontend/issue_show/components/edit_actions_spec.js
deleted file mode 100644
index 50c27cb5bda..00000000000
--- a/spec/frontend/issue_show/components/edit_actions_spec.js
+++ /dev/null
@@ -1,163 +0,0 @@
-import { GlButton, GlModal } from '@gitlab/ui';
-import { createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import IssuableEditActions from '~/issue_show/components/edit_actions.vue';
-import eventHub from '~/issue_show/event_hub';
-
-import {
- getIssueStateQueryResponse,
- updateIssueStateQueryResponse,
-} from '../mock_data/apollo_mock';
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-describe('Edit Actions component', () => {
- let wrapper;
- let fakeApollo;
- let mockIssueStateData;
-
- const mockResolvers = {
- Query: {
- issueState() {
- return {
- __typename: 'IssueState',
- rawData: mockIssueStateData(),
- };
- },
- },
- };
-
- const modalId = 'delete-issuable-modal-1';
-
- const createComponent = ({ props, data } = {}) => {
- fakeApollo = createMockApollo([], mockResolvers);
-
- wrapper = shallowMountExtended(IssuableEditActions, {
- apolloProvider: fakeApollo,
- propsData: {
- formState: {
- title: 'GitLab Issue',
- },
- canDestroy: true,
- issuableType: 'issue',
- ...props,
- },
- data() {
- return {
- issueState: {},
- modalId,
- ...data,
- };
- },
- });
- };
-
- async function deleteIssuable(localWrapper) {
- localWrapper.findComponent(GlModal).vm.$emit('primary');
- }
-
- const findModal = () => wrapper.findComponent(GlModal);
- const findEditButtons = () => wrapper.findAllComponents(GlButton);
- const findDeleteButton = () => wrapper.findByTestId('issuable-delete-button');
- const findSaveButton = () => wrapper.findByTestId('issuable-save-button');
- const findCancelButton = () => wrapper.findByTestId('issuable-cancel-button');
-
- beforeEach(() => {
- mockIssueStateData = jest.fn();
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders all buttons as enabled', () => {
- const buttons = findEditButtons().wrappers;
- buttons.forEach((button) => {
- expect(button.attributes('disabled')).toBeFalsy();
- });
- });
-
- it('does not render the delete button if canDestroy is false', () => {
- createComponent({ props: { canDestroy: false } });
- expect(findDeleteButton().exists()).toBe(false);
- });
-
- it('disables save button when title is blank', () => {
- createComponent({ props: { formState: { title: '', issue_type: '' } } });
-
- expect(findSaveButton().attributes('disabled')).toBe('true');
- });
-
- it('does not render the delete button if showDeleteButton is false', () => {
- createComponent({ props: { showDeleteButton: false } });
-
- expect(findDeleteButton().exists()).toBe(false);
- });
-
- describe('updateIssuable', () => {
- beforeEach(() => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- });
-
- it('sends update.issauble event when clicking save button', () => {
- findSaveButton().vm.$emit('click', { preventDefault: jest.fn() });
-
- expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
- });
- });
-
- describe('closeForm', () => {
- beforeEach(() => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- });
-
- it('emits close.form when clicking cancel', () => {
- findCancelButton().vm.$emit('click');
-
- expect(eventHub.$emit).toHaveBeenCalledWith('close.form');
- });
- });
-
- describe('renders create modal with the correct information', () => {
- it('renders correct modal id', () => {
- expect(findModal().attributes('modalid')).toBe(modalId);
- });
- });
-
- describe('deleteIssuable', () => {
- beforeEach(() => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- });
-
- it('does not send the `delete.issuable` event when clicking delete button', () => {
- findDeleteButton().vm.$emit('click');
- expect(eventHub.$emit).not.toHaveBeenCalled();
- });
-
- it('sends the `delete.issuable` event when clicking the delete confirm button', async () => {
- expect(eventHub.$emit).toHaveBeenCalledTimes(0);
- await deleteIssuable(wrapper);
- expect(eventHub.$emit).toHaveBeenCalledWith('delete.issuable', { destroy_confirm: true });
- expect(eventHub.$emit).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('with Apollo cache mock', () => {
- it('renders the right delete button text per apollo cache type', async () => {
- mockIssueStateData.mockResolvedValue(getIssueStateQueryResponse);
- await waitForPromises();
- expect(findDeleteButton().text()).toBe('Delete issue');
- });
-
- it('should not change the delete button text per apollo cache mutation', async () => {
- mockIssueStateData.mockResolvedValue(updateIssueStateQueryResponse);
- await waitForPromises();
- expect(findDeleteButton().text()).toBe('Delete issue');
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/edited_spec.js b/spec/frontend/issue_show/components/edited_spec.js
deleted file mode 100644
index a1683f060c0..00000000000
--- a/spec/frontend/issue_show/components/edited_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Vue from 'vue';
-import edited from '~/issue_show/components/edited.vue';
-
-function formatText(text) {
- return text.trim().replace(/\s\s+/g, ' ');
-}
-
-describe('edited', () => {
- const EditedComponent = Vue.extend(edited);
-
- it('should render an edited at+by string', () => {
- const editedComponent = new EditedComponent({
- propsData: {
- updatedAt: '2017-05-15T12:31:04.428Z',
- updatedByName: 'Some User',
- updatedByPath: '/some_user',
- },
- }).$mount();
-
- expect(formatText(editedComponent.$el.innerText)).toMatch(/Edited[\s\S]+?by Some User/);
- expect(editedComponent.$el.querySelector('.author-link').href).toMatch(/\/some_user$/);
- expect(editedComponent.$el.querySelector('time')).toBeTruthy();
- });
-
- it('if no updatedAt is provided, no time element will be rendered', () => {
- const editedComponent = new EditedComponent({
- propsData: {
- updatedByName: 'Some User',
- updatedByPath: '/some_user',
- },
- }).$mount();
-
- expect(formatText(editedComponent.$el.innerText)).toMatch(/Edited by Some User/);
- expect(editedComponent.$el.querySelector('.author-link').href).toMatch(/\/some_user$/);
- expect(editedComponent.$el.querySelector('time')).toBeFalsy();
- });
-
- it('if no updatedByName and updatedByPath is provided, no user element will be rendered', () => {
- const editedComponent = new EditedComponent({
- propsData: {
- updatedAt: '2017-05-15T12:31:04.428Z',
- },
- }).$mount();
-
- expect(formatText(editedComponent.$el.innerText)).not.toMatch(/by Some User/);
- expect(editedComponent.$el.querySelector('.author-link')).toBeFalsy();
- expect(editedComponent.$el.querySelector('time')).toBeTruthy();
- });
-});
diff --git a/spec/frontend/issue_show/components/fields/description_spec.js b/spec/frontend/issue_show/components/fields/description_spec.js
deleted file mode 100644
index a50be30cf4c..00000000000
--- a/spec/frontend/issue_show/components/fields/description_spec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import DescriptionField from '~/issue_show/components/fields/description.vue';
-import eventHub from '~/issue_show/event_hub';
-import MarkdownField from '~/vue_shared/components/markdown/field.vue';
-
-describe('Description field component', () => {
- let wrapper;
-
- const findTextarea = () => wrapper.find({ ref: 'textarea' });
-
- const mountComponent = (description = 'test') =>
- shallowMount(DescriptionField, {
- attachTo: document.body,
- propsData: {
- markdownPreviewPath: '/',
- markdownDocsPath: '/',
- formState: {
- description,
- },
- },
- stubs: {
- MarkdownField,
- },
- });
-
- beforeEach(() => {
- jest.spyOn(eventHub, '$emit');
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('renders markdown field with description', () => {
- wrapper = mountComponent();
-
- expect(findTextarea().element.value).toBe('test');
- });
-
- it('renders markdown field with a markdown description', () => {
- const markdown = '**test**';
-
- wrapper = mountComponent(markdown);
-
- expect(findTextarea().element.value).toBe(markdown);
- });
-
- it('focuses field when mounted', () => {
- wrapper = mountComponent();
-
- expect(document.activeElement).toBe(findTextarea().element);
- });
-
- it('triggers update with meta+enter', () => {
- wrapper = mountComponent();
-
- findTextarea().trigger('keydown.enter', { metaKey: true });
-
- expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
- });
-
- it('triggers update with ctrl+enter', () => {
- wrapper = mountComponent();
-
- findTextarea().trigger('keydown.enter', { ctrlKey: true });
-
- expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
- });
-});
diff --git a/spec/frontend/issue_show/components/fields/description_template_spec.js b/spec/frontend/issue_show/components/fields/description_template_spec.js
deleted file mode 100644
index dc126c53f5e..00000000000
--- a/spec/frontend/issue_show/components/fields/description_template_spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import Vue from 'vue';
-import descriptionTemplate from '~/issue_show/components/fields/description_template.vue';
-
-describe('Issue description template component with templates as hash', () => {
- let vm;
- let formState;
-
- beforeEach(() => {
- const Component = Vue.extend(descriptionTemplate);
- formState = {
- description: 'test',
- };
-
- vm = new Component({
- propsData: {
- formState,
- issuableTemplates: {
- test: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }],
- },
- projectId: 1,
- projectPath: '/',
- namespacePath: '/',
- projectNamespace: '/',
- },
- }).$mount();
- });
-
- it('renders templates as JSON hash in data attribute', () => {
- expect(vm.$el.querySelector('.js-issuable-selector').getAttribute('data-data')).toBe(
- '{"test":[{"name":"test","id":"test","project_path":"/","namespace_path":"/"}]}',
- );
- });
-
- it('updates formState when changing template', () => {
- vm.issuableTemplate.editor.setValue('test new template');
-
- expect(formState.description).toBe('test new template');
- });
-
- it('returns formState description with editor getValue', () => {
- formState.description = 'testing new template';
-
- expect(vm.issuableTemplate.editor.getValue()).toBe('testing new template');
- });
-});
-
-describe('Issue description template component with templates as array', () => {
- let vm;
- let formState;
-
- beforeEach(() => {
- const Component = Vue.extend(descriptionTemplate);
- formState = {
- description: 'test',
- };
-
- vm = new Component({
- propsData: {
- formState,
- issuableTemplates: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }],
- projectId: 1,
- projectPath: '/',
- namespacePath: '/',
- projectNamespace: '/',
- },
- }).$mount();
- });
-
- it('renders templates as JSON array in data attribute', () => {
- expect(vm.$el.querySelector('.js-issuable-selector').getAttribute('data-data')).toBe(
- '[{"name":"test","id":"test","project_path":"/","namespace_path":"/"}]',
- );
- });
-});
diff --git a/spec/frontend/issue_show/components/fields/title_spec.js b/spec/frontend/issue_show/components/fields/title_spec.js
deleted file mode 100644
index 783ce9eb76c..00000000000
--- a/spec/frontend/issue_show/components/fields/title_spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import TitleField from '~/issue_show/components/fields/title.vue';
-import eventHub from '~/issue_show/event_hub';
-
-describe('Title field component', () => {
- let wrapper;
-
- const findInput = () => wrapper.find({ ref: 'input' });
-
- beforeEach(() => {
- jest.spyOn(eventHub, '$emit');
-
- wrapper = shallowMount(TitleField, {
- propsData: {
- formState: {
- title: 'test',
- },
- },
- });
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('renders form control with formState title', () => {
- expect(findInput().element.value).toBe('test');
- });
-
- it('triggers update with meta+enter', () => {
- findInput().trigger('keydown.enter', { metaKey: true });
-
- expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
- });
-
- it('triggers update with ctrl+enter', () => {
- findInput().trigger('keydown.enter', { ctrlKey: true });
-
- expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
- });
-});
diff --git a/spec/frontend/issue_show/components/fields/type_spec.js b/spec/frontend/issue_show/components/fields/type_spec.js
deleted file mode 100644
index 95ae6f37877..00000000000
--- a/spec/frontend/issue_show/components/fields/type_spec.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import { GlFormGroup, GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import IssueTypeField, { i18n } from '~/issue_show/components/fields/type.vue';
-import { IssuableTypes } from '~/issue_show/constants';
-import {
- getIssueStateQueryResponse,
- updateIssueStateQueryResponse,
-} from '../../mock_data/apollo_mock';
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-describe('Issue type field component', () => {
- let wrapper;
- let fakeApollo;
- let mockIssueStateData;
-
- const mockResolvers = {
- Query: {
- issueState() {
- return {
- __typename: 'IssueState',
- rawData: mockIssueStateData(),
- };
- },
- },
- Mutation: {
- updateIssueState: jest.fn().mockResolvedValue(updateIssueStateQueryResponse),
- },
- };
-
- const findTypeFromGroup = () => wrapper.findComponent(GlFormGroup);
- const findTypeFromDropDown = () => wrapper.findComponent(GlDropdown);
- const findTypeFromDropDownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findTypeFromDropDownItemAt = (at) => findTypeFromDropDownItems().at(at);
- const findTypeFromDropDownItemIconAt = (at) =>
- findTypeFromDropDownItems().at(at).findComponent(GlIcon);
-
- const createComponent = ({ data } = {}, provide) => {
- fakeApollo = createMockApollo([], mockResolvers);
-
- wrapper = shallowMount(IssueTypeField, {
- localVue,
- apolloProvider: fakeApollo,
- data() {
- return {
- issueState: {},
- ...data,
- };
- },
- provide: {
- canCreateIncident: true,
- ...provide,
- },
- });
- };
-
- beforeEach(() => {
- mockIssueStateData = jest.fn();
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it.each`
- at | text | icon
- ${0} | ${IssuableTypes[0].text} | ${IssuableTypes[0].icon}
- ${1} | ${IssuableTypes[1].text} | ${IssuableTypes[1].icon}
- `(`renders the issue type $text with an icon in the dropdown`, ({ at, text, icon }) => {
- expect(findTypeFromDropDownItemIconAt(at).attributes('name')).toBe(icon);
- expect(findTypeFromDropDownItemAt(at).text()).toBe(text);
- });
-
- it('renders a form group with the correct label', () => {
- expect(findTypeFromGroup().attributes('label')).toBe(i18n.label);
- });
-
- it('renders a form select with the `issue_type` value', () => {
- expect(findTypeFromDropDown().attributes('value')).toBe(IssuableTypes.issue);
- });
-
- describe('with Apollo cache mock', () => {
- it('renders the selected issueType', async () => {
- mockIssueStateData.mockResolvedValue(getIssueStateQueryResponse);
- await waitForPromises();
- expect(findTypeFromDropDown().attributes('value')).toBe(IssuableTypes.issue);
- });
-
- it('updates the `issue_type` in the apollo cache when the value is changed', async () => {
- findTypeFromDropDownItems().at(1).vm.$emit('click', IssuableTypes.incident);
- await wrapper.vm.$nextTick();
- expect(findTypeFromDropDown().attributes('value')).toBe(IssuableTypes.incident);
- });
-
- describe('when user is a guest', () => {
- it('hides the incident type from the dropdown', async () => {
- createComponent({}, { canCreateIncident: false, issueType: 'issue' });
- await waitForPromises();
-
- expect(findTypeFromDropDownItemAt(0).isVisible()).toBe(true);
- expect(findTypeFromDropDownItemAt(1).isVisible()).toBe(false);
- expect(findTypeFromDropDown().attributes('value')).toBe(IssuableTypes.issue);
- });
-
- it('and incident is selected, includes incident in the dropdown', async () => {
- createComponent({}, { canCreateIncident: false, issueType: 'incident' });
- await waitForPromises();
-
- expect(findTypeFromDropDownItemAt(0).isVisible()).toBe(true);
- expect(findTypeFromDropDownItemAt(1).isVisible()).toBe(true);
- expect(findTypeFromDropDown().attributes('value')).toBe(IssuableTypes.incident);
- });
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/form_spec.js b/spec/frontend/issue_show/components/form_spec.js
deleted file mode 100644
index 28498cb90ec..00000000000
--- a/spec/frontend/issue_show/components/form_spec.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Autosave from '~/autosave';
-import DescriptionTemplate from '~/issue_show/components/fields/description_template.vue';
-import IssueTypeField from '~/issue_show/components/fields/type.vue';
-import formComponent from '~/issue_show/components/form.vue';
-import LockedWarning from '~/issue_show/components/locked_warning.vue';
-import eventHub from '~/issue_show/event_hub';
-
-jest.mock('~/autosave');
-
-describe('Inline edit form component', () => {
- let wrapper;
- const defaultProps = {
- canDestroy: true,
- formState: {
- title: 'b',
- description: 'a',
- lockedWarningVisible: false,
- },
- issuableType: 'issue',
- markdownPreviewPath: '/',
- markdownDocsPath: '/',
- projectPath: '/',
- projectId: 1,
- projectNamespace: '/',
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const createComponent = (props) => {
- wrapper = shallowMount(formComponent, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- const findDescriptionTemplate = () => wrapper.findComponent(DescriptionTemplate);
- const findIssuableTypeField = () => wrapper.findComponent(IssueTypeField);
- const findLockedWarning = () => wrapper.findComponent(LockedWarning);
- const findAlert = () => wrapper.findComponent(GlAlert);
-
- it('does not render template selector if no templates exist', () => {
- createComponent();
-
- expect(findDescriptionTemplate().exists()).toBe(false);
- });
-
- it('renders template selector when templates as array exists', () => {
- createComponent({
- issuableTemplates: [
- { name: 'test', id: 'test', project_path: 'test', namespace_path: 'test' },
- ],
- });
-
- expect(findDescriptionTemplate().exists()).toBe(true);
- });
-
- it('renders template selector when templates as hash exists', () => {
- createComponent({
- issuableTemplates: {
- test: [{ name: 'test', id: 'test', project_path: 'test', namespace_path: 'test' }],
- },
- });
-
- expect(findDescriptionTemplate().exists()).toBe(true);
- });
-
- it.each`
- issuableType | value
- ${'issue'} | ${true}
- ${'epic'} | ${false}
- `(
- 'when `issue_type` is set to "$issuableType" rendering the type select will be "$value"',
- ({ issuableType, value }) => {
- createComponent({
- issuableType,
- });
-
- expect(findIssuableTypeField().exists()).toBe(value);
- },
- );
-
- it('hides locked warning by default', () => {
- createComponent();
-
- expect(findLockedWarning().exists()).toBe(false);
- });
-
- it('shows locked warning if formState is different', () => {
- createComponent({ formState: { ...defaultProps.formState, lockedWarningVisible: true } });
-
- expect(findLockedWarning().exists()).toBe(true);
- });
-
- it('hides locked warning when currently saving', () => {
- createComponent({
- formState: { ...defaultProps.formState, updateLoading: true, lockedWarningVisible: true },
- });
-
- expect(findLockedWarning().exists()).toBe(false);
- });
-
- describe('autosave', () => {
- let spy;
-
- beforeEach(() => {
- spy = jest.spyOn(Autosave.prototype, 'reset');
- });
-
- it('initialized Autosave on mount', () => {
- createComponent();
-
- expect(Autosave).toHaveBeenCalledTimes(2);
- });
-
- it('calls reset on autosave when eventHub emits appropriate events', () => {
- createComponent();
-
- eventHub.$emit('close.form');
-
- expect(spy).toHaveBeenCalledTimes(2);
-
- eventHub.$emit('delete.issuable');
-
- expect(spy).toHaveBeenCalledTimes(4);
-
- eventHub.$emit('update.issuable');
-
- expect(spy).toHaveBeenCalledTimes(6);
- });
-
- describe('outdated description', () => {
- it('does not show warning if lock version from server is the same as the local lock version', () => {
- createComponent();
- expect(findAlert().exists()).toBe(false);
- });
-
- it('shows warning if lock version from server differs than the local lock version', async () => {
- Autosave.prototype.getSavedLockVersion.mockResolvedValue('lock version from local storage');
-
- createComponent({
- formState: { ...defaultProps.formState, lock_version: 'lock version from server' },
- });
-
- await wrapper.vm.$nextTick();
- expect(findAlert().exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/header_actions_spec.js b/spec/frontend/issue_show/components/header_actions_spec.js
deleted file mode 100644
index 4df62ec8717..00000000000
--- a/spec/frontend/issue_show/components/header_actions_spec.js
+++ /dev/null
@@ -1,348 +0,0 @@
-import { GlButton, GlDropdown, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import Vuex from 'vuex';
-import createFlash, { FLASH_TYPES } from '~/flash';
-import { IssuableType } from '~/issuable_show/constants';
-import HeaderActions from '~/issue_show/components/header_actions.vue';
-import { IssuableStatus, IssueStateEvent } from '~/issue_show/constants';
-import promoteToEpicMutation from '~/issue_show/queries/promote_to_epic.mutation.graphql';
-import * as urlUtility from '~/lib/utils/url_utility';
-import eventHub from '~/notes/event_hub';
-import createStore from '~/notes/stores';
-
-jest.mock('~/flash');
-
-describe('HeaderActions component', () => {
- let dispatchEventSpy;
- let mutateMock;
- let wrapper;
- let visitUrlSpy;
-
- const localVue = createLocalVue();
- localVue.use(Vuex);
- const store = createStore();
-
- const defaultProps = {
- canCreateIssue: true,
- canPromoteToEpic: true,
- canReopenIssue: true,
- canReportSpam: true,
- canUpdateIssue: true,
- iid: '32',
- isIssueAuthor: true,
- issueType: IssuableType.Issue,
- newIssuePath: 'gitlab-org/gitlab-test/-/issues/new',
- projectPath: 'gitlab-org/gitlab-test',
- reportAbusePath:
- '-/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%2Fgitlab-org%2Fgitlab-test%2F-%2Fissues%2F32&user_id=1',
- submitAsSpamPath: 'gitlab-org/gitlab-test/-/issues/32/submit_as_spam',
- };
-
- const updateIssueMutationResponse = { data: { updateIssue: { errors: [] } } };
-
- const promoteToEpicMutationResponse = {
- data: {
- promoteToEpic: {
- errors: [],
- epic: {
- webPath: '/groups/gitlab-org/-/epics/1',
- },
- },
- },
- };
-
- const promoteToEpicMutationErrorResponse = {
- data: {
- promoteToEpic: {
- errors: ['The issue has already been promoted to an epic.'],
- epic: {},
- },
- },
- };
-
- const findToggleIssueStateButton = () => wrapper.find(GlButton);
-
- const findDropdownAt = (index) => wrapper.findAll(GlDropdown).at(index);
-
- const findMobileDropdownItems = () => findDropdownAt(0).findAll(GlDropdownItem);
-
- const findDesktopDropdownItems = () => findDropdownAt(1).findAll(GlDropdownItem);
-
- const findModal = () => wrapper.find(GlModal);
-
- const findModalLinkAt = (index) => findModal().findAll(GlLink).at(index);
-
- const mountComponent = ({
- props = {},
- issueState = IssuableStatus.Open,
- blockedByIssues = [],
- mutateResponse = {},
- } = {}) => {
- mutateMock = jest.fn().mockResolvedValue(mutateResponse);
-
- store.dispatch('setNoteableData', {
- blocked_by_issues: blockedByIssues,
- state: issueState,
- });
-
- return shallowMount(HeaderActions, {
- localVue,
- store,
- provide: {
- ...defaultProps,
- ...props,
- },
- mocks: {
- $apollo: {
- mutate: mutateMock,
- },
- },
- });
- };
-
- afterEach(() => {
- if (dispatchEventSpy) {
- dispatchEventSpy.mockRestore();
- }
- if (visitUrlSpy) {
- visitUrlSpy.mockRestore();
- }
- wrapper.destroy();
- });
-
- describe.each`
- issueType
- ${IssuableType.Issue}
- ${IssuableType.Incident}
- `('when issue type is $issueType', ({ issueType }) => {
- describe('close/reopen button', () => {
- describe.each`
- description | issueState | buttonText | newIssueState
- ${`when the ${issueType} is open`} | ${IssuableStatus.Open} | ${`Close ${issueType}`} | ${IssueStateEvent.Close}
- ${`when the ${issueType} is closed`} | ${IssuableStatus.Closed} | ${`Reopen ${issueType}`} | ${IssueStateEvent.Reopen}
- `('$description', ({ issueState, buttonText, newIssueState }) => {
- beforeEach(() => {
- dispatchEventSpy = jest.spyOn(document, 'dispatchEvent');
-
- wrapper = mountComponent({
- props: { issueType },
- issueState,
- mutateResponse: updateIssueMutationResponse,
- });
- });
-
- it(`has text "${buttonText}"`, () => {
- expect(findToggleIssueStateButton().text()).toBe(buttonText);
- });
-
- it('calls apollo mutation', () => {
- findToggleIssueStateButton().vm.$emit('click');
-
- expect(mutateMock).toHaveBeenCalledWith(
- expect.objectContaining({
- variables: {
- input: {
- iid: defaultProps.iid,
- projectPath: defaultProps.projectPath,
- stateEvent: newIssueState,
- },
- },
- }),
- );
- });
-
- it('dispatches a custom event to update the issue page', async () => {
- findToggleIssueStateButton().vm.$emit('click');
-
- await wrapper.vm.$nextTick();
-
- expect(dispatchEventSpy).toHaveBeenCalledTimes(1);
- });
- });
- });
-
- describe.each`
- description | isCloseIssueItemVisible | findDropdownItems
- ${'mobile dropdown'} | ${true} | ${findMobileDropdownItems}
- ${'desktop dropdown'} | ${false} | ${findDesktopDropdownItems}
- `('$description', ({ isCloseIssueItemVisible, findDropdownItems }) => {
- describe.each`
- description | itemText | isItemVisible | canUpdateIssue | canCreateIssue | isIssueAuthor | canReportSpam | canPromoteToEpic
- ${`when user can update ${issueType}`} | ${`Close ${issueType}`} | ${isCloseIssueItemVisible} | ${true} | ${true} | ${true} | ${true} | ${true}
- ${`when user cannot update ${issueType}`} | ${`Close ${issueType}`} | ${false} | ${false} | ${true} | ${true} | ${true} | ${true}
- ${`when user can create ${issueType}`} | ${`New ${issueType}`} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
- ${`when user cannot create ${issueType}`} | ${`New ${issueType}`} | ${false} | ${true} | ${false} | ${true} | ${true} | ${true}
- ${'when user can promote to epic'} | ${'Promote to epic'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
- ${'when user cannot promote to epic'} | ${'Promote to epic'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false}
- ${'when user can report abuse'} | ${'Report abuse'} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true}
- ${'when user cannot report abuse'} | ${'Report abuse'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true}
- ${'when user can submit as spam'} | ${'Submit as spam'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
- ${'when user cannot submit as spam'} | ${'Submit as spam'} | ${false} | ${true} | ${true} | ${true} | ${false} | ${true}
- `(
- '$description',
- ({
- itemText,
- isItemVisible,
- canUpdateIssue,
- canCreateIssue,
- isIssueAuthor,
- canReportSpam,
- canPromoteToEpic,
- }) => {
- beforeEach(() => {
- wrapper = mountComponent({
- props: {
- canUpdateIssue,
- canCreateIssue,
- isIssueAuthor,
- issueType,
- canReportSpam,
- canPromoteToEpic,
- },
- });
- });
-
- it(`${isItemVisible ? 'shows' : 'hides'} "${itemText}" item`, () => {
- expect(
- findDropdownItems()
- .filter((item) => item.text() === itemText)
- .exists(),
- ).toBe(isItemVisible);
- });
- },
- );
- });
- });
-
- describe('when "Promote to epic" button is clicked', () => {
- describe('when response is successful', () => {
- beforeEach(() => {
- visitUrlSpy = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
-
- wrapper = mountComponent({
- mutateResponse: promoteToEpicMutationResponse,
- });
-
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
- });
-
- it('invokes GraphQL mutation when clicked', () => {
- expect(mutateMock).toHaveBeenCalledWith(
- expect.objectContaining({
- mutation: promoteToEpicMutation,
- variables: {
- input: {
- iid: defaultProps.iid,
- projectPath: defaultProps.projectPath,
- },
- },
- }),
- );
- });
-
- it('shows a success message and tells the user they are being redirected', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: 'The issue was successfully promoted to an epic. Redirecting to epic...',
- type: FLASH_TYPES.SUCCESS,
- });
- });
-
- it('redirects to newly created epic path', () => {
- expect(visitUrlSpy).toHaveBeenCalledWith(
- promoteToEpicMutationResponse.data.promoteToEpic.epic.webPath,
- );
- });
- });
-
- describe('when response contains errors', () => {
- beforeEach(() => {
- visitUrlSpy = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
-
- wrapper = mountComponent({
- mutateResponse: promoteToEpicMutationErrorResponse,
- });
-
- wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
- });
-
- it('shows an error message', () => {
- expect(createFlash).toHaveBeenCalledWith({
- message: promoteToEpicMutationErrorResponse.data.promoteToEpic.errors.join('; '),
- });
- });
- });
- });
-
- describe('when `toggle.issuable.state` event is emitted', () => {
- it('invokes a method to toggle the issue state', () => {
- wrapper = mountComponent({ mutateResponse: updateIssueMutationResponse });
-
- eventHub.$emit('toggle.issuable.state');
-
- expect(mutateMock).toHaveBeenCalledWith(
- expect.objectContaining({
- variables: {
- input: {
- iid: defaultProps.iid,
- projectPath: defaultProps.projectPath,
- stateEvent: IssueStateEvent.Close,
- },
- },
- }),
- );
- });
- });
-
- describe('modal', () => {
- const blockedByIssues = [
- { iid: 13, web_url: 'gitlab-org/gitlab-test/-/issues/13' },
- { iid: 79, web_url: 'gitlab-org/gitlab-test/-/issues/79' },
- ];
-
- beforeEach(() => {
- wrapper = mountComponent({ blockedByIssues });
- });
-
- it('has title text', () => {
- expect(findModal().attributes('title')).toBe(
- 'Are you sure you want to close this blocked issue?',
- );
- });
-
- it('has body text', () => {
- expect(findModal().text()).toContain(
- 'This issue is currently blocked by the following issues:',
- );
- });
-
- it('calls apollo mutation when primary button is clicked', () => {
- findModal().vm.$emit('primary');
-
- expect(mutateMock).toHaveBeenCalledWith(
- expect.objectContaining({
- variables: {
- input: {
- iid: defaultProps.iid.toString(),
- projectPath: defaultProps.projectPath,
- stateEvent: IssueStateEvent.Close,
- },
- },
- }),
- );
- });
-
- describe.each`
- ordinal | index
- ${'first'} | ${0}
- ${'second'} | ${1}
- `('$ordinal blocked-by issue link', ({ index }) => {
- it('has link text', () => {
- expect(findModalLinkAt(index).text()).toBe(`#${blockedByIssues[index].iid}`);
- });
-
- it('has url', () => {
- expect(findModalLinkAt(index).attributes('href')).toBe(blockedByIssues[index].web_url);
- });
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js b/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
deleted file mode 100644
index 6758e6192b8..00000000000
--- a/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import merge from 'lodash/merge';
-import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
-import { formatDate } from '~/lib/utils/datetime_utility';
-
-jest.mock('~/lib/utils/datetime_utility');
-
-describe('Highlight Bar', () => {
- let wrapper;
-
- const alert = {
- iid: 1,
- startedAt: '2020-05-29T10:39:22Z',
- detailsUrl: 'http://127.0.0.1:3000/root/unique-alerts/-/alert_management/1/details',
- eventCount: 1,
- title: 'Alert 1',
- };
-
- const mountComponent = (options) => {
- wrapper = shallowMount(
- HighlightBar,
- merge(
- {
- propsData: { alert },
- provide: { fullPath: 'test', iid: 1, slaFeatureAvailable: true },
- },
- options,
- ),
- );
- };
-
- beforeEach(() => {
- mountComponent();
- });
-
- afterEach(() => {
- if (wrapper) {
- wrapper.destroy();
- wrapper = null;
- }
- });
-
- const findLink = () => wrapper.find(GlLink);
-
- describe('empty state', () => {
- beforeEach(() => {
- mountComponent({ propsData: { alert: null } });
- });
-
- it('renders a empty component', () => {
- expect(wrapper.isVisible()).toBe(false);
- });
- });
-
- describe('alert present', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders a link to the alert page', () => {
- expect(findLink().exists()).toBe(true);
- expect(findLink().attributes('href')).toBe(alert.detailsUrl);
- expect(findLink().attributes('title')).toBe(alert.title);
- expect(findLink().text()).toBe(`#${alert.iid}`);
- });
-
- it('renders formatted start time of the alert', () => {
- const formattedDate = '2020-05-29 UTC';
- formatDate.mockReturnValueOnce(formattedDate);
- mountComponent();
- expect(formatDate).toHaveBeenCalledWith(alert.startedAt, 'yyyy-mm-dd Z');
- expect(wrapper.text()).toContain(formattedDate);
- });
-
- it('renders a number of alert events', () => {
- expect(wrapper.text()).toContain(alert.eventCount);
- });
- });
-
- describe('when child data is present', () => {
- beforeEach(() => {
- mountComponent({
- data() {
- return { hasChildData: true };
- },
- });
- });
-
- it('renders the highlight bar component', () => {
- expect(wrapper.isVisible()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js b/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
deleted file mode 100644
index 6b9f5b17e99..00000000000
--- a/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { GlTab } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import merge from 'lodash/merge';
-import waitForPromises from 'helpers/wait_for_promises';
-import { trackIncidentDetailsViewsOptions } from '~/incidents/constants';
-import DescriptionComponent from '~/issue_show/components/description.vue';
-import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
-import IncidentTabs from '~/issue_show/components/incidents/incident_tabs.vue';
-import INVALID_URL from '~/lib/utils/invalid_url';
-import Tracking from '~/tracking';
-import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
-import { descriptionProps } from '../../mock_data/mock_data';
-
-const mockAlert = {
- __typename: 'AlertManagementAlert',
- detailsUrl: INVALID_URL,
- iid: '1',
-};
-
-describe('Incident Tabs component', () => {
- let wrapper;
-
- const mountComponent = (data = {}, options = {}) => {
- wrapper = shallowMount(
- IncidentTabs,
- merge(
- {
- propsData: {
- ...descriptionProps,
- },
- stubs: {
- DescriptionComponent: true,
- MetricsTab: true,
- },
- provide: {
- fullPath: '',
- iid: '',
- uploadMetricsFeatureAvailable: true,
- },
- data() {
- return { alert: mockAlert, ...data };
- },
- mocks: {
- $apollo: {
- queries: {
- alert: {
- loading: true,
- },
- },
- },
- },
- },
- options,
- ),
- );
- };
-
- const findTabs = () => wrapper.findAll(GlTab);
- const findSummaryTab = () => findTabs().at(0);
- const findMetricsTab = () => wrapper.find('[data-testid="metrics-tab"]');
- const findAlertDetailsTab = () => wrapper.find('[data-testid="alert-details-tab"]');
- const findAlertDetailsComponent = () => wrapper.find(AlertDetailsTable);
- const findDescriptionComponent = () => wrapper.find(DescriptionComponent);
- const findHighlightBarComponent = () => wrapper.find(HighlightBar);
-
- describe('empty state', () => {
- beforeEach(() => {
- mountComponent({ alert: null });
- });
-
- it('does not show the alert details tab', () => {
- expect(findAlertDetailsComponent().exists()).toBe(false);
- });
- });
-
- describe('with an alert present', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders the summary tab', () => {
- expect(findSummaryTab().exists()).toBe(true);
- expect(findSummaryTab().attributes('title')).toBe('Summary');
- });
-
- it('renders the alert details tab', () => {
- expect(findAlertDetailsTab().exists()).toBe(true);
- expect(findAlertDetailsTab().attributes('title')).toBe('Alert details');
- });
-
- it('renders the alert details table with the correct props', () => {
- const alert = { iid: mockAlert.iid };
-
- expect(findAlertDetailsComponent().props('alert')).toMatchObject(alert);
- expect(findAlertDetailsComponent().props('loading')).toBe(true);
- });
-
- it('renders the description component with highlight bar', () => {
- expect(findDescriptionComponent().exists()).toBe(true);
- expect(findHighlightBarComponent().exists()).toBe(true);
- });
-
- it('renders the highlight bar component with the correct props', () => {
- const alert = { detailsUrl: mockAlert.detailsUrl };
-
- expect(findHighlightBarComponent().props('alert')).toMatchObject(alert);
- });
-
- it('passes all props to the description component', () => {
- expect(findDescriptionComponent().props()).toMatchObject(descriptionProps);
- });
- });
-
- describe('upload metrics feature available', () => {
- it('shows the metric tab when metrics are available', async () => {
- mountComponent({}, { provide: { uploadMetricsFeatureAvailable: true } });
-
- await waitForPromises();
-
- expect(findMetricsTab().exists()).toBe(true);
- });
-
- it('hides the tab when metrics are not available', async () => {
- mountComponent({}, { provide: { uploadMetricsFeatureAvailable: false } });
-
- await waitForPromises();
-
- expect(findMetricsTab().exists()).toBe(false);
- });
- });
-
- describe('Snowplow tracking', () => {
- beforeEach(() => {
- jest.spyOn(Tracking, 'event');
- mountComponent();
- });
-
- it('should track incident details views', () => {
- const { category, action } = trackIncidentDetailsViewsOptions;
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
- });
- });
-});
diff --git a/spec/frontend/issue_show/components/pinned_links_spec.js b/spec/frontend/issue_show/components/pinned_links_spec.js
deleted file mode 100644
index 3fe1f9fd6d9..00000000000
--- a/spec/frontend/issue_show/components/pinned_links_spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import PinnedLinks from '~/issue_show/components/pinned_links.vue';
-import { STATUS_PAGE_PUBLISHED, JOIN_ZOOM_MEETING } from '~/issue_show/constants';
-
-const plainZoomUrl = 'https://zoom.us/j/123456789';
-const plainStatusUrl = 'https://status.com';
-
-describe('PinnedLinks', () => {
- let wrapper;
-
- const findButtons = () => wrapper.findAll(GlButton);
-
- const createComponent = (props) => {
- wrapper = shallowMount(PinnedLinks, {
- propsData: {
- zoomMeetingUrl: '',
- publishedIncidentUrl: '',
- ...props,
- },
- });
- };
-
- it('displays Zoom link', () => {
- createComponent({
- zoomMeetingUrl: `<a href="${plainZoomUrl}">Zoom</a>`,
- });
-
- expect(findButtons().at(0).text()).toBe(JOIN_ZOOM_MEETING);
- });
-
- it('displays Status link', () => {
- createComponent({
- publishedIncidentUrl: `<a href="${plainStatusUrl}">Status</a>`,
- });
-
- expect(findButtons().at(0).text()).toBe(STATUS_PAGE_PUBLISHED);
- });
-
- it('does not render if there are no links', () => {
- createComponent({
- zoomMeetingUrl: '',
- publishedIncidentUrl: '',
- });
-
- expect(findButtons()).toHaveLength(0);
- });
-});
diff --git a/spec/frontend/issue_show/components/title_spec.js b/spec/frontend/issue_show/components/title_spec.js
deleted file mode 100644
index 78880a7f540..00000000000
--- a/spec/frontend/issue_show/components/title_spec.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import Vue from 'vue';
-import titleComponent from '~/issue_show/components/title.vue';
-import eventHub from '~/issue_show/event_hub';
-import Store from '~/issue_show/stores';
-
-describe('Title component', () => {
- let vm;
- beforeEach(() => {
- setFixtures(`<title />`);
-
- const Component = Vue.extend(titleComponent);
- const store = new Store({
- titleHtml: '',
- descriptionHtml: '',
- issuableRef: '',
- });
- vm = new Component({
- propsData: {
- issuableRef: '#1',
- titleHtml: 'Testing <img />',
- titleText: 'Testing',
- showForm: false,
- formState: store.formState,
- },
- }).$mount();
- });
-
- it('renders title HTML', () => {
- expect(vm.$el.querySelector('.title').innerHTML.trim()).toBe('Testing <img>');
- });
-
- it('updates page title when changing titleHtml', () => {
- const spy = jest.spyOn(vm, 'setPageTitle');
- vm.titleHtml = 'test';
-
- return vm.$nextTick().then(() => {
- expect(spy).toHaveBeenCalled();
- });
- });
-
- it('animates title changes', () => {
- vm.titleHtml = 'test';
- return vm
- .$nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-pre-pulse');
- jest.runAllTimers();
- return vm.$nextTick();
- })
- .then(() => {
- expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-trigger-pulse');
- });
- });
-
- it('updates page title after changing title', () => {
- vm.titleHtml = 'changed';
- vm.titleText = 'changed';
-
- return vm.$nextTick().then(() => {
- expect(document.querySelector('title').textContent.trim()).toContain('changed');
- });
- });
-
- describe('inline edit button', () => {
- it('should not show by default', () => {
- expect(vm.$el.querySelector('.btn-edit')).toBeNull();
- });
-
- it('should not show if canUpdate is false', () => {
- vm.showInlineEditButton = true;
- vm.canUpdate = false;
-
- expect(vm.$el.querySelector('.btn-edit')).toBeNull();
- });
-
- it('should show if showInlineEditButton and canUpdate', () => {
- vm.showInlineEditButton = true;
- vm.canUpdate = true;
-
- expect(vm.$el.querySelector('.btn-edit')).toBeDefined();
- });
-
- it('should trigger open.form event when clicked', () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- vm.showInlineEditButton = true;
- vm.canUpdate = true;
-
- Vue.nextTick(() => {
- vm.$el.querySelector('.btn-edit').click();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('open.form');
- });
- });
- });
-});
diff --git a/spec/frontend/issue_show/issue_spec.js b/spec/frontend/issue_show/issue_spec.js
deleted file mode 100644
index 76989413edb..00000000000
--- a/spec/frontend/issue_show/issue_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
-import { initIssuableApp } from '~/issue_show/issue';
-import * as parseData from '~/issue_show/utils/parse_data';
-import axios from '~/lib/utils/axios_utils';
-import createStore from '~/notes/stores';
-import { appProps } from './mock_data/mock_data';
-
-const mock = new MockAdapter(axios);
-mock.onGet().reply(200);
-
-jest.mock('~/lib/utils/poll');
-
-const setupHTML = (initialData) => {
- document.body.innerHTML = `<div id="js-issuable-app"></div>`;
- document.getElementById('js-issuable-app').dataset.initial = JSON.stringify(initialData);
-};
-
-describe('Issue show index', () => {
- describe('initIssueableApp', () => {
- it('should initialize app with no potential XSS attack', async () => {
- const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
- const parseDataSpy = jest.spyOn(parseData, 'parseIssuableData');
-
- setupHTML({
- ...appProps,
- initialDescriptionHtml: '<svg onload=window.alert(1)>',
- });
-
- const initialDataEl = document.getElementById('js-issuable-app');
- const issuableData = parseData.parseIssuableData(initialDataEl);
- initIssuableApp(issuableData, createStore());
-
- await waitForPromises();
-
- expect(parseDataSpy).toHaveBeenCalled();
- expect(alertSpy).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/issue_show/mock_data/apollo_mock.js b/spec/frontend/issue_show/mock_data/apollo_mock.js
deleted file mode 100644
index bfd31e74393..00000000000
--- a/spec/frontend/issue_show/mock_data/apollo_mock.js
+++ /dev/null
@@ -1,9 +0,0 @@
-export const getIssueStateQueryResponse = {
- issueType: 'issue',
- isDirty: false,
-};
-
-export const updateIssueStateQueryResponse = {
- issueType: 'incident',
- isDirty: true,
-};
diff --git a/spec/frontend/issue_show/mock_data/mock_data.js b/spec/frontend/issue_show/mock_data/mock_data.js
deleted file mode 100644
index a73826954c3..00000000000
--- a/spec/frontend/issue_show/mock_data/mock_data.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { TEST_HOST } from 'helpers/test_constants';
-
-export const initialRequest = {
- title: '<p>this is a title</p>',
- title_text: 'this is a title',
- description: '<p>this is a description!</p>',
- description_text: 'this is a description',
- task_status: '2 of 4 completed',
- updated_at: '2015-05-15T12:31:04.428Z',
- updated_by_name: 'Some User',
- updated_by_path: '/some_user',
- lock_version: 1,
-};
-
-export const secondRequest = {
- title: '<p>2</p>',
- title_text: '2',
- description: '<p>42</p>',
- description_text: '42',
- task_status: '0 of 0 completed',
- updated_at: '2016-05-15T12:31:04.428Z',
- updated_by_name: 'Other User',
- updated_by_path: '/other_user',
- lock_version: 2,
-};
-
-export const descriptionProps = {
- canUpdate: true,
- descriptionHtml: 'test',
- descriptionText: 'test',
- taskStatus: '',
- updateUrl: TEST_HOST,
-};
-
-export const publishedIncidentUrl = 'https://status.com/';
-
-export const zoomMeetingUrl = 'https://gitlab.zoom.us/j/95919234811';
-
-export const appProps = {
- canUpdate: true,
- canDestroy: true,
- endpoint: '/gitlab-org/gitlab-shell/-/issues/9/realtime_changes',
- updateEndpoint: TEST_HOST,
- issuableRef: '#1',
- issuableStatus: 'opened',
- initialTitleHtml: '',
- initialTitleText: '',
- initialDescriptionHtml: 'test',
- initialDescriptionText: 'test',
- lockVersion: 1,
- issueType: 'issue',
- markdownPreviewPath: '/',
- markdownDocsPath: '/',
- projectNamespace: '/',
- projectPath: '/',
- projectId: 1,
- issuableTemplateNamesPath: '/issuable-templates-path',
- zoomMeetingUrl,
- publishedIncidentUrl,
-};
diff --git a/spec/frontend/issue_show/store_spec.js b/spec/frontend/issue_show/store_spec.js
deleted file mode 100644
index b7fd70bf00e..00000000000
--- a/spec/frontend/issue_show/store_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import Store from '~/issue_show/stores';
-import updateDescription from '~/issue_show/utils/update_description';
-
-jest.mock('~/issue_show/utils/update_description');
-
-describe('Store', () => {
- let store;
-
- beforeEach(() => {
- store = new Store({
- descriptionHtml: '<p>This is a description</p>',
- });
- });
-
- describe('updateState', () => {
- beforeEach(() => {
- document.body.innerHTML = `
- <div class="detail-page-description content-block">
- <details open>
- <summary>One</summary>
- </details>
- <details>
- <summary>Two</summary>
- </details>
- </div>
- `;
- });
-
- afterEach(() => {
- document.getElementsByTagName('html')[0].innerHTML = '';
- });
-
- it('calls updateDetailsState', () => {
- store.updateState({ description: '' });
-
- expect(updateDescription).toHaveBeenCalledTimes(1);
- });
- });
-});
diff --git a/spec/frontend/issue_show/utils/update_description_spec.js b/spec/frontend/issue_show/utils/update_description_spec.js
deleted file mode 100644
index b2c6bd3c302..00000000000
--- a/spec/frontend/issue_show/utils/update_description_spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import updateDescription from '~/issue_show/utils/update_description';
-
-describe('updateDescription', () => {
- it('returns the correct value to be set as descriptionHtml', () => {
- const actual = updateDescription(
- '<details><summary>One</summary></details><details><summary>Two</summary></details>',
- [{ open: true }, { open: false }], // mocking NodeList from the dom.
- );
-
- expect(actual).toEqual(
- '<details open="true"><summary>One</summary></details><details><summary>Two</summary></details>',
- );
- });
-
- describe('when description details returned from api is different then whats currently on the dom', () => {
- it('returns the description from the api', () => {
- const dataDescription = '<details><summary>One</summary></details>';
-
- const actual = updateDescription(dataDescription, []);
-
- expect(actual).toEqual(dataDescription);
- });
- });
-});