Commit ca34500c authored by Kushal Pandya's avatar Kushal Pandya

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

Migrate javascripts/* specs to Jest

Closes #34861

See merge request gitlab-org/gitlab!32586
parents 510a32e0 ac493c39
...@@ -4,7 +4,7 @@ import $ from 'jquery'; ...@@ -4,7 +4,7 @@ import $ from 'jquery';
import { escape } from 'lodash'; import { escape } from 'lodash';
import fuzzaldrinPlus from 'fuzzaldrin-plus'; import fuzzaldrinPlus from 'fuzzaldrin-plus';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
import { visitUrl } from './lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import { isObject } from './lib/utils/type_utility'; import { isObject } from './lib/utils/type_utility';
import renderItem from './gl_dropdown/render'; import renderItem from './gl_dropdown/render';
......
import $ from 'jquery'; import $ from 'jquery';
import { getParameterByName } from '~/lib/utils/common_utils'; import { getParameterByName } from '~/lib/utils/common_utils';
import axios from './lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { removeParams } from './lib/utils/url_utility'; import { removeParams } from '~/lib/utils/url_utility';
const ENDLESS_SCROLL_BOTTOM_PX = 400; const ENDLESS_SCROLL_BOTTOM_PX = 400;
const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000; const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000;
......
...@@ -28,12 +28,20 @@ const useLocalStorage = fn => { ...@@ -28,12 +28,20 @@ const useLocalStorage = fn => {
/** /**
* Create an object with the localStorage interface but `jest.fn()` implementations. * Create an object with the localStorage interface but `jest.fn()` implementations.
*/ */
export const createLocalStorageSpy = () => ({ export const createLocalStorageSpy = () => {
clear: jest.fn(), let storage = {};
getItem: jest.fn(),
setItem: jest.fn(), return {
removeItem: jest.fn(), clear: jest.fn(() => {
}); storage = {};
}),
getItem: jest.fn(key => storage[key]),
setItem: jest.fn((key, value) => {
storage[key] = value;
}),
removeItem: jest.fn(key => delete storage[key]),
};
};
/** /**
* Before each test, overwrite `window.localStorage` with a spy implementation. * Before each test, overwrite `window.localStorage` with a spy implementation.
......
import { useLocalStorageSpy } from './local_storage_helper';
useLocalStorageSpy();
describe('localStorage helper', () => {
it('mocks localStorage but works exactly like original localStorage', () => {
localStorage.setItem('test', 'testing');
localStorage.setItem('test2', 'testing');
expect(localStorage.getItem('test')).toBe('testing');
localStorage.removeItem('test', 'testing');
expect(localStorage.getItem('test')).toBeUndefined();
expect(localStorage.getItem('test2')).toBe('testing');
localStorage.clear();
expect(localStorage.getItem('test2')).toBeUndefined();
});
});
...@@ -16,9 +16,8 @@ describe('Importer Status', () => { ...@@ -16,9 +16,8 @@ describe('Importer Status', () => {
describe('addToImport', () => { describe('addToImport', () => {
const importUrl = '/import_url'; const importUrl = '/import_url';
const fixtures = `
beforeEach(() => { <table>
setFixtures(`
<tr id="repo_123"> <tr id="repo_123">
<td class="import-target"></td> <td class="import-target"></td>
<td class="import-actions job-status"> <td class="import-actions job-status">
...@@ -26,9 +25,13 @@ describe('Importer Status', () => { ...@@ -26,9 +25,13 @@ describe('Importer Status', () => {
</button> </button>
</td> </td>
</tr> </tr>
`); </table>
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {}); `;
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
beforeEach(() => {
setFixtures(fixtures);
jest.spyOn(ImporterStatus.prototype, 'initStatusPage').mockImplementation(() => {});
jest.spyOn(ImporterStatus.prototype, 'setAutoUpdate').mockImplementation(() => {});
instance = new ImporterStatus({ instance = new ImporterStatus({
jobsUrl: '', jobsUrl: '',
importUrl, importUrl,
...@@ -53,7 +56,7 @@ describe('Importer Status', () => { ...@@ -53,7 +56,7 @@ describe('Importer Status', () => {
}); });
it('shows error message after failed POST request', done => { it('shows error message after failed POST request', done => {
appendSetFixtures('<div class="flash-container"></div>'); setFixtures(`${fixtures}<div class="flash-container"></div>`);
mock.onPost(importUrl).reply(422, { mock.onPost(importUrl).reply(422, {
errors: 'You forgot your lunch', errors: 'You forgot your lunch',
...@@ -89,8 +92,8 @@ describe('Importer Status', () => { ...@@ -89,8 +92,8 @@ describe('Importer Status', () => {
document.body.appendChild(div); document.body.appendChild(div);
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {}); jest.spyOn(ImporterStatus.prototype, 'initStatusPage').mockImplementation(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {}); jest.spyOn(ImporterStatus.prototype, 'setAutoUpdate').mockImplementation(() => {});
instance = new ImporterStatus({ instance = new ImporterStatus({
jobsUrl, jobsUrl,
}); });
......
...@@ -4,24 +4,26 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -4,24 +4,26 @@ import axios from '~/lib/utils/axios_utils';
import MergeRequest from '~/merge_request'; import MergeRequest from '~/merge_request';
import CloseReopenReportToggle from '~/close_reopen_report_toggle'; import CloseReopenReportToggle from '~/close_reopen_report_toggle';
import IssuablesHelper from '~/helpers/issuables_helper'; import IssuablesHelper from '~/helpers/issuables_helper';
import { TEST_HOST } from 'spec/test_constants';
describe('MergeRequest', function() { describe('MergeRequest', () => {
describe('task lists', function() { const test = {};
describe('task lists', () => {
let mock; let mock;
preloadFixtures('merge_requests/merge_request_with_task_list.html'); preloadFixtures('merge_requests/merge_request_with_task_list.html');
beforeEach(function() { beforeEach(() => {
loadFixtures('merge_requests/merge_request_with_task_list.html'); loadFixtures('merge_requests/merge_request_with_task_list.html');
spyOn(axios, 'patch').and.callThrough(); jest.spyOn(axios, 'patch');
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock mock
.onPatch(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`) .onPatch(`${TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`)
.reply(200, {}); .reply(200, {});
this.merge = new MergeRequest(); test.merge = new MergeRequest();
return this.merge; return test.merge;
}); });
afterEach(() => { afterEach(() => {
...@@ -29,14 +31,14 @@ describe('MergeRequest', function() { ...@@ -29,14 +31,14 @@ describe('MergeRequest', function() {
}); });
it('modifies the Markdown field', done => { it('modifies the Markdown field', done => {
spyOn($, 'ajax').and.stub(); jest.spyOn($, 'ajax').mockImplementation();
const changeEvent = document.createEvent('HTMLEvents'); const changeEvent = document.createEvent('HTMLEvents');
changeEvent.initEvent('change', true, true); changeEvent.initEvent('change', true, true);
$('input[type=checkbox]') $('input[type=checkbox]')
.first() .first()
.attr('checked', true)[0] .attr('checked', true)[0]
.dispatchEvent(changeEvent); .dispatchEvent(changeEvent);
setTimeout(() => { setImmediate(() => {
expect($('.js-task-list-field').val()).toBe( expect($('.js-task-list-field').val()).toBe(
'- [x] Task List Item\n- [ ] \n- [ ] Task List Item 2\n', '- [x] Task List Item\n- [ ] \n- [ ] Task List Item 2\n',
); );
...@@ -46,14 +48,14 @@ describe('MergeRequest', function() { ...@@ -46,14 +48,14 @@ describe('MergeRequest', function() {
it('ensure that task with only spaces does not get checked incorrectly', done => { it('ensure that task with only spaces does not get checked incorrectly', done => {
// fixed in 'deckar01-task_list', '2.2.1' gem // fixed in 'deckar01-task_list', '2.2.1' gem
spyOn($, 'ajax').and.stub(); jest.spyOn($, 'ajax').mockImplementation();
const changeEvent = document.createEvent('HTMLEvents'); const changeEvent = document.createEvent('HTMLEvents');
changeEvent.initEvent('change', true, true); changeEvent.initEvent('change', true, true);
$('input[type=checkbox]') $('input[type=checkbox]')
.last() .last()
.attr('checked', true)[0] .attr('checked', true)[0]
.dispatchEvent(changeEvent); .dispatchEvent(changeEvent);
setTimeout(() => { setImmediate(() => {
expect($('.js-task-list-field').val()).toBe( expect($('.js-task-list-field').val()).toBe(
'- [ ] Task List Item\n- [ ] \n- [x] Task List Item 2\n', '- [ ] Task List Item\n- [ ] \n- [x] Task List Item 2\n',
); );
...@@ -73,9 +75,9 @@ describe('MergeRequest', function() { ...@@ -73,9 +75,9 @@ describe('MergeRequest', function() {
detail: { lineNumber, lineSource, index, checked }, detail: { lineNumber, lineSource, index, checked },
}); });
setTimeout(() => { setImmediate(() => {
expect(axios.patch).toHaveBeenCalledWith( expect(axios.patch).toHaveBeenCalledWith(
`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`, `${TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`,
{ {
merge_request: { merge_request: {
description: '- [ ] Task List Item\n- [ ] \n- [ ] Task List Item 2\n', description: '- [ ] Task List Item\n- [ ] \n- [ ] Task List Item 2\n',
...@@ -89,13 +91,9 @@ describe('MergeRequest', function() { ...@@ -89,13 +91,9 @@ describe('MergeRequest', function() {
}); });
}); });
// https://gitlab.com/gitlab-org/gitlab/issues/34861 it('shows an error notification when tasklist update failed', done => {
// eslint-disable-next-line jasmine/no-disabled-tests
xit('shows an error notification when tasklist update failed', done => {
mock mock
.onPatch( .onPatch(`${TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`)
`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/-/merge_requests/1.json`,
)
.reply(409, {}); .reply(409, {});
$('.js-task-list-field').trigger({ $('.js-task-list-field').trigger({
...@@ -103,7 +101,7 @@ describe('MergeRequest', function() { ...@@ -103,7 +101,7 @@ describe('MergeRequest', function() {
detail: { lineNumber, lineSource, index, checked }, detail: { lineNumber, lineSource, index, checked },
}); });
setTimeout(() => { setImmediate(() => {
expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe( expect(document.querySelector('.flash-container .flash-text').innerText.trim()).toBe(
'Someone edited this merge request at the same time you did. Please refresh the page to see changes.', 'Someone edited this merge request at the same time you did. Please refresh the page to see changes.',
); );
...@@ -116,11 +114,11 @@ describe('MergeRequest', function() { ...@@ -116,11 +114,11 @@ describe('MergeRequest', function() {
describe('class constructor', () => { describe('class constructor', () => {
beforeEach(() => { beforeEach(() => {
spyOn($, 'ajax').and.stub(); jest.spyOn($, 'ajax').mockImplementation();
}); });
it('calls .initCloseReopenReport', () => { it('calls .initCloseReopenReport', () => {
spyOn(IssuablesHelper, 'initCloseReopenReport'); jest.spyOn(IssuablesHelper, 'initCloseReopenReport').mockImplementation(() => {});
new MergeRequest(); // eslint-disable-line no-new new MergeRequest(); // eslint-disable-line no-new
...@@ -128,14 +126,20 @@ describe('MergeRequest', function() { ...@@ -128,14 +126,20 @@ describe('MergeRequest', function() {
}); });
it('calls .initDroplab', () => { it('calls .initDroplab', () => {
const container = jasmine.createSpyObj('container', ['querySelector']); const container = {
querySelector: jest.fn().mockName('container.querySelector'),
};
const dropdownTrigger = {}; const dropdownTrigger = {};
const dropdownList = {}; const dropdownList = {};
const button = {}; const button = {};
spyOn(CloseReopenReportToggle.prototype, 'initDroplab'); jest.spyOn(CloseReopenReportToggle.prototype, 'initDroplab').mockImplementation(() => {});
spyOn(document, 'querySelector').and.returnValue(container); jest.spyOn(document, 'querySelector').mockReturnValue(container);
container.querySelector.and.returnValues(dropdownTrigger, dropdownList, button);
container.querySelector
.mockReturnValueOnce(dropdownTrigger)
.mockReturnValueOnce(dropdownList)
.mockReturnValueOnce(button);
new MergeRequest(); // eslint-disable-line no-new new MergeRequest(); // eslint-disable-line no-new
...@@ -151,15 +155,15 @@ describe('MergeRequest', function() { ...@@ -151,15 +155,15 @@ describe('MergeRequest', function() {
describe('merge request of another user', () => { describe('merge request of another user', () => {
beforeEach(() => { beforeEach(() => {
loadFixtures('merge_requests/merge_request_with_task_list.html'); loadFixtures('merge_requests/merge_request_with_task_list.html');
this.el = document.querySelector('.js-issuable-actions'); test.el = document.querySelector('.js-issuable-actions');
new MergeRequest(); // eslint-disable-line no-new new MergeRequest(); // eslint-disable-line no-new
MergeRequest.hideCloseButton(); MergeRequest.hideCloseButton();
}); });
it('hides the dropdown close item and selects the next item', () => { it('hides the dropdown close item and selects the next item', () => {
const closeItem = this.el.querySelector('li.close-item'); const closeItem = test.el.querySelector('li.close-item');
const smallCloseItem = this.el.querySelector('.js-close-item'); const smallCloseItem = test.el.querySelector('.js-close-item');
const reportItem = this.el.querySelector('li.report-item'); const reportItem = test.el.querySelector('li.report-item');
expect(closeItem).toHaveClass('hidden'); expect(closeItem).toHaveClass('hidden');
expect(smallCloseItem).toHaveClass('hidden'); expect(smallCloseItem).toHaveClass('hidden');
...@@ -171,13 +175,13 @@ describe('MergeRequest', function() { ...@@ -171,13 +175,13 @@ describe('MergeRequest', function() {
describe('merge request of current_user', () => { describe('merge request of current_user', () => {
beforeEach(() => { beforeEach(() => {
loadFixtures('merge_requests/merge_request_of_current_user.html'); loadFixtures('merge_requests/merge_request_of_current_user.html');
this.el = document.querySelector('.js-issuable-actions'); test.el = document.querySelector('.js-issuable-actions');
MergeRequest.hideCloseButton(); MergeRequest.hideCloseButton();
}); });
it('hides the close button', () => { it('hides the close button', () => {
const closeButton = this.el.querySelector('.btn-close'); const closeButton = test.el.querySelector('.btn-close');
const smallCloseItem = this.el.querySelector('.js-close-item'); const smallCloseItem = test.el.querySelector('.js-close-item');
expect(closeButton).toHaveClass('hidden'); expect(closeButton).toHaveClass('hidden');
expect(smallCloseItem).toHaveClass('hidden'); expect(smallCloseItem).toHaveClass('hidden');
......
...@@ -2,7 +2,7 @@ import $ from 'jquery'; ...@@ -2,7 +2,7 @@ import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import timeoutPromise from './helpers/set_timeout_promise_helper'; import waitForPromises from './helpers/wait_for_promises';
describe('Mini Pipeline Graph Dropdown', () => { describe('Mini Pipeline Graph Dropdown', () => {
preloadFixtures('static/mini_dropdown_graph.html'); preloadFixtures('static/mini_dropdown_graph.html');
...@@ -39,9 +39,9 @@ describe('Mini Pipeline Graph Dropdown', () => { ...@@ -39,9 +39,9 @@ describe('Mini Pipeline Graph Dropdown', () => {
}); });
it('should call getBuildsList', () => { it('should call getBuildsList', () => {
const getBuildsListSpy = spyOn(MiniPipelineGraph.prototype, 'getBuildsList').and.callFake( const getBuildsListSpy = jest
function() {}, .spyOn(MiniPipelineGraph.prototype, 'getBuildsList')
); .mockImplementation(() => {});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents(); new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
...@@ -51,7 +51,7 @@ describe('Mini Pipeline Graph Dropdown', () => { ...@@ -51,7 +51,7 @@ describe('Mini Pipeline Graph Dropdown', () => {
}); });
it('should make a request to the endpoint provided in the html', () => { it('should make a request to the endpoint provided in the html', () => {
const ajaxSpy = spyOn(axios, 'get').and.callThrough(); const ajaxSpy = jest.spyOn(axios, 'get');
mock.onGet('foobar').reply(200, { mock.onGet('foobar').reply(200, {
html: '', html: '',
...@@ -61,7 +61,7 @@ describe('Mini Pipeline Graph Dropdown', () => { ...@@ -61,7 +61,7 @@ describe('Mini Pipeline Graph Dropdown', () => {
document.querySelector('.js-builds-dropdown-button').click(); document.querySelector('.js-builds-dropdown-button').click();
expect(ajaxSpy.calls.allArgs()[0][0]).toEqual('foobar'); expect(ajaxSpy.mock.calls[0][0]).toEqual('foobar');
}); });
it('should not close when user uses cmd/ctrl + click', done => { it('should not close when user uses cmd/ctrl + click', done => {
...@@ -78,11 +78,11 @@ describe('Mini Pipeline Graph Dropdown', () => { ...@@ -78,11 +78,11 @@ describe('Mini Pipeline Graph Dropdown', () => {
document.querySelector('.js-builds-dropdown-button').click(); document.querySelector('.js-builds-dropdown-button').click();
timeoutPromise() waitForPromises()
.then(() => { .then(() => {
document.querySelector('a.mini-pipeline-graph-dropdown-item').click(); document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
}) })
.then(timeoutPromise) .then(waitForPromises)
.then(() => { .then(() => {
expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true); expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
}) })
...@@ -97,7 +97,7 @@ describe('Mini Pipeline Graph Dropdown', () => { ...@@ -97,7 +97,7 @@ describe('Mini Pipeline Graph Dropdown', () => {
document.querySelector('.js-builds-dropdown-button').click(); document.querySelector('.js-builds-dropdown-button').click();
setTimeout(() => { setImmediate(() => {
expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false); expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
done(); done();
}); });
......
...@@ -2,6 +2,11 @@ import $ from 'jquery'; ...@@ -2,6 +2,11 @@ import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import Pager from '~/pager'; import Pager from '~/pager';
import { removeParams } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
removeParams: jest.fn().mockName('removeParams'),
}));
describe('pager', () => { describe('pager', () => {
let axiosMock; let axiosMock;
...@@ -19,7 +24,7 @@ describe('pager', () => { ...@@ -19,7 +24,7 @@ describe('pager', () => {
beforeEach(() => { beforeEach(() => {
setFixtures('<div class="content_list"></div><div class="loading"></div>'); setFixtures('<div class="content_list"></div><div class="loading"></div>');
spyOn($.fn, 'endlessScroll').and.stub(); jest.spyOn($.fn, 'endlessScroll').mockImplementation();
}); });
afterEach(() => { afterEach(() => {
...@@ -36,7 +41,7 @@ describe('pager', () => { ...@@ -36,7 +41,7 @@ describe('pager', () => {
it('should use current url if data-href attribute not provided', () => { it('should use current url if data-href attribute not provided', () => {
const href = `${gl.TEST_HOST}/some_list`; const href = `${gl.TEST_HOST}/some_list`;
spyOnDependency(Pager, 'removeParams').and.returnValue(href); removeParams.mockReturnValue(href);
Pager.init(); Pager.init();
expect(Pager.url).toBe(href); expect(Pager.url).toBe(href);
...@@ -52,7 +57,7 @@ describe('pager', () => { ...@@ -52,7 +57,7 @@ describe('pager', () => {
it('keeps extra query parameters from url', () => { it('keeps extra query parameters from url', () => {
window.history.replaceState({}, null, '?filter=test&offset=100'); window.history.replaceState({}, null, '?filter=test&offset=100');
const href = `${gl.TEST_HOST}/some_list?filter=test`; const href = `${gl.TEST_HOST}/some_list?filter=test`;
const removeParams = spyOnDependency(Pager, 'removeParams').and.returnValue(href); removeParams.mockReturnValue(href);
Pager.init(); Pager.init();
expect(removeParams).toHaveBeenCalledWith(['limit', 'offset']); expect(removeParams).toHaveBeenCalledWith(['limit', 'offset']);
...@@ -78,7 +83,7 @@ describe('pager', () => { ...@@ -78,7 +83,7 @@ describe('pager', () => {
setFixtures( setFixtures(
'<div class="content_list" data-href="/some_list"></div><div class="loading"></div>', '<div class="content_list" data-href="/some_list"></div><div class="loading"></div>',
); );
spyOn(axios, 'get').and.callThrough(); jest.spyOn(axios, 'get');
Pager.init(); Pager.init();
}); });
...@@ -86,10 +91,10 @@ describe('pager', () => { ...@@ -86,10 +91,10 @@ describe('pager', () => {
it('shows loader while loading next page', done => { it('shows loader while loading next page', done => {
mockSuccess(); mockSuccess();
spyOn(Pager.loading, 'show'); jest.spyOn(Pager.loading, 'show').mockImplementation(() => {});
Pager.getOld(); Pager.getOld();
setTimeout(() => { setImmediate(() => {
expect(Pager.loading.show).toHaveBeenCalled(); expect(Pager.loading.show).toHaveBeenCalled();
done(); done();
...@@ -99,10 +104,10 @@ describe('pager', () => { ...@@ -99,10 +104,10 @@ describe('pager', () => {
it('hides loader on success', done => { it('hides loader on success', done => {
mockSuccess(); mockSuccess();
spyOn(Pager.loading, 'hide'); jest.spyOn(Pager.loading, 'hide').mockImplementation(() => {});
Pager.getOld(); Pager.getOld();
setTimeout(() => { setImmediate(() => {
expect(Pager.loading.hide).toHaveBeenCalled(); expect(Pager.loading.hide).toHaveBeenCalled();
done(); done();
...@@ -112,10 +117,10 @@ describe('pager', () => { ...@@ -112,10 +117,10 @@ describe('pager', () => {
it('hides loader on error', done => { it('hides loader on error', done => {
mockError(); mockError();
spyOn(Pager.loading, 'hide'); jest.spyOn(Pager.loading, 'hide').mockImplementation(() => {});
Pager.getOld(); Pager.getOld();
setTimeout(() => { setImmediate(() => {
expect(Pager.loading.hide).toHaveBeenCalled(); expect(Pager.loading.hide).toHaveBeenCalled();
done(); done();
...@@ -127,8 +132,8 @@ describe('pager', () => { ...@@ -127,8 +132,8 @@ describe('pager', () => {
Pager.limit = 20; Pager.limit = 20;
Pager.getOld(); Pager.getOld();
setTimeout(() => { setImmediate(() => {
const [url, params] = axios.get.calls.argsFor(0); const [url, params] = axios.get.mock.calls[0];
expect(params).toEqual({ expect(params).toEqual({
params: { params: {
...@@ -148,10 +153,10 @@ describe('pager', () => { ...@@ -148,10 +153,10 @@ describe('pager', () => {
Pager.limit = 20; Pager.limit = 20;
mockSuccess(1); mockSuccess(1);
spyOn(Pager.loading, 'hide'); jest.spyOn(Pager.loading, 'hide').mockImplementation(() => {});
Pager.getOld(); Pager.getOld();
setTimeout(() => { setImmediate(() => {
expect(Pager.loading.hide).toHaveBeenCalled(); expect(Pager.loading.hide).toHaveBeenCalled();
expect(Pager.disable).toBe(true); expect(Pager.disable).toBe(true);
......
...@@ -5,6 +5,11 @@ import '~/lib/utils/common_utils'; ...@@ -5,6 +5,11 @@ import '~/lib/utils/common_utils';
import '~/gl_dropdown'; import '~/gl_dropdown';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { addDelimiter } from '~/lib/utils/text_utility'; import { addDelimiter } from '~/lib/utils/text_utility';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrl'),
}));
const TEST_COUNT_BIG = 2000; const TEST_COUNT_BIG = 2000;
const TEST_DONE_COUNT_BIG = 7300; const TEST_DONE_COUNT_BIG = 7300;
...@@ -30,7 +35,7 @@ describe('Todos', () => { ...@@ -30,7 +35,7 @@ describe('Todos', () => {
it('opens the todo url', done => { it('opens the todo url', done => {
const todoLink = todoItem.dataset.url; const todoLink = todoItem.dataset.url;
spyOnDependency(Todos, 'visitUrl').and.callFake(url => { visitUrl.mockImplementation(url => {
expect(url).toEqual(todoLink); expect(url).toEqual(todoLink);
done(); done();
}); });
...@@ -39,14 +44,12 @@ describe('Todos', () => { ...@@ -39,14 +44,12 @@ describe('Todos', () => {
}); });
describe('meta click', () => { describe('meta click', () => {
let visitUrlSpy;
let windowOpenSpy; let windowOpenSpy;
let metakeyEvent; let metakeyEvent;
beforeEach(() => { beforeEach(() => {
metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true }); metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
visitUrlSpy = spyOnDependency(Todos, 'visitUrl').and.callFake(() => {}); windowOpenSpy = jest.spyOn(window, 'open').mockImplementation(() => {});
windowOpenSpy = spyOn(window, 'open').and.callFake(() => {});
}); });
it('opens the todo url in another tab', () => { it('opens the todo url in another tab', () => {
...@@ -54,7 +57,7 @@ describe('Todos', () => { ...@@ -54,7 +57,7 @@ describe('Todos', () => {
$('.todos-list .todo').trigger(metakeyEvent); $('.todos-list .todo').trigger(metakeyEvent);
expect(visitUrlSpy).not.toHaveBeenCalled(); expect(visitUrl).not.toHaveBeenCalled();
expect(windowOpenSpy).toHaveBeenCalledWith(todoLink, '_blank'); expect(windowOpenSpy).toHaveBeenCalledWith(todoLink, '_blank');
}); });
...@@ -62,7 +65,7 @@ describe('Todos', () => { ...@@ -62,7 +65,7 @@ describe('Todos', () => {
$('.todos-list a').on('click', e => e.preventDefault()); $('.todos-list a').on('click', e => e.preventDefault());
$('.todos-list img').trigger(metakeyEvent); $('.todos-list img').trigger(metakeyEvent);
expect(visitUrlSpy).not.toHaveBeenCalled(); expect(visitUrl).not.toHaveBeenCalled();
expect(windowOpenSpy).not.toHaveBeenCalled(); expect(windowOpenSpy).not.toHaveBeenCalled();
}); });
}); });
...@@ -78,7 +81,7 @@ describe('Todos', () => { ...@@ -78,7 +81,7 @@ describe('Todos', () => {
mock mock
.onDelete(path) .onDelete(path)
.replyOnce(200, { count: TEST_COUNT_BIG, done_count: TEST_DONE_COUNT_BIG }); .replyOnce(200, { count: TEST_COUNT_BIG, done_count: TEST_DONE_COUNT_BIG });
onToggleSpy = jasmine.createSpy('onToggle'); onToggleSpy = jest.fn();
$(document).on('todo:toggle', onToggleSpy); $(document).on('todo:toggle', onToggleSpy);
// Act // Act
...@@ -89,7 +92,7 @@ describe('Todos', () => { ...@@ -89,7 +92,7 @@ describe('Todos', () => {
}); });
it('dispatches todo:toggle', () => { it('dispatches todo:toggle', () => {
expect(onToggleSpy).toHaveBeenCalledWith(jasmine.anything(), TEST_COUNT_BIG); expect(onToggleSpy).toHaveBeenCalledWith(expect.anything(), TEST_COUNT_BIG);
}); });
it('updates pending text', () => { it('updates pending text', () => {
......
...@@ -2,6 +2,9 @@ import AccessorUtilities from '~/lib/utils/accessor'; ...@@ -2,6 +2,9 @@ import AccessorUtilities from '~/lib/utils/accessor';
import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
import trackData from '~/pages/sessions/new/index'; import trackData from '~/pages/sessions/new/index';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
useLocalStorageSpy();
describe('SigninTabsMemoizer', () => { describe('SigninTabsMemoizer', () => {
const fixtureTemplate = 'static/signin_tabs.html'; const fixtureTemplate = 'static/signin_tabs.html';
...@@ -22,7 +25,7 @@ describe('SigninTabsMemoizer', () => { ...@@ -22,7 +25,7 @@ describe('SigninTabsMemoizer', () => {
beforeEach(() => { beforeEach(() => {
loadFixtures(fixtureTemplate); loadFixtures(fixtureTemplate);
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true); jest.spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').mockReturnValue(true);
}); });
it('does nothing if no tab was previously selected', () => { it('does nothing if no tab was previously selected', () => {
...@@ -38,8 +41,8 @@ describe('SigninTabsMemoizer', () => { ...@@ -38,8 +41,8 @@ describe('SigninTabsMemoizer', () => {
const fakeTab = { const fakeTab = {
click: () => {}, click: () => {},
}; };
spyOn(document, 'querySelector').and.returnValue(fakeTab); jest.spyOn(document, 'querySelector').mockReturnValue(fakeTab);
spyOn(fakeTab, 'click'); jest.spyOn(fakeTab, 'click').mockImplementation(() => {});
memo.bootstrap(); memo.bootstrap();
...@@ -51,17 +54,18 @@ describe('SigninTabsMemoizer', () => { ...@@ -51,17 +54,18 @@ describe('SigninTabsMemoizer', () => {
it('clicks the first tab if value in local storage is bad', () => { it('clicks the first tab if value in local storage is bad', () => {
createMemoizer().saveData('#bogus'); createMemoizer().saveData('#bogus');
const fakeTab = { const fakeTab = {
click: () => {}, click: jest.fn().mockName('fakeTab_click'),
}; };
spyOn(document, 'querySelector').and.callFake(selector => jest
selector === `${tabSelector} a[href="#bogus"]` ? null : fakeTab, .spyOn(document, 'querySelector')
); .mockImplementation(selector =>
spyOn(fakeTab, 'click'); selector === `${tabSelector} a[href="#bogus"]` ? null : fakeTab,
);
memo.bootstrap(); memo.bootstrap();
// verify that triggers click on stored selector and fallback // verify that triggers click on stored selector and fallback
expect(document.querySelector.calls.allArgs()).toEqual([ expect(document.querySelector.mock.calls).toEqual([
['ul.new-session-tabs a[href="#bogus"]'], ['ul.new-session-tabs a[href="#bogus"]'],
['ul.new-session-tabs a'], ['ul.new-session-tabs a'],
]); ]);
...@@ -97,7 +101,7 @@ describe('SigninTabsMemoizer', () => { ...@@ -97,7 +101,7 @@ describe('SigninTabsMemoizer', () => {
describe('trackData', () => { describe('trackData', () => {
beforeEach(() => { beforeEach(() => {
spyOn(Tracking, 'event'); jest.spyOn(Tracking, 'event').mockImplementation(() => {});
}); });
describe('with tracking data', () => { describe('with tracking data', () => {
...@@ -144,12 +148,10 @@ describe('SigninTabsMemoizer', () => { ...@@ -144,12 +148,10 @@ describe('SigninTabsMemoizer', () => {
memo = { memo = {
currentTabKey, currentTabKey,
}; };
spyOn(localStorage, 'setItem');
}); });
describe('if .isLocalStorageAvailable is `false`', () => { describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(function() { beforeEach(() => {
memo.isLocalStorageAvailable = false; memo.isLocalStorageAvailable = false;
SigninTabsMemoizer.prototype.saveData.call(memo); SigninTabsMemoizer.prototype.saveData.call(memo);
...@@ -163,7 +165,7 @@ describe('SigninTabsMemoizer', () => { ...@@ -163,7 +165,7 @@ describe('SigninTabsMemoizer', () => {
describe('if .isLocalStorageAvailable is `true`', () => { describe('if .isLocalStorageAvailable is `true`', () => {
const value = 'value'; const value = 'value';
beforeEach(function() { beforeEach(() => {
memo.isLocalStorageAvailable = true; memo.isLocalStorageAvailable = true;
SigninTabsMemoizer.prototype.saveData.call(memo, value); SigninTabsMemoizer.prototype.saveData.call(memo, value);
...@@ -184,11 +186,11 @@ describe('SigninTabsMemoizer', () => { ...@@ -184,11 +186,11 @@ describe('SigninTabsMemoizer', () => {
currentTabKey, currentTabKey,
}; };
spyOn(localStorage, 'getItem').and.returnValue(itemValue); localStorage.getItem.mockReturnValue(itemValue);
}); });
describe('if .isLocalStorageAvailable is `false`', () => { describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(function() { beforeEach(() => {
memo.isLocalStorageAvailable = false; memo.isLocalStorageAvailable = false;
readData = SigninTabsMemoizer.prototype.readData.call(memo); readData = SigninTabsMemoizer.prototype.readData.call(memo);
...@@ -201,7 +203,7 @@ describe('SigninTabsMemoizer', () => { ...@@ -201,7 +203,7 @@ describe('SigninTabsMemoizer', () => {
}); });
describe('if .isLocalStorageAvailable is `true`', () => { describe('if .isLocalStorageAvailable is `true`', () => {
beforeEach(function() { beforeEach(() => {
memo.isLocalStorageAvailable = true; memo.isLocalStorageAvailable = true;
readData = SigninTabsMemoizer.prototype.readData.call(memo); readData = SigninTabsMemoizer.prototype.readData.call(memo);
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import setTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import PersistentUserCallout from '~/persistent_user_callout'; import PersistentUserCallout from '~/persistent_user_callout';
import Flash from '~/flash';
jest.mock('~/flash');
describe('PersistentUserCallout', () => { describe('PersistentUserCallout', () => {
const dismissEndpoint = '/dismiss'; const dismissEndpoint = '/dismiss';
...@@ -51,44 +54,35 @@ describe('PersistentUserCallout', () => { ...@@ -51,44 +54,35 @@ describe('PersistentUserCallout', () => {
button = fixture.querySelector('.js-close'); button = fixture.querySelector('.js-close');
mockAxios = new MockAdapter(axios); mockAxios = new MockAdapter(axios);
persistentUserCallout = new PersistentUserCallout(container); persistentUserCallout = new PersistentUserCallout(container);
spyOn(persistentUserCallout.container, 'remove'); jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
mockAxios.restore(); mockAxios.restore();
}); });
it('POSTs endpoint and removes container when clicking close', done => { it('POSTs endpoint and removes container when clicking close', () => {
mockAxios.onPost(dismissEndpoint).replyOnce(200); mockAxios.onPost(dismissEndpoint).replyOnce(200);
button.click(); button.click();
setTimeoutPromise() return waitForPromises().then(() => {
.then(() => { expect(persistentUserCallout.container.remove).toHaveBeenCalled();
expect(persistentUserCallout.container.remove).toHaveBeenCalled(); expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ feature_name: featureName }));
expect(mockAxios.history.post[0].data).toBe( });
JSON.stringify({ feature_name: featureName }),
);
})
.then(done)
.catch(done.fail);
}); });
it('invokes Flash when the dismiss request fails', done => { it('invokes Flash when the dismiss request fails', () => {
const Flash = spyOnDependency(PersistentUserCallout, 'Flash');
mockAxios.onPost(dismissEndpoint).replyOnce(500); mockAxios.onPost(dismissEndpoint).replyOnce(500);
button.click(); button.click();
setTimeoutPromise() return waitForPromises().then(() => {
.then(() => { expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
expect(persistentUserCallout.container.remove).not.toHaveBeenCalled(); expect(Flash).toHaveBeenCalledWith(
expect(Flash).toHaveBeenCalledWith( 'An error occurred while dismissing the alert. Refresh the page and try again.',
'An error occurred while dismissing the alert. Refresh the page and try again.', );
); });
})
.then(done)
.catch(done.fail);
}); });
}); });
...@@ -108,56 +102,45 @@ describe('PersistentUserCallout', () => { ...@@ -108,56 +102,45 @@ describe('PersistentUserCallout', () => {
normalLink = fixture.querySelector('.normal-link'); normalLink = fixture.querySelector('.normal-link');
mockAxios = new MockAdapter(axios); mockAxios = new MockAdapter(axios);
persistentUserCallout = new PersistentUserCallout(container); persistentUserCallout = new PersistentUserCallout(container);
spyOn(persistentUserCallout.container, 'remove'); jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {});
windowSpy = spyOn(window, 'open').and.callFake(() => {}); windowSpy = jest.spyOn(window, 'open').mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
mockAxios.restore(); mockAxios.restore();
}); });
it('defers loading of a link until callout is dismissed', done => { it('defers loading of a link until callout is dismissed', () => {
const { href, target } = deferredLink; const { href, target } = deferredLink;
mockAxios.onPost(dismissEndpoint).replyOnce(200); mockAxios.onPost(dismissEndpoint).replyOnce(200);
deferredLink.click(); deferredLink.click();
setTimeoutPromise() return waitForPromises().then(() => {
.then(() => { expect(windowSpy).toHaveBeenCalledWith(href, target);
expect(windowSpy).toHaveBeenCalledWith(href, target); expect(persistentUserCallout.container.remove).toHaveBeenCalled();
expect(persistentUserCallout.container.remove).toHaveBeenCalled(); expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ feature_name: featureName }));
expect(mockAxios.history.post[0].data).toBe( });
JSON.stringify({ feature_name: featureName }),
);
})
.then(done)
.catch(done.fail);
}); });
it('does not dismiss callout on non-deferred links', done => { it('does not dismiss callout on non-deferred links', () => {
normalLink.click(); normalLink.click();
setTimeoutPromise() return waitForPromises().then(() => {
.then(() => { expect(windowSpy).not.toHaveBeenCalled();
expect(windowSpy).not.toHaveBeenCalled(); expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
expect(persistentUserCallout.container.remove).not.toHaveBeenCalled(); });
})
.then(done)
.catch(done.fail);
}); });
it('does not follow link when notification is closed', done => { it('does not follow link when notification is closed', () => {
mockAxios.onPost(dismissEndpoint).replyOnce(200); mockAxios.onPost(dismissEndpoint).replyOnce(200);
button.click(); button.click();
setTimeoutPromise() return waitForPromises().then(() => {
.then(() => { expect(windowSpy).not.toHaveBeenCalled();
expect(windowSpy).not.toHaveBeenCalled(); expect(persistentUserCallout.container.remove).toHaveBeenCalled();
expect(persistentUserCallout.container.remove).toHaveBeenCalled(); });
})
.then(done)
.catch(done.fail);
}); });
}); });
......
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