Commit cbebb046 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch 'himkp-jest-sidebar' into 'master'

Migrate spec/javascripts/sidebar/ to Jest

Closes #194256

See merge request gitlab-org/gitlab!32535
parents 23193ed0 23e014a9
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';
describe('Issuable Time Tracker', () => {
......@@ -35,7 +35,9 @@ describe('Issuable Time Tracker', () => {
...TimeTracker.components,
transition: {
// disable animations
template: '<div><slot></slot></div>',
render(h) {
return h('div', this.$slots.default);
},
},
},
});
......@@ -100,9 +102,9 @@ describe('Issuable Time Tracker', () => {
it('should show full times when the sidebar is collapsed', done => {
Vue.nextTick(() => {
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();
});
});
......@@ -175,10 +177,10 @@ describe('Issuable Time Tracker', () => {
it('should display the human readable version of time estimated', done => {
Vue.nextTick(() => {
const estimateText = vm.$el.querySelector('.time-tracking-estimate-only-pane')
.innerText;
const correctText = 'Estimated: 2h 46m';
.textContent;
const correctText = 'Estimated: 2h 46m';
expect(estimateText).toBe(correctText);
expect(estimateText.trim()).toBe(correctText);
done();
});
});
......@@ -196,7 +198,7 @@ describe('Issuable Time Tracker', () => {
it('should display the human readable version of time spent', done => {
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';
expect(spentText).toBe(correctText);
......@@ -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 => {
Vue.nextTick(() => {
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';
expect(vm.showNoTimeTrackingState).toBe(true);
expect($noTrackingPane).toBeVisible();
expect(noTrackingText).toBe(correctText);
expect(noTrackingText.trim()).toBe(correctText);
done();
});
});
......@@ -234,12 +236,10 @@ describe('Issuable Time Tracker', () => {
const closeHelpButton = () => vm.$el.querySelector('.close-help-button');
const helpPane = () => vm.$el.querySelector('.time-tracking-help-state');
beforeEach(done => {
beforeEach(() => {
initTimeTrackingComponent({ timeEstimate: 0, timeSpent: 0 });
Vue.nextTick()
.then(done)
.catch(done.fail);
return vm.$nextTick();
});
it('should not show the "Help" pane by default', () => {
......@@ -247,16 +247,17 @@ describe('Issuable Time Tracker', () => {
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();
Vue.nextTick()
.then(() => {
expect(vm.showHelpState).toBe(true);
expect(helpPane()).toBeVisible();
})
.then(done)
.catch(done.fail);
return vm.$nextTick().then(() => {
expect(vm.showHelpState).toBe(true);
// let animations run
jest.advanceTimersByTime(500);
expect(helpPane()).toBeVisible();
});
});
it('should not show the "Help" pane when help button is clicked and then closed', done => {
......
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';
describe('LockIssueSidebar', () => {
......@@ -61,7 +61,7 @@ describe('LockIssueSidebar', () => {
});
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');
expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
......@@ -77,7 +77,7 @@ describe('LockIssueSidebar', () => {
expect(vm1.isLockDialogOpen).toBe(true);
setTimeout(() => {
setImmediate(() => {
expect(vm1.$el.innerHTML.includes('Unlock this issue?')).toBe(true);
done();
......
......@@ -7,15 +7,16 @@ import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue';
import Mock from './mock_data';
describe('SidebarMoveIssue', function() {
describe('SidebarMoveIssue', () => {
let mock;
const test = {};
beforeEach(() => {
mock = new MockAdapter(axios);
const mockData = Mock.responseMap.GET['/autocomplete/projects?project_id=15'];
mock.onGet('/autocomplete/projects?project_id=15').reply(200, mockData);
this.mediator = new SidebarMediator(Mock.mediator);
this.$content = $(`
test.mediator = new SidebarMediator(Mock.mediator);
test.$content = $(`
<div class="dropdown">
<div class="js-toggle"></div>
<div class="dropdown-menu">
......@@ -24,15 +25,15 @@ describe('SidebarMoveIssue', function() {
<div class="js-confirm-button"></div>
</div>
`);
this.$toggleButton = this.$content.find('.js-toggle');
this.$confirmButton = this.$content.find('.js-confirm-button');
test.$toggleButton = test.$content.find('.js-toggle');
test.$confirmButton = test.$content.find('.js-confirm-button');
this.sidebarMoveIssue = new SidebarMoveIssue(
this.mediator,
this.$toggleButton,
this.$confirmButton,
test.sidebarMoveIssue = new SidebarMoveIssue(
test.mediator,
test.$toggleButton,
test.$confirmButton,
);
this.sidebarMoveIssue.init();
test.sidebarMoveIssue.init();
});
afterEach(() => {
......@@ -40,46 +41,46 @@ describe('SidebarMoveIssue', function() {
SidebarStore.singleton = null;
SidebarMediator.singleton = null;
this.sidebarMoveIssue.destroy();
test.sidebarMoveIssue.destroy();
mock.restore();
});
describe('init', () => {
it('should initialize the dropdown and listeners', () => {
spyOn(this.sidebarMoveIssue, 'initDropdown');
spyOn(this.sidebarMoveIssue, 'addEventListeners');
jest.spyOn(test.sidebarMoveIssue, 'initDropdown').mockImplementation(() => {});
jest.spyOn(test.sidebarMoveIssue, 'addEventListeners').mockImplementation(() => {});
this.sidebarMoveIssue.init();
test.sidebarMoveIssue.init();
expect(this.sidebarMoveIssue.initDropdown).toHaveBeenCalled();
expect(this.sidebarMoveIssue.addEventListeners).toHaveBeenCalled();
expect(test.sidebarMoveIssue.initDropdown).toHaveBeenCalled();
expect(test.sidebarMoveIssue.addEventListeners).toHaveBeenCalled();
});
});
describe('destroy', () => {
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', () => {
it('should initialize the gl_dropdown', () => {
spyOn($.fn, 'glDropdown');
jest.spyOn($.fn, 'glDropdown').mockImplementation(() => {});
this.sidebarMoveIssue.initDropdown();
test.sidebarMoveIssue.initDropdown();
expect($.fn.glDropdown).toHaveBeenCalled();
});
it('escapes html from project name', done => {
this.$toggleButton.dropdown('toggle');
test.$toggleButton.dropdown('toggle');
setTimeout(() => {
expect(this.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual(
setImmediate(() => {
expect(test.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual(
'&lt;img src=x onerror=alert(document.domain)&gt; foo / bar',
);
done();
......@@ -89,78 +90,78 @@ describe('SidebarMoveIssue', function() {
describe('onConfirmClicked', () => {
it('should move the issue with valid project ID', () => {
spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.resolve());
this.mediator.setMoveToProjectId(7);
jest.spyOn(test.mediator, 'moveIssue').mockReturnValue(Promise.resolve());
test.mediator.setMoveToProjectId(7);
this.sidebarMoveIssue.onConfirmClicked();
test.sidebarMoveIssue.onConfirmClicked();
expect(this.mediator.moveIssue).toHaveBeenCalled();
expect(this.$confirmButton.prop('disabled')).toBeTruthy();
expect(this.$confirmButton.hasClass('is-loading')).toBe(true);
expect(test.mediator.moveIssue).toHaveBeenCalled();
expect(test.$confirmButton.prop('disabled')).toBeTruthy();
expect(test.$confirmButton.hasClass('is-loading')).toBe(true);
});
it('should remove loading state from confirm button on failure', done => {
spyOn(window, 'Flash');
spyOn(this.mediator, 'moveIssue').and.returnValue(Promise.reject());
this.mediator.setMoveToProjectId(7);
jest.spyOn(window, 'Flash').mockImplementation(() => {});
jest.spyOn(test.mediator, 'moveIssue').mockReturnValue(Promise.reject());
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
setTimeout(() => {
setImmediate(() => {
expect(window.Flash).toHaveBeenCalled();
expect(this.$confirmButton.prop('disabled')).toBeFalsy();
expect(this.$confirmButton.hasClass('is-loading')).toBe(false);
expect(test.$confirmButton.prop('disabled')).toBeFalsy();
expect(test.$confirmButton.hasClass('is-loading')).toBe(false);
done();
});
});
it('should not move the issue with id=0', () => {
spyOn(this.mediator, 'moveIssue');
this.mediator.setMoveToProjectId(0);
jest.spyOn(test.mediator, 'moveIssue').mockImplementation(() => {});
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 => {
spyOn(this.mediator, 'setMoveToProjectId');
jest.spyOn(test.mediator, 'setMoveToProjectId').mockImplementation(() => {});
// Open the dropdown
this.$toggleButton.dropdown('toggle');
test.$toggleButton.dropdown('toggle');
// Wait for the autocomplete request to finish
setTimeout(() => {
this.$content
setImmediate(() => {
test.$content
.find('.js-move-issue-dropdown-item')
.eq(0)
.trigger('click');
expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(0);
expect(this.$confirmButton.prop('disabled')).toBeTruthy();
expect(test.mediator.setMoveToProjectId).toHaveBeenCalledWith(0);
expect(test.$confirmButton.prop('disabled')).toBeTruthy();
done();
}, 0);
});
});
it('should set moveToProjectId on dropdown item click', done => {
spyOn(this.mediator, 'setMoveToProjectId');
jest.spyOn(test.mediator, 'setMoveToProjectId').mockImplementation(() => {});
// Open the dropdown
this.$toggleButton.dropdown('toggle');
test.$toggleButton.dropdown('toggle');
// Wait for the autocomplete request to finish
setTimeout(() => {
this.$content
setImmediate(() => {
test.$content
.find('.js-move-issue-dropdown-item')
.eq(1)
.trigger('click');
expect(this.mediator.setMoveToProjectId).toHaveBeenCalledWith(20);
expect(this.$confirmButton.attr('disabled')).toBe(undefined);
expect(test.mediator.setMoveToProjectId).toHaveBeenCalledWith(20);
expect(test.$confirmButton.attr('disabled')).toBe(undefined);
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