Commit 23e014a9 authored by Himanshu Kapoor's avatar Himanshu Kapoor Committed by Enrique Alcántara

Migrate javascripts/sidebar specs to Jest

Migrate specs in spec/javascripts/sidebar from Karma to Jest.
parent 454c8f25
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import TimeTracker from '~/sidebar/components/time_tracking/time_tracker.vue'; import TimeTracker from '~/sidebar/components/time_tracking/time_tracker.vue';
describe('Issuable Time Tracker', () => { describe('Issuable Time Tracker', () => {
...@@ -35,7 +35,9 @@ describe('Issuable Time Tracker', () => { ...@@ -35,7 +35,9 @@ describe('Issuable Time Tracker', () => {
...TimeTracker.components, ...TimeTracker.components,
transition: { transition: {
// disable animations // disable animations
template: '<div><slot></slot></div>', render(h) {
return h('div', this.$slots.default);
},
}, },
}, },
}); });
...@@ -100,9 +102,9 @@ describe('Issuable Time Tracker', () => { ...@@ -100,9 +102,9 @@ describe('Issuable Time Tracker', () => {
it('should show full times when the sidebar is collapsed', done => { it('should show full times when the sidebar is collapsed', done => {
Vue.nextTick(() => { Vue.nextTick(() => {
const timeTrackingText = vm.$el.querySelector('.time-tracking-collapsed-summary span') const timeTrackingText = vm.$el.querySelector('.time-tracking-collapsed-summary span')
.innerText; .textContent;
expect(timeTrackingText).toBe('1h 23m / 1d 3h'); expect(timeTrackingText.trim()).toBe('1h 23m / 1d 3h');
done(); done();
}); });
}); });
...@@ -175,10 +177,10 @@ describe('Issuable Time Tracker', () => { ...@@ -175,10 +177,10 @@ describe('Issuable Time Tracker', () => {
it('should display the human readable version of time estimated', done => { it('should display the human readable version of time estimated', done => {
Vue.nextTick(() => { Vue.nextTick(() => {
const estimateText = vm.$el.querySelector('.time-tracking-estimate-only-pane') const estimateText = vm.$el.querySelector('.time-tracking-estimate-only-pane')
.innerText; .textContent;
const correctText = 'Estimated: 2h 46m'; const correctText = 'Estimated: 2h 46m';
expect(estimateText).toBe(correctText); expect(estimateText.trim()).toBe(correctText);
done(); done();
}); });
}); });
...@@ -196,7 +198,7 @@ describe('Issuable Time Tracker', () => { ...@@ -196,7 +198,7 @@ describe('Issuable Time Tracker', () => {
it('should display the human readable version of time spent', done => { it('should display the human readable version of time spent', done => {
Vue.nextTick(() => { Vue.nextTick(() => {
const spentText = vm.$el.querySelector('.time-tracking-spend-only-pane').innerText; const spentText = vm.$el.querySelector('.time-tracking-spend-only-pane').textContent;
const correctText = 'Spent: 1h 23m'; const correctText = 'Spent: 1h 23m';
expect(spentText).toBe(correctText); expect(spentText).toBe(correctText);
...@@ -218,12 +220,12 @@ describe('Issuable Time Tracker', () => { ...@@ -218,12 +220,12 @@ describe('Issuable Time Tracker', () => {
it('should only show the "No time tracking" pane when both timeEstimate and time_spent are falsey', done => { it('should only show the "No time tracking" pane when both timeEstimate and time_spent are falsey', done => {
Vue.nextTick(() => { Vue.nextTick(() => {
const $noTrackingPane = vm.$el.querySelector('.time-tracking-no-tracking-pane'); const $noTrackingPane = vm.$el.querySelector('.time-tracking-no-tracking-pane');
const noTrackingText = $noTrackingPane.innerText; const noTrackingText = $noTrackingPane.textContent;
const correctText = 'No estimate or time spent'; const correctText = 'No estimate or time spent';
expect(vm.showNoTimeTrackingState).toBe(true); expect(vm.showNoTimeTrackingState).toBe(true);
expect($noTrackingPane).toBeVisible(); expect($noTrackingPane).toBeVisible();
expect(noTrackingText).toBe(correctText); expect(noTrackingText.trim()).toBe(correctText);
done(); done();
}); });
}); });
...@@ -234,12 +236,10 @@ describe('Issuable Time Tracker', () => { ...@@ -234,12 +236,10 @@ describe('Issuable Time Tracker', () => {
const closeHelpButton = () => vm.$el.querySelector('.close-help-button'); const closeHelpButton = () => vm.$el.querySelector('.close-help-button');
const helpPane = () => vm.$el.querySelector('.time-tracking-help-state'); const helpPane = () => vm.$el.querySelector('.time-tracking-help-state');
beforeEach(done => { beforeEach(() => {
initTimeTrackingComponent({ timeEstimate: 0, timeSpent: 0 }); initTimeTrackingComponent({ timeEstimate: 0, timeSpent: 0 });
Vue.nextTick() return vm.$nextTick();
.then(done)
.catch(done.fail);
}); });
it('should not show the "Help" pane by default', () => { it('should not show the "Help" pane by default', () => {
...@@ -247,16 +247,17 @@ describe('Issuable Time Tracker', () => { ...@@ -247,16 +247,17 @@ describe('Issuable Time Tracker', () => {
expect(helpPane()).toBeNull(); expect(helpPane()).toBeNull();
}); });
it('should show the "Help" pane when help button is clicked', done => { it('should show the "Help" pane when help button is clicked', () => {
helpButton().click(); helpButton().click();
Vue.nextTick() return vm.$nextTick().then(() => {
.then(() => {
expect(vm.showHelpState).toBe(true); expect(vm.showHelpState).toBe(true);
// let animations run
jest.advanceTimersByTime(500);
expect(helpPane()).toBeVisible(); expect(helpPane()).toBeVisible();
}) });
.then(done)
.catch(done.fail);
}); });
it('should not show the "Help" pane when help button is clicked and then closed', done => { it('should not show the "Help" pane when help button is clicked and then closed', done => {
......
import Vue from 'vue'; import Vue from 'vue';
import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper'; import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
import lockIssueSidebar from '~/sidebar/components/lock/lock_issue_sidebar.vue'; import lockIssueSidebar from '~/sidebar/components/lock/lock_issue_sidebar.vue';
describe('LockIssueSidebar', () => { describe('LockIssueSidebar', () => {
...@@ -61,7 +61,7 @@ describe('LockIssueSidebar', () => { ...@@ -61,7 +61,7 @@ describe('LockIssueSidebar', () => {
}); });
it('tracks an event when "Edit" is clicked', () => { it('tracks an event when "Edit" is clicked', () => {
const spy = mockTracking('_category_', vm1.$el, spyOn); const spy = mockTracking('_category_', vm1.$el, jest.spyOn);
triggerEvent('.lock-edit'); triggerEvent('.lock-edit');
expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', { expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
...@@ -77,7 +77,7 @@ describe('LockIssueSidebar', () => { ...@@ -77,7 +77,7 @@ describe('LockIssueSidebar', () => {
expect(vm1.isLockDialogOpen).toBe(true); expect(vm1.isLockDialogOpen).toBe(true);
setTimeout(() => { setImmediate(() => {
expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true); expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true);
done(); done();
......
...@@ -7,15 +7,16 @@ import SidebarService from '~/sidebar/services/sidebar_service'; ...@@ -7,15 +7,16 @@ import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue'; import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue';
import Mock from './mock_data'; import Mock from './mock_data';
describe('SidebarMoveIssue', function() { describe('SidebarMoveIssue', () => {
let mock; let mock;
const test = {};
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
const mockData = Mock.responseMap.GET['/autocomplete/projects?project_id=15']; const mockData = Mock.responseMap.GET['/autocomplete/projects?project_id=15'];
mock.onGet('/autocomplete/projects?project_id=15').reply(200, mockData); mock.onGet('/autocomplete/projects?project_id=15').reply(200, mockData);
this.mediator = new SidebarMediator(Mock.mediator); test.mediator = new SidebarMediator(Mock.mediator);
this.$content = $(` test.$content = $(`
<div class="dropdown"> <div class="dropdown">
<div class="js-toggle"></div> <div class="js-toggle"></div>
<div class="dropdown-menu"> <div class="dropdown-menu">
...@@ -24,15 +25,15 @@ describe('SidebarMoveIssue', function() { ...@@ -24,15 +25,15 @@ describe('SidebarMoveIssue', function() {
<div class="js-confirm-button"></div> <div class="js-confirm-button"></div>
</div> </div>
`); `);
this.$toggleButton = this.$content.find('.js-toggle'); test.$toggleButton = test.$content.find('.js-toggle');
this.$confirmButton = this.$content.find('.js-confirm-button'); test.$confirmButton = test.$content.find('.js-confirm-button');
this.sidebarMoveIssue = new SidebarMoveIssue( test.sidebarMoveIssue = new SidebarMoveIssue(
this.mediator, test.mediator,
this.$toggleButton, test.$toggleButton,
this.$confirmButton, test.$confirmButton,
); );
this.sidebarMoveIssue.init(); test.sidebarMoveIssue.init();
}); });
afterEach(() => { afterEach(() => {
...@@ -40,46 +41,46 @@ describe('SidebarMoveIssue', function() { ...@@ -40,46 +41,46 @@ describe('SidebarMoveIssue', function() {
SidebarStore.singleton = null; SidebarStore.singleton = null;
SidebarMediator.singleton = null; SidebarMediator.singleton = null;
this.sidebarMoveIssue.destroy(); test.sidebarMoveIssue.destroy();
mock.restore(); mock.restore();
}); });
describe('init', () => { describe('init', () => {
it('should initialize the dropdown and listeners', () => { it('should initialize the dropdown and listeners', () => {
spyOn(this.sidebarMoveIssue, 'initDropdown'); jest.spyOn(test.sidebarMoveIssue, 'initDropdown').mockImplementation(() => {});
spyOn(this.sidebarMoveIssue, 'addEventListeners'); jest.spyOn(test.sidebarMoveIssue, 'addEventListeners').mockImplementation(() => {});
this.sidebarMoveIssue.init(); test.sidebarMoveIssue.init();
expect(this.sidebarMoveIssue.initDropdown).toHaveBeenCalled(); expect(test.sidebarMoveIssue.initDropdown).toHaveBeenCalled();
expect(this.sidebarMoveIssue.addEventListeners).toHaveBeenCalled(); expect(test.sidebarMoveIssue.addEventListeners).toHaveBeenCalled();
}); });
}); });
describe('destroy', () => { describe('destroy', () => {
it('should remove the listeners', () => { it('should remove the listeners', () => {
spyOn(this.sidebarMoveIssue, 'removeEventListeners'); jest.spyOn(test.sidebarMoveIssue, 'removeEventListeners').mockImplementation(() => {});
this.sidebarMoveIssue.destroy(); test.sidebarMoveIssue.destroy();
expect(this.sidebarMoveIssue.removeEventListeners).toHaveBeenCalled(); expect(test.sidebarMoveIssue.removeEventListeners).toHaveBeenCalled();
}); });
}); });
describe('initDropdown', () => { describe('initDropdown', () => {
it('should initialize the gl_dropdown', () => { it('should initialize the gl_dropdown', () => {
spyOn($.fn, 'glDropdown'); jest.spyOn($.fn, 'glDropdown').mockImplementation(() => {});
this.sidebarMoveIssue.initDropdown(); test.sidebarMoveIssue.initDropdown();
expect($.fn.glDropdown).toHaveBeenCalled(); expect($.fn.glDropdown).toHaveBeenCalled();
}); });
it('escapes html from project name', done => { it('escapes html from project name', done => {
this.$toggleButton.dropdown('toggle'); test.$toggleButton.dropdown('toggle');
setTimeout(() => { setImmediate(() => {
expect(this.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual( expect(test.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual(
'&lt;img src=x onerror=alert(document.domain)&gt; foo / bar', '&lt;img src=x onerror=alert(document.domain)&gt; foo / bar',
); );
done(); done();
...@@ -89,78 +90,78 @@ describe('SidebarMoveIssue', function() { ...@@ -89,78 +90,78 @@ describe('SidebarMoveIssue', function() {
describe('onConfirmClicked', () => { describe('onConfirmClicked', () => {
it('should move the issue with valid project ID', () => { it('should move the issue with valid project ID', () => {
spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.resolve()); jest.spyOn(test.mediator, 'moveIssue').mockReturnValue(Promise.resolve());
this.mediator.setMoveToProjectId(7); test.mediator.setMoveToProjectId(7);
this.sidebarMoveIssue.onConfirmClicked(); test.sidebarMoveIssue.onConfirmClicked();
expect(this.mediator.moveIssue).toHaveBeenCalled(); expect(test.mediator.moveIssue).toHaveBeenCalled();
expect(this.$confirmButton.prop('disabled')).toBeTruthy(); expect(test.$confirmButton.prop('disabled')).toBeTruthy();
expect(this.$confirmButton.hasClass('is-loading')).toBe(true); expect(test.$confirmButton.hasClass('is-loading')).toBe(true);
}); });
it('should remove loading state from confirm button on failure', done => { it('should remove loading state from confirm button on failure', done => {
spyOn(window, 'Flash'); jest.spyOn(window, 'Flash').mockImplementation(() => {});
spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.reject()); jest.spyOn(test.mediator, 'moveIssue').mockReturnValue(Promise.reject());
this.mediator.setMoveToProjectId(7); test.mediator.setMoveToProjectId(7);
this.sidebarMoveIssue.onConfirmClicked(); test.sidebarMoveIssue.onConfirmClicked();
expect(this.mediator.moveIssue).toHaveBeenCalled(); expect(test.mediator.moveIssue).toHaveBeenCalled();
// Wait for the move issue request to fail // Wait for the move issue request to fail
setTimeout(() => { setImmediate(() => {
expect(window.Flash).toHaveBeenCalled(); expect(window.Flash).toHaveBeenCalled();
expect(this.$confirmButton.prop('disabled')).toBeFalsy(); expect(test.$confirmButton.prop('disabled')).toBeFalsy();
expect(this.$confirmButton.hasClass('is-loading')).toBe(false); expect(test.$confirmButton.hasClass('is-loading')).toBe(false);
done(); done();
}); });
}); });
it('should not move the issue with id=0', () => { it('should not move the issue with id=0', () => {
spyOn(this.mediator, 'moveIssue'); jest.spyOn(test.mediator, 'moveIssue').mockImplementation(() => {});
this.mediator.setMoveToProjectId(0); test.mediator.setMoveToProjectId(0);
this.sidebarMoveIssue.onConfirmClicked(); test.sidebarMoveIssue.onConfirmClicked();
expect(this.mediator.moveIssue).not.toHaveBeenCalled(); expect(test.mediator.moveIssue).not.toHaveBeenCalled();
}); });
}); });
it('should set moveToProjectId on dropdown item "No project" click', done => { it('should set moveToProjectId on dropdown item "No project" click', done => {
spyOn(this.mediator, 'setMoveToProjectId'); jest.spyOn(test.mediator, 'setMoveToProjectId').mockImplementation(() => {});
// Open the dropdown // Open the dropdown
this.$toggleButton.dropdown('toggle'); test.$toggleButton.dropdown('toggle');
// Wait for the autocomplete request to finish // Wait for the autocomplete request to finish
setTimeout(() => { setImmediate(() => {
this.$content test.$content
.find('.js-move-issue-dropdown-item') .find('.js-move-issue-dropdown-item')
.eq(0) .eq(0)
.trigger('click'); .trigger('click');
expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(0); expect(test.mediator.setMoveToProjectId).toHaveBeenCalledWith(0);
expect(this.$confirmButton.prop('disabled')).toBeTruthy(); expect(test.$confirmButton.prop('disabled')).toBeTruthy();
done(); done();
}, 0); });
}); });
it('should set moveToProjectId on dropdown item click', done => { it('should set moveToProjectId on dropdown item click', done => {
spyOn(this.mediator, 'setMoveToProjectId'); jest.spyOn(test.mediator, 'setMoveToProjectId').mockImplementation(() => {});
// Open the dropdown // Open the dropdown
this.$toggleButton.dropdown('toggle'); test.$toggleButton.dropdown('toggle');
// Wait for the autocomplete request to finish // Wait for the autocomplete request to finish
setTimeout(() => { setImmediate(() => {
this.$content test.$content
.find('.js-move-issue-dropdown-item') .find('.js-move-issue-dropdown-item')
.eq(1) .eq(1)
.trigger('click'); .trigger('click');
expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(20); expect(test.mediator.setMoveToProjectId).toHaveBeenCalledWith(20);
expect(this.$confirmButton.attr('disabled')).toBe(undefined); expect(test.$confirmButton.attr('disabled')).toBe(undefined);
done(); done();
}, 0); });
}); });
}); });
// No new code should be added to this file. Instead, modify the
// file this one re-exports from. For more detail about why, see:
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
import mockData from '../../frontend/sidebar/mock_data';
export default mockData;
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