Commit 065cef41 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Enrique Alcántara

Migrate issue_show application specs to jest

As part of the transition from Karma to jest,
migrate all issue show application specs
implemented in Karma to jest.
parent d84e96cc
......@@ -329,7 +329,7 @@ export default {
},
deleteIssuable(payload) {
this.service
return this.service
.deleteIssuable(payload)
.then(res => res.data)
.then(data => {
......@@ -340,7 +340,7 @@ export default {
})
.catch(() => {
createFlash(
sprintf(s__('Error deleting %{issuableType}'), { issuableType: this.issuableType }),
sprintf(s__('Error deleting %{issuableType}'), { issuableType: this.issuableType }),
);
});
},
......@@ -365,7 +365,12 @@ export default {
:issuable-type="issuableType"
/>
<recaptcha-modal v-show="showRecaptcha" :html="recaptchaHTML" @close="closeRecaptchaModal" />
<recaptcha-modal
v-show="showRecaptcha"
ref="recaptchaModal"
:html="recaptchaHTML"
@close="closeRecaptchaModal"
/>
</div>
<div v-else>
<title-component
......
......@@ -8386,7 +8386,7 @@ msgstr ""
msgid "Error creating label."
msgstr ""
msgid "Error deleting %{issuableType}"
msgid "Error deleting %{issuableType}"
msgstr ""
msgid "Error deleting project. Check logs for error details."
......
import $ from 'jquery';
import Vue from 'vue';
import '~/behaviors/markdown/render_gfm';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mountComponent from 'helpers/vue_mount_component_helper';
import { TEST_HOST } from 'helpers/test_constants';
import Description from '~/issue_show/components/description.vue';
import TaskList from '~/task_list';
jest.mock('~/task_list');
describe('Description component', () => {
let vm;
......@@ -13,7 +17,7 @@ describe('Description component', () => {
descriptionText: 'test',
updatedAt: new Date().toString(),
taskStatus: '',
updateUrl: gl.TEST_HOST,
updateUrl: TEST_HOST,
};
beforeEach(() => {
......@@ -39,25 +43,26 @@ describe('Description component', () => {
$('.issuable-meta .flash-container').remove();
});
it('animates description changes', done => {
it('animates description changes', () => {
vm.descriptionHtml = 'changed';
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.md').classList.contains('issue-realtime-pre-pulse'),
).toBeTruthy();
setTimeout(() => {
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();
done();
});
});
});
it('opens reCAPTCHA dialog if update rejected as spam', done => {
it('opens reCAPTCHA dialog if update rejected as spam', () => {
let modal;
const recaptchaChild = vm.$children.find(
// eslint-disable-next-line no-underscore-dangle
......@@ -70,7 +75,8 @@ describe('Description component', () => {
recaptcha_html: '<div class="g-recaptcha">recaptcha_html</div>',
});
vm.$nextTick()
return vm
.$nextTick()
.then(() => {
modal = vm.$el.querySelector('.js-recaptcha-modal');
......@@ -83,128 +89,105 @@ describe('Description component', () => {
.then(() => {
expect(modal.style.display).toEqual('none');
expect(document.body.querySelector('.js-recaptcha-script')).toBeNull();
})
.then(done)
.catch(done.fail);
});
});
describe('TaskList', () => {
let TaskList;
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,
Object.assign({}, props, {
issuableType: 'issuableType',
}),
);
TaskList = spyOnDependency(Description, 'TaskList');
});
it('re-inits the TaskList when description changed', done => {
it('re-inits the TaskList when description changed', () => {
vm.descriptionHtml = 'changed';
setTimeout(() => {
expect(TaskList).toHaveBeenCalled();
done();
});
expect(TaskList).toHaveBeenCalled();
});
it('does not re-init the TaskList when canUpdate is false', done => {
it('does not re-init the TaskList when canUpdate is false', () => {
vm.canUpdate = false;
vm.descriptionHtml = 'changed';
setTimeout(() => {
expect(TaskList).not.toHaveBeenCalled();
done();
});
expect(TaskList).toHaveBeenCalledTimes(1);
});
it('calls with issuableType dataType', done => {
it('calls with issuableType dataType', () => {
vm.descriptionHtml = 'changed';
setTimeout(() => {
expect(TaskList).toHaveBeenCalledWith({
dataType: 'issuableType',
fieldName: 'description',
selector: '.detail-page-description',
onSuccess: jasmine.any(Function),
onError: jasmine.any(Function),
lockVersion: 0,
});
done();
expect(TaskList).toHaveBeenCalledWith({
dataType: 'issuableType',
fieldName: 'description',
selector: '.detail-page-description',
onSuccess: expect.any(Function),
onError: expect.any(Function),
lockVersion: 0,
});
});
});
describe('taskStatus', () => {
it('adds full taskStatus', done => {
it('adds full taskStatus', () => {
vm.taskStatus = '1 of 1';
setTimeout(() => {
return vm.$nextTick().then(() => {
expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe(
'1 of 1',
);
done();
});
});
it('adds short taskStatus', done => {
it('adds short taskStatus', () => {
vm.taskStatus = '1 of 1';
setTimeout(() => {
return vm.$nextTick().then(() => {
expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe(
'1/1 task',
);
done();
});
});
it('clears task status text when no tasks are present', done => {
it('clears task status text when no tasks are present', () => {
vm.taskStatus = '0 of 0';
setTimeout(() => {
return vm.$nextTick().then(() => {
expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe('');
done();
});
});
});
it('applies syntax highlighting and math when description changed', done => {
spyOn(vm, 'renderGFM').and.callThrough();
spyOn($.prototype, 'renderGFM').and.callThrough();
vm.descriptionHtml = 'changed';
Vue.nextTick(() => {
setTimeout(() => {
expect(vm.$refs['gfm-content']).toBeDefined();
expect(vm.renderGFM).toHaveBeenCalled();
expect($.prototype.renderGFM).toHaveBeenCalled();
done();
});
});
});
it('sets data-update-url', () => {
expect(vm.$el.querySelector('textarea').dataset.updateUrl).toEqual(gl.TEST_HOST);
});
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.';
spyOn(vm, '$emit');
const spy = jest.spyOn(vm, '$emit');
vm.taskListUpdateError();
expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(msg);
expect(vm.$emit).toHaveBeenCalledWith('taskListUpdateFailed');
expect(spy).toHaveBeenCalledWith('taskListUpdateFailed');
});
});
});
......@@ -5,7 +5,7 @@ describe('Issue description template component', () => {
let vm;
let formState;
beforeEach(done => {
beforeEach(() => {
const Component = Vue.extend(descriptionTemplate);
formState = {
description: 'test',
......@@ -19,8 +19,6 @@ describe('Issue description template component', () => {
projectNamespace: '/',
},
}).$mount();
Vue.nextTick(done);
});
it('renders templates as JSON array in data attribute', () => {
......
import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mountComponent from 'helpers/vue_mount_component_helper';
import formComponent from '~/issue_show/components/form.vue';
import Autosave from '~/autosave';
import eventHub from '~/issue_show/event_hub';
jest.mock('~/autosave');
describe('Inline edit form component', () => {
let vm;
const defaultProps = {
......@@ -65,18 +68,16 @@ describe('Inline edit form component', () => {
});
describe('autosave', () => {
let autosaveObj;
let autosave;
let spy;
beforeEach(() => {
autosaveObj = { reset: jasmine.createSpy() };
autosave = spyOnDependency(formComponent, 'Autosave').and.returnValue(autosaveObj);
spy = jest.spyOn(Autosave.prototype, 'reset');
});
it('initialized Autosave on mount', () => {
createComponent();
expect(autosave).toHaveBeenCalledTimes(2);
expect(Autosave).toHaveBeenCalledTimes(2);
});
it('calls reset on autosave when eventHub emits appropriate events', () => {
......@@ -84,15 +85,15 @@ describe('Inline edit form component', () => {
eventHub.$emit('close.form');
expect(autosaveObj.reset).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledTimes(2);
eventHub.$emit('delete.issuable');
expect(autosaveObj.reset).toHaveBeenCalledTimes(4);
expect(spy).toHaveBeenCalledTimes(4);
eventHub.$emit('update.issuable');
expect(autosaveObj.reset).toHaveBeenCalledTimes(6);
expect(spy).toHaveBeenCalledTimes(6);
});
});
});
......@@ -5,8 +5,9 @@ import eventHub from '~/issue_show/event_hub';
describe('Title component', () => {
let vm;
beforeEach(() => {
setFixtures(`<title />`);
const Component = Vue.extend(titleComponent);
const store = new Store({
titleHtml: '',
......@@ -28,51 +29,39 @@ describe('Title component', () => {
expect(vm.$el.querySelector('.title').innerHTML.trim()).toBe('Testing <img>');
});
it('updates page title when changing titleHtml', done => {
spyOn(vm, 'setPageTitle');
it('updates page title when changing titleHtml', () => {
const spy = jest.spyOn(vm, 'setPageTitle');
vm.titleHtml = 'test';
Vue.nextTick(() => {
expect(vm.setPageTitle).toHaveBeenCalled();
done();
return vm.$nextTick().then(() => {
expect(spy).toHaveBeenCalled();
});
});
it('animates title changes', done => {
it('animates title changes', () => {
vm.titleHtml = 'test';
Vue.nextTick(() => {
expect(
vm.$el.querySelector('.title').classList.contains('issue-realtime-pre-pulse'),
).toBeTruthy();
setTimeout(() => {
expect(
vm.$el.querySelector('.title').classList.contains('issue-realtime-trigger-pulse'),
).toBeTruthy();
done();
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', done => {
it('updates page title after changing title', () => {
vm.titleHtml = 'changed';
vm.titleText = 'changed';
Vue.nextTick(() => {
return vm.$nextTick().then(() => {
expect(document.querySelector('title').textContent.trim()).toContain('changed');
done();
});
});
describe('inline edit button', () => {
beforeEach(() => {
spyOn(eventHub, '$emit');
});
it('should not show by default', () => {
expect(vm.$el.querySelector('.btn-edit')).toBeNull();
});
......@@ -92,6 +81,7 @@ describe('Title component', () => {
});
it('should trigger open.form event when clicked', () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
vm.showInlineEditButton = true;
vm.canUpdate = true;
......
export * from '../../frontend/issue_show/helpers.js';
export * from '../../frontend/issue_show/mock_data';
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment