diff options
Diffstat (limited to 'spec/frontend/issues/show/components')
7 files changed, 299 insertions, 223 deletions
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js index 02db82b84dc..ac2717a5028 100644 --- a/spec/frontend/issues/show/components/app_spec.js +++ b/spec/frontend/issues/show/components/app_spec.js @@ -145,33 +145,30 @@ describe('Issuable output', () => { }); }); - it('shows actions if permissions are correct', () => { + it('shows actions if permissions are correct', async () => { wrapper.vm.showForm = true; - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find('.markdown-selector').exists()).toBe(true); - }); + await nextTick(); + expect(wrapper.find('.markdown-selector').exists()).toBe(true); }); - it('does not show actions if permissions are incorrect', () => { + it('does not show actions if permissions are incorrect', async () => { wrapper.vm.showForm = true; wrapper.setProps({ canUpdate: false }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find('.markdown-selector').exists()).toBe(false); - }); + await nextTick(); + expect(wrapper.find('.markdown-selector').exists()).toBe(false); }); - it('does not update formState if form is already open', () => { + it('does not update formState if form is already open', async () => { 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'); - }); + await nextTick(); + expect(wrapper.vm.store.formState.title).not.toBe('testing 123'); }); describe('Pinned links propagated', () => { @@ -186,31 +183,29 @@ describe('Issuable output', () => { }); describe('updateIssuable', () => { - it('fetches new data after update', () => { + it('fetches new data after update', async () => { 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(); - }); + await wrapper.vm.updateIssuable(); + expect(updateStoreSpy).toHaveBeenCalled(); + expect(getDataSpy).toHaveBeenCalled(); }); - it('correctly updates issuable data', () => { + it('correctly updates issuable data', async () => { 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'); - }); + await wrapper.vm.updateIssuable(); + expect(spy).toHaveBeenCalledWith(wrapper.vm.formState); + expect(eventHub.$emit).toHaveBeenCalledWith('close.form'); }); - it('does not redirect if issue has not moved', () => { + it('does not redirect if issue has not moved', async () => { jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({ data: { web_url: window.location.pathname, @@ -218,12 +213,11 @@ describe('Issuable output', () => { }, }); - return wrapper.vm.updateIssuable().then(() => { - expect(visitUrl).not.toHaveBeenCalled(); - }); + await wrapper.vm.updateIssuable(); + expect(visitUrl).not.toHaveBeenCalled(); }); - it('does not redirect if issue has not moved and user has switched tabs', () => { + it('does not redirect if issue has not moved and user has switched tabs', async () => { jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({ data: { web_url: '', @@ -231,12 +225,11 @@ describe('Issuable output', () => { }, }); - return wrapper.vm.updateIssuable().then(() => { - expect(visitUrl).not.toHaveBeenCalled(); - }); + await wrapper.vm.updateIssuable(); + expect(visitUrl).not.toHaveBeenCalled(); }); - it('redirects if returned web_url has changed', () => { + it('redirects if returned web_url has changed', async () => { jest.spyOn(wrapper.vm.service, 'updateIssuable').mockResolvedValue({ data: { web_url: '/testing-issue-move', @@ -246,108 +239,95 @@ describe('Issuable output', () => { wrapper.vm.updateIssuable(); - return wrapper.vm.updateIssuable().then(() => { - expect(visitUrl).toHaveBeenCalledWith('/testing-issue-move'); - }); + await wrapper.vm.updateIssuable(); + expect(visitUrl).toHaveBeenCalledWith('/testing-issue-move'); }); describe('shows dialog when issue has unsaved changed', () => { - it('confirms on title change', () => { + it('confirms on title change', async () => { 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(); - }); + await nextTick(); + expect(e.returnValue).not.toBeNull(); }); - it('confirms on description change', () => { + it('confirms on description change', async () => { 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(); - }); + await nextTick(); + expect(e.returnValue).not.toBeNull(); }); - it('does nothing when nothing has changed', () => { + it('does nothing when nothing has changed', async () => { const e = { returnValue: null }; wrapper.vm.handleBeforeUnloadEvent(e); - return wrapper.vm.$nextTick().then(() => { - expect(e.returnValue).toBeNull(); - }); + await nextTick(); + expect(e.returnValue).toBeNull(); }); }); describe('error when updating', () => { - it('closes form on error', () => { + it('closes form on error', async () => { 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`, - ); - }); + await wrapper.vm.updateIssuable(); + 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', () => { + it('returns the correct error message for issuableType', async () => { 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`, - ); - }); + await nextTick(); + await wrapper.vm.updateIssuable(); + 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', () => { + it('shows error message from backend if exists', async () => { 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}`, - ); - }); + await wrapper.vm.updateIssuable(); + expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe( + `${wrapper.vm.defaultErrorMessage}. ${msg}`, + ); }); }); }); 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); + it('shows locked warning if form is open & data is different', async () => { + await nextTick(); + wrapper.vm.updateAndShowForm(); + + wrapper.vm.poll.makeRequest(); + + await new Promise((resolve) => { + wrapper.vm.$watch('formState.lockedWarningVisible', (value) => { + if (value) { + resolve(); + } }); + }); + + expect(wrapper.vm.formState.lockedWarningVisible).toBe(true); + expect(wrapper.vm.formState.lock_version).toBe(1); + expect(findAlert().exists()).toBe(true); }); }); @@ -398,12 +378,11 @@ describe('Issuable output', () => { expect(wrapper.find('.btn-edit').exists()).toBe(true); }); - it('should render if showInlineEditButton', () => { + it('should render if showInlineEditButton', async () => { wrapper.setProps({ showInlineEditButton: true }); - return wrapper.vm.$nextTick(() => { - expect(wrapper.find('.btn-edit').exists()).toBe(true); - }); + await nextTick(); + expect(wrapper.find('.btn-edit').exists()).toBe(true); }); }); diff --git a/spec/frontend/issues/show/components/description_spec.js b/spec/frontend/issues/show/components/description_spec.js index d39e00b9c9e..3890fc7a353 100644 --- a/spec/frontend/issues/show/components/description_spec.js +++ b/spec/frontend/issues/show/components/description_spec.js @@ -1,21 +1,56 @@ import $ from 'jquery'; -import Vue from 'vue'; +import { nextTick } from 'vue'; import '~/behaviors/markdown/render_gfm'; +import { GlPopover, GlModal } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { stubComponent } from 'helpers/stub_component'; import { TEST_HOST } from 'helpers/test_constants'; -import mountComponent from 'helpers/vue_mount_component_helper'; import Description from '~/issues/show/components/description.vue'; import TaskList from '~/task_list'; -import { descriptionProps as props } from '../mock_data/mock_data'; +import CreateWorkItem from '~/work_items/pages/create_work_item.vue'; +import { + descriptionProps as initialProps, + descriptionHtmlWithCheckboxes, +} from '../mock_data/mock_data'; jest.mock('~/task_list'); +const showModal = jest.fn(); +const hideModal = jest.fn(); + describe('Description component', () => { - let vm; - let DescriptionComponent; + let wrapper; + + const findGfmContent = () => wrapper.find('[data-testid="gfm-content"]'); + const findTextarea = () => wrapper.find('[data-testid="textarea"]'); + const findTaskActionButtons = () => wrapper.findAll('.js-add-task'); + const findConvertToTaskButton = () => wrapper.find('[data-testid="convert-to-task"]'); + const findTaskSvg = () => wrapper.find('[data-testid="issue-open-m-icon"]'); + + const findPopovers = () => wrapper.findAllComponents(GlPopover); + const findModal = () => wrapper.findComponent(GlModal); + const findCreateWorkItem = () => wrapper.findComponent(CreateWorkItem); + + function createComponent({ props = {}, provide = {} } = {}) { + wrapper = shallowMount(Description, { + propsData: { + ...initialProps, + ...props, + }, + provide, + stubs: { + GlModal: stubComponent(GlModal, { + methods: { + show: showModal, + hide: hideModal, + }, + }), + GlPopover, + }, + }); + } beforeEach(() => { - DescriptionComponent = Vue.extend(Description); - if (!document.querySelector('.issuable-meta')) { const metaData = document.createElement('div'); metaData.classList.add('issuable-meta'); @@ -24,91 +59,102 @@ describe('Description component', () => { document.body.appendChild(metaData); } - - vm = mountComponent(DescriptionComponent, props); }); afterEach(() => { - vm.$destroy(); + wrapper.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('doesnt animate first description changes', async () => { + createComponent(); + await wrapper.setProps({ + descriptionHtml: 'changed', }); + + expect(findGfmContent().classes()).not.toContain('issue-realtime-pre-pulse'); }); - 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('animates description changes on live update', async () => { + createComponent(); + await wrapper.setProps({ + descriptionHtml: 'changed', + }); + + expect(findGfmContent().classes()).not.toContain('issue-realtime-pre-pulse'); + + await wrapper.setProps({ + descriptionHtml: 'changed second time', + }); + + expect(findGfmContent().classes()).toContain('issue-realtime-pre-pulse'); + + await jest.runOnlyPendingTimers(); + + expect(findGfmContent().classes()).toContain('issue-realtime-trigger-pulse'); }); - it('applies syntax highlighting and math when description changed', () => { - const vmSpy = jest.spyOn(vm, 'renderGFM'); + it('applies syntax highlighting and math when description changed', async () => { const prototypeSpy = jest.spyOn($.prototype, 'renderGFM'); - vm.descriptionHtml = 'changed'; + createComponent(); - return vm.$nextTick().then(() => { - expect(vm.$refs['gfm-content']).toBeDefined(); - expect(vmSpy).toHaveBeenCalled(); - expect(prototypeSpy).toHaveBeenCalled(); - expect($.prototype.renderGFM).toHaveBeenCalled(); + await wrapper.setProps({ + descriptionHtml: 'changed', }); + + expect(findGfmContent().exists()).toBe(true); + expect(prototypeSpy).toHaveBeenCalled(); }); it('sets data-update-url', () => { - expect(vm.$el.querySelector('textarea').dataset.updateUrl).toEqual(TEST_HOST); + createComponent(); + expect(findTextarea().attributes('data-update-url')).toBe(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'; + createComponent({ + props: { + issuableType: 'issuableType', + }, + }); + wrapper.setProps({ + descriptionHtml: 'changed', + }); expect(TaskList).toHaveBeenCalled(); }); - it('does not re-init the TaskList when canUpdate is false', () => { - vm.canUpdate = false; - vm.descriptionHtml = 'changed'; + it('does not re-init the TaskList when canUpdate is false', async () => { + createComponent({ + props: { + issuableType: 'issuableType', + canUpdate: false, + }, + }); + wrapper.setProps({ + descriptionHtml: 'changed', + }); - expect(TaskList).toHaveBeenCalledTimes(1); + expect(TaskList).not.toHaveBeenCalled(); }); it('calls with issuableType dataType', () => { - vm.descriptionHtml = 'changed'; + createComponent({ + props: { + issuableType: 'issuableType', + }, + }); + wrapper.setProps({ + descriptionHtml: 'changed', + }); expect(TaskList).toHaveBeenCalledWith({ dataType: 'issuableType', @@ -123,65 +169,119 @@ describe('Description component', () => { }); 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 full taskStatus', async () => { + createComponent({ + props: { + taskStatus: '1 of 1', + }, }); - }); + await nextTick(); - it('adds short taskStatus', () => { - vm.taskStatus = '1 of 1'; + expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe( + '1 of 1', + ); + }); - return vm.$nextTick().then(() => { - expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe( - '1/1 task', - ); + it('adds short taskStatus', async () => { + createComponent({ + props: { + taskStatus: '1 of 1', + }, }); - }); + await nextTick(); - it('clears task status text when no tasks are present', () => { - vm.taskStatus = '0 of 0'; + expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe( + '1/1 task', + ); + }); - return vm.$nextTick().then(() => { - expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe(''); + it('clears task status text when no tasks are present', async () => { + createComponent({ + props: { + taskStatus: '0 of 0', + }, }); + + await nextTick(); + + 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(); + describe('with work items feature flag is enabled', () => { + describe('empty description', () => { + beforeEach(async () => { + createComponent({ + props: { + descriptionHtml: '', + }, + provide: { + glFeatures: { + workItems: true, + }, + }, + }); + await nextTick(); + }); - expect(spy).toHaveBeenCalledWith('taskListUpdateStarted'); + it('renders without error', () => { + expect(findTaskActionButtons()).toHaveLength(0); + }); }); - }); - describe('taskListUpdateSuccess', () => { - it('emits event to parent', () => { - const spy = jest.spyOn(vm, '$emit'); + describe('description with checkboxes', () => { + beforeEach(async () => { + createComponent({ + props: { + descriptionHtml: descriptionHtmlWithCheckboxes, + }, + provide: { + glFeatures: { + workItems: true, + }, + }, + }); + await nextTick(); + }); - vm.taskListUpdateSuccess(); + it('renders a list of hidden buttons corresponding to checkboxes in description HTML', () => { + expect(findTaskActionButtons()).toHaveLength(3); + }); - expect(spy).toHaveBeenCalledWith('taskListUpdateSucceeded'); - }); - }); + it('renders a list of popovers corresponding to checkboxes in description HTML', () => { + expect(findPopovers()).toHaveLength(3); + expect(findPopovers().at(0).props('target')).toBe( + findTaskActionButtons().at(0).attributes('id'), + ); + }); - 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'); + it('does not show a modal by default', () => { + expect(findModal().props('visible')).toBe(false); + }); - vm.taskListUpdateError(); + it('opens a modal when a button on popover is clicked and displays correct title', async () => { + findConvertToTaskButton().vm.$emit('click'); + expect(showModal).toHaveBeenCalled(); + await nextTick(); + expect(findCreateWorkItem().props('initialTitle').trim()).toBe('todo 1'); + }); + + it('closes the modal on `closeCreateTaskModal` event', () => { + findConvertToTaskButton().vm.$emit('click'); + findCreateWorkItem().vm.$emit('closeModal'); + expect(hideModal).toHaveBeenCalled(); + }); - expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(msg); - expect(spy).toHaveBeenCalledWith('taskListUpdateFailed'); + it('updates description HTML on `onCreate` event', async () => { + const newTitle = 'New title'; + findConvertToTaskButton().vm.$emit('click'); + findCreateWorkItem().vm.$emit('onCreate', newTitle); + expect(hideModal).toHaveBeenCalled(); + await nextTick(); + + expect(findTaskSvg().exists()).toBe(true); + expect(wrapper.text()).toContain(newTitle); + }); }); }); }); diff --git a/spec/frontend/issues/show/components/fields/description_spec.js b/spec/frontend/issues/show/components/fields/description_spec.js index 3043c4c3673..dd511c3945c 100644 --- a/spec/frontend/issues/show/components/fields/description_spec.js +++ b/spec/frontend/issues/show/components/fields/description_spec.js @@ -25,6 +25,7 @@ describe('Description field component', () => { beforeEach(() => { jest.spyOn(eventHub, '$emit'); + gon.features = { markdownContinueLists: true }; }); afterEach(() => { diff --git a/spec/frontend/issues/show/components/fields/type_spec.js b/spec/frontend/issues/show/components/fields/type_spec.js index 7f7b16583e6..3333ceffca9 100644 --- a/spec/frontend/issues/show/components/fields/type_spec.js +++ b/spec/frontend/issues/show/components/fields/type_spec.js @@ -1,5 +1,6 @@ import { GlFormGroup, GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; +import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -10,8 +11,7 @@ import { updateIssueStateQueryResponse, } from '../../mock_data/apollo_mock'; -const localVue = createLocalVue(); -localVue.use(VueApollo); +Vue.use(VueApollo); describe('Issue type field component', () => { let wrapper; @@ -43,7 +43,6 @@ describe('Issue type field component', () => { fakeApollo = createMockApollo([], mockResolvers); wrapper = shallowMount(IssueTypeField, { - localVue, apolloProvider: fakeApollo, data() { return { @@ -93,7 +92,7 @@ describe('Issue type field component', () => { 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(); + await nextTick(); expect(findTypeFromDropDown().attributes('value')).toBe(issuableTypes.incident); }); diff --git a/spec/frontend/issues/show/components/form_spec.js b/spec/frontend/issues/show/components/form_spec.js index db49d2635ba..5c0fe991b22 100644 --- a/spec/frontend/issues/show/components/form_spec.js +++ b/spec/frontend/issues/show/components/form_spec.js @@ -1,5 +1,6 @@ import { GlAlert } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; import Autosave from '~/autosave'; import DescriptionTemplate from '~/issues/show/components/fields/description_template.vue'; import IssueTypeField from '~/issues/show/components/fields/type.vue'; @@ -148,7 +149,7 @@ describe('Inline edit form component', () => { formState: { ...defaultProps.formState, lock_version: 'lock version from server' }, }); - await wrapper.vm.$nextTick(); + await nextTick(); expect(findAlert().exists()).toBe(true); }); }); diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js index d09bf6faa13..4a557a60b94 100644 --- a/spec/frontend/issues/show/components/header_actions_spec.js +++ b/spec/frontend/issues/show/components/header_actions_spec.js @@ -1,5 +1,5 @@ import { GlButton, GlDropdown, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui'; -import Vue from 'vue'; +import Vue, { nextTick } from 'vue'; import { shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import { mockTracking } from 'helpers/tracking_helper'; @@ -153,7 +153,7 @@ describe('HeaderActions component', () => { it('dispatches a custom event to update the issue page', async () => { findToggleIssueStateButton().vm.$emit('click'); - await wrapper.vm.$nextTick(); + await nextTick(); expect(dispatchEventSpy).toHaveBeenCalledTimes(1); }); diff --git a/spec/frontend/issues/show/components/title_spec.js b/spec/frontend/issues/show/components/title_spec.js index f9026557be2..29b5353ef1c 100644 --- a/spec/frontend/issues/show/components/title_spec.js +++ b/spec/frontend/issues/show/components/title_spec.js @@ -1,4 +1,4 @@ -import Vue from 'vue'; +import Vue, { nextTick } from 'vue'; import titleComponent from '~/issues/show/components/title.vue'; import eventHub from '~/issues/show/event_hub'; import Store from '~/issues/show/stores'; @@ -29,36 +29,33 @@ describe('Title component', () => { expect(vm.$el.querySelector('.title').innerHTML.trim()).toBe('Testing <img>'); }); - it('updates page title when changing titleHtml', () => { + it('updates page title when changing titleHtml', async () => { const spy = jest.spyOn(vm, 'setPageTitle'); vm.titleHtml = 'test'; - return vm.$nextTick().then(() => { - expect(spy).toHaveBeenCalled(); - }); + await nextTick(); + expect(spy).toHaveBeenCalled(); }); - it('animates title changes', () => { + it('animates title changes', async () => { 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'); - }); + + await nextTick(); + + expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-pre-pulse'); + jest.runAllTimers(); + + await nextTick(); + + expect(vm.$el.querySelector('.title').classList).toContain('issue-realtime-trigger-pulse'); }); - it('updates page title after changing title', () => { + it('updates page title after changing title', async () => { vm.titleHtml = 'changed'; vm.titleText = 'changed'; - return vm.$nextTick().then(() => { - expect(document.querySelector('title').textContent.trim()).toContain('changed'); - }); + await nextTick(); + expect(document.querySelector('title').textContent.trim()).toContain('changed'); }); describe('inline edit button', () => { @@ -80,16 +77,15 @@ describe('Title component', () => { expect(vm.$el.querySelector('.btn-edit')).toBeDefined(); }); - it('should trigger open.form event when clicked', () => { + it('should trigger open.form event when clicked', async () => { jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); vm.showInlineEditButton = true; vm.canUpdate = true; - Vue.nextTick(() => { - vm.$el.querySelector('.btn-edit').click(); + await nextTick(); + vm.$el.querySelector('.btn-edit').click(); - expect(eventHub.$emit).toHaveBeenCalledWith('open.form'); - }); + expect(eventHub.$emit).toHaveBeenCalledWith('open.form'); }); }); }); |