Commit 4c1dff36 authored by Kushal Pandya's avatar Kushal Pandya

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

Migrate several specs to Jest

Closes #194291, #194272, and #27259

See merge request gitlab-org/gitlab!34016
parents 759bcf35 346ba81d
...@@ -95,7 +95,7 @@ export default class FilteredSearchVisualTokens { ...@@ -95,7 +95,7 @@ export default class FilteredSearchVisualTokens {
const tokenType = tokenName.toLowerCase(); const tokenType = tokenName.toLowerCase();
const tokenValueContainer = parentElement.querySelector('.value-container'); const tokenValueContainer = parentElement.querySelector('.value-container');
const tokenValueElement = tokenValueContainer.querySelector('.value'); const tokenValueElement = tokenValueContainer.querySelector('.value');
tokenValueElement.innerText = tokenValue; tokenValueElement.textContent = tokenValue;
const visualTokenValue = new VisualTokenValue(tokenValue, tokenType, tokenOperator); const visualTokenValue = new VisualTokenValue(tokenValue, tokenType, tokenOperator);
...@@ -140,9 +140,9 @@ export default class FilteredSearchVisualTokens { ...@@ -140,9 +140,9 @@ export default class FilteredSearchVisualTokens {
li.innerHTML = nameHTML + operatorHTML; li.innerHTML = nameHTML + operatorHTML;
} }
li.querySelector('.name').innerText = name; li.querySelector('.name').textContent = name;
if (hasOperator) { if (hasOperator) {
li.querySelector('.operator').innerText = operator; li.querySelector('.operator').textContent = operator;
} }
const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container'); const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container');
...@@ -162,8 +162,8 @@ export default class FilteredSearchVisualTokens { ...@@ -162,8 +162,8 @@ export default class FilteredSearchVisualTokens {
lastVisualToken.innerHTML = FilteredSearchVisualTokens.createVisualTokenElementHTML({ lastVisualToken.innerHTML = FilteredSearchVisualTokens.createVisualTokenElementHTML({
hasOperator: Boolean(operator), hasOperator: Boolean(operator),
}); });
lastVisualToken.querySelector('.name').innerText = name; lastVisualToken.querySelector('.name').textContent = name;
lastVisualToken.querySelector('.operator').innerText = operator; lastVisualToken.querySelector('.operator').textContent = operator;
FilteredSearchVisualTokens.renderVisualTokenValue(lastVisualToken, name, value, operator); FilteredSearchVisualTokens.renderVisualTokenValue(lastVisualToken, name, value, operator);
} }
} }
...@@ -208,8 +208,8 @@ export default class FilteredSearchVisualTokens { ...@@ -208,8 +208,8 @@ export default class FilteredSearchVisualTokens {
}, },
}); });
} else { } else {
const previousTokenName = lastVisualToken.querySelector('.name').innerText; const previousTokenName = lastVisualToken.querySelector('.name').textContent;
const previousTokenOperator = lastVisualToken.querySelector('.operator').innerText; const previousTokenOperator = lastVisualToken.querySelector('.operator').textContent;
const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container'); const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container');
tokensContainer.removeChild(lastVisualToken); tokensContainer.removeChild(lastVisualToken);
...@@ -234,7 +234,7 @@ export default class FilteredSearchVisualTokens { ...@@ -234,7 +234,7 @@ export default class FilteredSearchVisualTokens {
const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
if (lastVisualToken && lastVisualToken.classList.contains('filtered-search-term')) { if (lastVisualToken && lastVisualToken.classList.contains('filtered-search-term')) {
lastVisualToken.querySelector('.name').innerText += ` ${searchTerm}`; lastVisualToken.querySelector('.name').textContent += ` ${searchTerm}`;
} else { } else {
FilteredSearchVisualTokens.addVisualTokenElement({ FilteredSearchVisualTokens.addVisualTokenElement({
name: searchTerm, name: searchTerm,
...@@ -261,12 +261,12 @@ export default class FilteredSearchVisualTokens { ...@@ -261,12 +261,12 @@ export default class FilteredSearchVisualTokens {
const value = lastVisualToken.querySelector('.value'); const value = lastVisualToken.querySelector('.value');
const name = lastVisualToken.querySelector('.name'); const name = lastVisualToken.querySelector('.name');
const valueText = value ? value.innerText : ''; const valueText = value ? value.textContent : '';
const nameText = name ? name.innerText : ''; const nameText = name ? name.textContent : '';
if (includeOperator) { if (includeOperator) {
const operator = lastVisualToken.querySelector('.operator'); const operator = lastVisualToken.querySelector('.operator');
const operatorText = operator ? operator.innerText : ''; const operatorText = operator ? operator.textContent : '';
return valueText || operatorText || nameText; return valueText || operatorText || nameText;
} }
...@@ -278,7 +278,7 @@ export default class FilteredSearchVisualTokens { ...@@ -278,7 +278,7 @@ export default class FilteredSearchVisualTokens {
const operator = lastVisualToken && lastVisualToken.querySelector('.operator'); const operator = lastVisualToken && lastVisualToken.querySelector('.operator');
return operator?.innerText; return operator?.textContent;
} }
static removeLastTokenPartial() { static removeLastTokenPartial() {
...@@ -346,8 +346,8 @@ export default class FilteredSearchVisualTokens { ...@@ -346,8 +346,8 @@ export default class FilteredSearchVisualTokens {
if (token.classList.contains('filtered-search-token')) { if (token.classList.contains('filtered-search-token')) {
FilteredSearchVisualTokens.addFilterVisualToken( FilteredSearchVisualTokens.addFilterVisualToken(
nameElement.innerText, nameElement.textContent,
operatorElement.innerText, operatorElement.textContent,
null, null,
{ {
uppercaseTokenName: nameElement.classList.contains('text-uppercase'), uppercaseTokenName: nameElement.classList.contains('text-uppercase'),
...@@ -359,13 +359,13 @@ export default class FilteredSearchVisualTokens { ...@@ -359,13 +359,13 @@ export default class FilteredSearchVisualTokens {
if (!value) { if (!value) {
const valueElement = valueContainerElement.querySelector('.value'); const valueElement = valueContainerElement.querySelector('.value');
value = valueElement.innerText; value = valueElement.textContent;
} }
} }
// token is a search term // token is a search term
if (!value) { if (!value) {
value = nameElement.innerText; value = nameElement.textContent;
} }
input.value = value; input.value = value;
......
<script> <script>
import '~/gl_dropdown';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import UsersSelect from '~/users_select'; import UsersSelect from '~/users_select';
......
...@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue'; import Vue from 'vue';
import AssigneeSelect from 'ee/boards/components/assignee_select.vue'; import AssigneeSelect from 'ee/boards/components/assignee_select.vue';
import { boardObj } from 'spec/boards/mock_data'; import { boardObj } from 'jest/boards/mock_data';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
...@@ -51,7 +51,7 @@ describe('Assignee select component', () => { ...@@ -51,7 +51,7 @@ describe('Assignee select component', () => {
}, },
}).$mount('.test-container'); }).$mount('.test-container');
setTimeout(done); setImmediate(done);
}); });
describe('canEdit', () => { describe('canEdit', () => {
...@@ -100,10 +100,12 @@ describe('Assignee select component', () => { ...@@ -100,10 +100,12 @@ describe('Assignee select component', () => {
it('sets assignee', done => { it('sets assignee', done => {
vm.$el.querySelector('.edit-link').click(); vm.$el.querySelector('.edit-link').click();
setTimeout(() => { jest.runOnlyPendingTimers();
setImmediate(() => {
vm.$el.querySelectorAll('li a')[2].click(); vm.$el.querySelectorAll('li a')[2].click();
setTimeout(() => { setImmediate(() => {
expect(activeDropdownItem(0)).toEqual('second assignee'); expect(activeDropdownItem(0)).toEqual('second assignee');
expect(vm.board.assignee).toEqual(assignee2); expect(vm.board.assignee).toEqual(assignee2);
done(); done();
......
...@@ -9,6 +9,7 @@ describe('BoardList Component', () => { ...@@ -9,6 +9,7 @@ describe('BoardList Component', () => {
project: { project: {
path: '/test', path: '/test',
}, },
real_path: '',
}; };
const componentProps = { const componentProps = {
......
import Vue from 'vue'; import Vue from 'vue';
import MockAdapater from 'axios-mock-adapter'; import MockAdapater from 'axios-mock-adapter';
import MilestoneSelect from 'ee/boards/components/milestone_select.vue'; import MilestoneSelect from 'ee/boards/components/milestone_select.vue';
import { boardObj } from 'spec/boards/mock_data'; import { boardObj } from 'jest/boards/mock_data';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
...@@ -45,7 +45,7 @@ describe('Milestone select component', () => { ...@@ -45,7 +45,7 @@ describe('Milestone select component', () => {
}, },
}).$mount('.test-container'); }).$mount('.test-container');
setTimeout(done); setImmediate(done);
}); });
describe('canEdit', () => { describe('canEdit', () => {
...@@ -103,15 +103,18 @@ describe('Milestone select component', () => { ...@@ -103,15 +103,18 @@ describe('Milestone select component', () => {
mock.restore(); mock.restore();
}); });
it('sets Any milestone', done => { it('sets Any milestone', async done => {
vm.board.milestone_id = 0; vm.board.milestone_id = 0;
vm.$el.querySelector('.edit-link').click(); vm.$el.querySelector('.edit-link').click();
setTimeout(() => { await vm.$nextTick();
jest.runOnlyPendingTimers();
setImmediate(() => {
vm.$el.querySelectorAll('li a')[0].click(); vm.$el.querySelectorAll('li a')[0].click();
}); });
setTimeout(() => { setImmediate(() => {
expect(activeDropdownItem(0)).toEqual('Any milestone'); expect(activeDropdownItem(0)).toEqual('Any milestone');
expect(selectedText()).toEqual('Any milestone'); expect(selectedText()).toEqual('Any milestone');
done(); done();
...@@ -121,11 +124,13 @@ describe('Milestone select component', () => { ...@@ -121,11 +124,13 @@ describe('Milestone select component', () => {
it('sets No milestone', done => { it('sets No milestone', done => {
vm.$el.querySelector('.edit-link').click(); vm.$el.querySelector('.edit-link').click();
setTimeout(() => { jest.runOnlyPendingTimers();
setImmediate(() => {
vm.$el.querySelectorAll('li a')[1].click(); vm.$el.querySelectorAll('li a')[1].click();
}); });
setTimeout(() => { setImmediate(() => {
expect(activeDropdownItem(0)).toEqual('No milestone'); expect(activeDropdownItem(0)).toEqual('No milestone');
expect(selectedText()).toEqual('No milestone'); expect(selectedText()).toEqual('No milestone');
done(); done();
...@@ -135,11 +140,13 @@ describe('Milestone select component', () => { ...@@ -135,11 +140,13 @@ describe('Milestone select component', () => {
it('sets milestone', done => { it('sets milestone', done => {
vm.$el.querySelector('.edit-link').click(); vm.$el.querySelector('.edit-link').click();
setTimeout(() => { jest.runOnlyPendingTimers();
setImmediate(() => {
vm.$el.querySelectorAll('li a')[4].click(); vm.$el.querySelectorAll('li a')[4].click();
}); });
setTimeout(() => { setImmediate(() => {
expect(activeDropdownItem(0)).toEqual('first milestone'); expect(activeDropdownItem(0)).toEqual('first milestone');
expect(selectedText()).toEqual('first milestone'); expect(selectedText()).toEqual('first milestone');
expect(vm.board.milestone).toEqual(milestone); expect(vm.board.milestone).toEqual(milestone);
......
...@@ -36,6 +36,11 @@ describe('AddIssuableForm', () => { ...@@ -36,6 +36,11 @@ describe('AddIssuableForm', () => {
let wrapper; let wrapper;
afterEach(() => { afterEach(() => {
// Jest doesn't blur an item even if it is destroyed,
// so blur the input manually after each test
const input = findFormInput(wrapper);
if (input) input.blur();
wrapper.destroy(); wrapper.destroy();
}); });
...@@ -178,7 +183,7 @@ describe('AddIssuableForm', () => { ...@@ -178,7 +183,7 @@ describe('AddIssuableForm', () => {
describe('when the form is submitted', () => { describe('when the form is submitted', () => {
it('emits an event with a "relates_to" link type when the "relates to" radio input selected', done => { it('emits an event with a "relates_to" link type when the "relates to" radio input selected', done => {
spyOn(wrapper.vm, '$emit'); jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
wrapper.vm.linkedIssueType = linkedIssueTypesMap.RELATES_TO; wrapper.vm.linkedIssueType = linkedIssueTypesMap.RELATES_TO;
wrapper.vm.onFormSubmit(); wrapper.vm.onFormSubmit();
...@@ -193,7 +198,7 @@ describe('AddIssuableForm', () => { ...@@ -193,7 +198,7 @@ describe('AddIssuableForm', () => {
}); });
it('emits an event with a "blocks" link type when the "blocks" radio input selected', done => { it('emits an event with a "blocks" link type when the "blocks" radio input selected', done => {
spyOn(wrapper.vm, '$emit'); jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
wrapper.vm.linkedIssueType = linkedIssueTypesMap.BLOCKS; wrapper.vm.linkedIssueType = linkedIssueTypesMap.BLOCKS;
wrapper.vm.onFormSubmit(); wrapper.vm.onFormSubmit();
...@@ -208,7 +213,7 @@ describe('AddIssuableForm', () => { ...@@ -208,7 +213,7 @@ describe('AddIssuableForm', () => {
}); });
it('emits an event with a "is_blocked_by" link type when the "is blocked by" radio input selected', done => { it('emits an event with a "is_blocked_by" link type when the "is blocked by" radio input selected', done => {
spyOn(wrapper.vm, '$emit'); jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {});
wrapper.vm.linkedIssueType = linkedIssueTypesMap.IS_BLOCKED_BY; wrapper.vm.linkedIssueType = linkedIssueTypesMap.IS_BLOCKED_BY;
wrapper.vm.onFormSubmit(); wrapper.vm.onFormSubmit();
......
...@@ -2,6 +2,7 @@ import $ from 'jquery'; ...@@ -2,6 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import loadAwardsHandler from '~/awards_handler'; import loadAwardsHandler from '~/awards_handler';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
import waitForPromises from './helpers/wait_for_promises';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gon = window.gon || {}; window.gon = window.gon || {};
...@@ -10,28 +11,32 @@ let openAndWaitForEmojiMenu; ...@@ -10,28 +11,32 @@ let openAndWaitForEmojiMenu;
let awardsHandler = null; let awardsHandler = null;
const urlRoot = gon.relative_url_root; const urlRoot = gon.relative_url_root;
const lazyAssert = function(done, assertFn) { const lazyAssert = (done, assertFn) => {
setTimeout(function() { jest.runOnlyPendingTimers();
assertFn(); waitForPromises()
done(); .then(() => {
// Maybe jasmine.clock here? assertFn();
}, 333); done();
})
.catch(e => {
throw e;
});
}; };
describe('AwardsHandler', function() { describe('AwardsHandler', () => {
preloadFixtures('snippets/show.html'); preloadFixtures('snippets/show.html');
beforeEach(function(done) { beforeEach(done => {
loadFixtures('snippets/show.html'); loadFixtures('snippets/show.html');
loadAwardsHandler(true) loadAwardsHandler(true)
.then(obj => { .then(obj => {
awardsHandler = obj; awardsHandler = obj;
spyOn(awardsHandler, 'postEmoji').and.callFake((button, url, emoji, cb) => cb()); jest.spyOn(awardsHandler, 'postEmoji').mockImplementation((button, url, emoji, cb) => cb());
done(); done();
}) })
.catch(fail); .catch(done.fail);
let isEmojiMenuBuilt = false; let isEmojiMenuBuilt = false;
openAndWaitForEmojiMenu = function() { openAndWaitForEmojiMenu = () => {
return new Promise(resolve => { return new Promise(resolve => {
if (isEmojiMenuBuilt) { if (isEmojiMenuBuilt) {
resolve(); resolve();
...@@ -49,7 +54,7 @@ describe('AwardsHandler', function() { ...@@ -49,7 +54,7 @@ describe('AwardsHandler', function() {
}; };
}); });
afterEach(function() { afterEach(() => {
// restore original url root value // restore original url root value
gon.relative_url_root = urlRoot; gon.relative_url_root = urlRoot;
...@@ -59,12 +64,12 @@ describe('AwardsHandler', function() { ...@@ -59,12 +64,12 @@ describe('AwardsHandler', function() {
awardsHandler.destroy(); awardsHandler.destroy();
}); });
describe('::showEmojiMenu', function() { describe('::showEmojiMenu', () => {
it('should show emoji menu when Add emoji button clicked', function(done) { it('should show emoji menu when Add emoji button clicked', done => {
$('.js-add-award') $('.js-add-award')
.eq(0) .eq(0)
.click(); .click();
lazyAssert(done, function() { lazyAssert(done, () => {
const $emojiMenu = $('.emoji-menu'); const $emojiMenu = $('.emoji-menu');
expect($emojiMenu.length).toBe(1); expect($emojiMenu.length).toBe(1);
...@@ -74,20 +79,20 @@ describe('AwardsHandler', function() { ...@@ -74,20 +79,20 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should also show emoji menu for the smiley icon in notes', function(done) { it('should also show emoji menu for the smiley icon in notes', done => {
$('.js-add-award.note-action-button').click(); $('.js-add-award.note-action-button').click();
lazyAssert(done, function() { lazyAssert(done, () => {
const $emojiMenu = $('.emoji-menu'); const $emojiMenu = $('.emoji-menu');
expect($emojiMenu.length).toBe(1); expect($emojiMenu.length).toBe(1);
}); });
}); });
it('should remove emoji menu when body is clicked', function(done) { it('should remove emoji menu when body is clicked', done => {
$('.js-add-award') $('.js-add-award')
.eq(0) .eq(0)
.click(); .click();
lazyAssert(done, function() { lazyAssert(done, () => {
const $emojiMenu = $('.emoji-menu'); const $emojiMenu = $('.emoji-menu');
$('body').click(); $('body').click();
...@@ -97,11 +102,11 @@ describe('AwardsHandler', function() { ...@@ -97,11 +102,11 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should not remove emoji menu when search is clicked', function(done) { it('should not remove emoji menu when search is clicked', done => {
$('.js-add-award') $('.js-add-award')
.eq(0) .eq(0)
.click(); .click();
lazyAssert(done, function() { lazyAssert(done, () => {
const $emojiMenu = $('.emoji-menu'); const $emojiMenu = $('.emoji-menu');
$('.emoji-search').click(); $('.emoji-search').click();
...@@ -112,8 +117,8 @@ describe('AwardsHandler', function() { ...@@ -112,8 +117,8 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('::addAwardToEmojiBar', function() { describe('::addAwardToEmojiBar', () => {
it('should add emoji to votes block', function() { it('should add emoji to votes block', () => {
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false); awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
const $emojiButton = $votesBlock.find('[data-name=heart]'); const $emojiButton = $votesBlock.find('[data-name=heart]');
...@@ -123,7 +128,7 @@ describe('AwardsHandler', function() { ...@@ -123,7 +128,7 @@ describe('AwardsHandler', function() {
expect($votesBlock.hasClass('hidden')).toBe(false); expect($votesBlock.hasClass('hidden')).toBe(false);
}); });
it('should remove the emoji when we click again', function() { it('should remove the emoji when we click again', () => {
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false); awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false); awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
...@@ -132,7 +137,7 @@ describe('AwardsHandler', function() { ...@@ -132,7 +137,7 @@ describe('AwardsHandler', function() {
expect($emojiButton.length).toBe(0); expect($emojiButton.length).toBe(0);
}); });
it('should decrement the emoji counter', function() { it('should decrement the emoji counter', () => {
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false); awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
const $emojiButton = $votesBlock.find('[data-name=heart]'); const $emojiButton = $votesBlock.find('[data-name=heart]');
...@@ -144,8 +149,8 @@ describe('AwardsHandler', function() { ...@@ -144,8 +149,8 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('::userAuthored', function() { describe('::userAuthored', () => {
it('should update tooltip to user authored title', function() { it('should update tooltip to user authored title', () => {
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
$thumbsUpEmoji.attr('data-title', 'sam'); $thumbsUpEmoji.attr('data-title', 'sam');
...@@ -156,27 +161,25 @@ describe('AwardsHandler', function() { ...@@ -156,27 +161,25 @@ describe('AwardsHandler', function() {
); );
}); });
it('should restore tooltip back to initial vote list', function() { it('should restore tooltip back to initial vote list', () => {
jasmine.clock().install();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
$thumbsUpEmoji.attr('data-title', 'sam'); $thumbsUpEmoji.attr('data-title', 'sam');
awardsHandler.userAuthored($thumbsUpEmoji); awardsHandler.userAuthored($thumbsUpEmoji);
jasmine.clock().tick(2801); jest.advanceTimersByTime(2801);
jasmine.clock().uninstall();
expect($thumbsUpEmoji.data('originalTitle')).toBe('sam'); expect($thumbsUpEmoji.data('originalTitle')).toBe('sam');
}); });
}); });
describe('::getAwardUrl', function() { describe('::getAwardUrl', () => {
it('returns the url for request', function() { it('returns the url for request', () => {
expect(awardsHandler.getAwardUrl()).toBe('http://test.host/snippets/1/toggle_award_emoji'); expect(awardsHandler.getAwardUrl()).toBe('http://test.host/snippets/1/toggle_award_emoji');
}); });
}); });
describe('::addAward and ::checkMutuality', function() { describe('::addAward and ::checkMutuality', () => {
it('should handle :+1: and :-1: mutuality', function() { it('should handle :+1: and :-1: mutuality', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
...@@ -194,8 +197,8 @@ describe('AwardsHandler', function() { ...@@ -194,8 +197,8 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('::removeEmoji', function() { describe('::removeEmoji', () => {
it('should remove emoji', function() { it('should remove emoji', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
awardsHandler.addAward($votesBlock, awardUrl, 'fire', false); awardsHandler.addAward($votesBlock, awardUrl, 'fire', false);
...@@ -207,8 +210,8 @@ describe('AwardsHandler', function() { ...@@ -207,8 +210,8 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('::addYouToUserList', function() { describe('::addYouToUserList', () => {
it('should prepend "You" to the award tooltip', function() { it('should prepend "You" to the award tooltip', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
...@@ -219,7 +222,7 @@ describe('AwardsHandler', function() { ...@@ -219,7 +222,7 @@ describe('AwardsHandler', function() {
expect($thumbsUpEmoji.data('originalTitle')).toBe('You, sam, jerry, max, and andy'); expect($thumbsUpEmoji.data('originalTitle')).toBe('You, sam, jerry, max, and andy');
}); });
it('handles the special case where "You" is not cleanly comma separated', function() { it('handles the special case where "You" is not cleanly comma separated', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
...@@ -231,8 +234,8 @@ describe('AwardsHandler', function() { ...@@ -231,8 +234,8 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('::removeYouToUserList', function() { describe('::removeYouToUserList', () => {
it('removes "You" from the front of the tooltip', function() { it('removes "You" from the front of the tooltip', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
...@@ -244,7 +247,7 @@ describe('AwardsHandler', function() { ...@@ -244,7 +247,7 @@ describe('AwardsHandler', function() {
expect($thumbsUpEmoji.data('originalTitle')).toBe('sam, jerry, max, and andy'); expect($thumbsUpEmoji.data('originalTitle')).toBe('sam, jerry, max, and andy');
}); });
it('handles the special case where "You" is not cleanly comma separated', function() { it('handles the special case where "You" is not cleanly comma separated', () => {
const awardUrl = awardsHandler.getAwardUrl(); const awardUrl = awardsHandler.getAwardUrl();
const $votesBlock = $('.js-awards-block').eq(0); const $votesBlock = $('.js-awards-block').eq(0);
const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent(); const $thumbsUpEmoji = $votesBlock.find('[data-name=thumbsup]').parent();
...@@ -258,7 +261,7 @@ describe('AwardsHandler', function() { ...@@ -258,7 +261,7 @@ describe('AwardsHandler', function() {
}); });
describe('::searchEmojis', () => { describe('::searchEmojis', () => {
it('should filter the emoji', function(done) { it('should filter the emoji', done => {
openAndWaitForEmojiMenu() openAndWaitForEmojiMenu()
.then(() => { .then(() => {
expect($('[data-name=angel]').is(':visible')).toBe(true); expect($('[data-name=angel]').is(':visible')).toBe(true);
...@@ -276,7 +279,7 @@ describe('AwardsHandler', function() { ...@@ -276,7 +279,7 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should clear the search when searching for nothing', function(done) { it('should clear the search when searching for nothing', done => {
openAndWaitForEmojiMenu() openAndWaitForEmojiMenu()
.then(() => { .then(() => {
awardsHandler.searchEmojis('ali'); awardsHandler.searchEmojis('ali');
...@@ -298,9 +301,9 @@ describe('AwardsHandler', function() { ...@@ -298,9 +301,9 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('emoji menu', function() { describe('emoji menu', () => {
const emojiSelector = '[data-name="sunglasses"]'; const emojiSelector = '[data-name="sunglasses"]';
const openEmojiMenuAndAddEmoji = function() { const openEmojiMenuAndAddEmoji = () => {
return openAndWaitForEmojiMenu().then(() => { return openAndWaitForEmojiMenu().then(() => {
const $menu = $('.emoji-menu'); const $menu = $('.emoji-menu');
const $block = $('.js-awards-block'); const $block = $('.js-awards-block');
...@@ -315,7 +318,7 @@ describe('AwardsHandler', function() { ...@@ -315,7 +318,7 @@ describe('AwardsHandler', function() {
}); });
}; };
it('should add selected emoji to awards block', function(done) { it('should add selected emoji to awards block', done => {
openEmojiMenuAndAddEmoji() openEmojiMenuAndAddEmoji()
.then(done) .then(done)
.catch(err => { .catch(err => {
...@@ -323,7 +326,7 @@ describe('AwardsHandler', function() { ...@@ -323,7 +326,7 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should remove already selected emoji', function(done) { it('should remove already selected emoji', done => {
openEmojiMenuAndAddEmoji() openEmojiMenuAndAddEmoji()
.then(() => { .then(() => {
$('.js-add-award') $('.js-add-award')
...@@ -344,13 +347,13 @@ describe('AwardsHandler', function() { ...@@ -344,13 +347,13 @@ describe('AwardsHandler', function() {
}); });
}); });
describe('frequently used emojis', function() { describe('frequently used emojis', () => {
beforeEach(() => { beforeEach(() => {
// Clear it out // Clear it out
Cookies.set('frequently_used_emojis', ''); Cookies.set('frequently_used_emojis', '');
}); });
it('shouldn\'t have any "Frequently used" heading if no frequently used emojis', function(done) { it('shouldn\'t have any "Frequently used" heading if no frequently used emojis', done => {
return openAndWaitForEmojiMenu() return openAndWaitForEmojiMenu()
.then(() => { .then(() => {
const emojiMenu = document.querySelector('.emoji-menu'); const emojiMenu = document.querySelector('.emoji-menu');
...@@ -364,7 +367,7 @@ describe('AwardsHandler', function() { ...@@ -364,7 +367,7 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should have any frequently used section when there are frequently used emojis', function(done) { it('should have any frequently used section when there are frequently used emojis', done => {
awardsHandler.addEmojiToFrequentlyUsedList('8ball'); awardsHandler.addEmojiToFrequentlyUsedList('8ball');
return openAndWaitForEmojiMenu() return openAndWaitForEmojiMenu()
...@@ -383,7 +386,7 @@ describe('AwardsHandler', function() { ...@@ -383,7 +386,7 @@ describe('AwardsHandler', function() {
}); });
}); });
it('should disregard invalid frequently used emoji that are being attempted to be added', function() { it('should disregard invalid frequently used emoji that are being attempted to be added', () => {
awardsHandler.addEmojiToFrequentlyUsedList('8ball'); awardsHandler.addEmojiToFrequentlyUsedList('8ball');
awardsHandler.addEmojiToFrequentlyUsedList('invalid_emoji'); awardsHandler.addEmojiToFrequentlyUsedList('invalid_emoji');
awardsHandler.addEmojiToFrequentlyUsedList('grinning'); awardsHandler.addEmojiToFrequentlyUsedList('grinning');
...@@ -391,7 +394,7 @@ describe('AwardsHandler', function() { ...@@ -391,7 +394,7 @@ describe('AwardsHandler', function() {
expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']); expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
}); });
it('should disregard invalid frequently used emoji already set in cookie', function() { it('should disregard invalid frequently used emoji already set in cookie', () => {
Cookies.set('frequently_used_emojis', '8ball,invalid_emoji,grinning'); Cookies.set('frequently_used_emojis', '8ball,invalid_emoji,grinning');
expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']); expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
......
...@@ -3,7 +3,8 @@ import { clone } from 'lodash'; ...@@ -3,7 +3,8 @@ import { clone } from 'lodash';
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 Sidebar from '~/right_sidebar'; import Sidebar from '~/right_sidebar';
import timeoutPromise from './helpers/set_timeout_promise_helper'; import waitForPromises from './helpers/wait_for_promises';
import { TEST_HOST } from 'spec/test_constants';
describe('Issuable right sidebar collapsed todo toggle', () => { describe('Issuable right sidebar collapsed todo toggle', () => {
const fixtureName = 'issues/open-issue.html'; const fixtureName = 'issues/open-issue.html';
...@@ -23,7 +24,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -23,7 +24,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock.onPost(`${gl.TEST_HOST}/frontend-fixtures/issues-project/todos`).reply(() => { mock.onPost(`${TEST_HOST}/frontend-fixtures/issues-project/todos`).reply(() => {
const response = clone(todoData); const response = clone(todoData);
return [200, response]; return [200, response];
...@@ -64,7 +65,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -64,7 +65,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('toggle todo state', done => { it('toggle todo state', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
setTimeout(() => { setImmediate(() => {
expect( expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'), document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
).not.toBeNull(); ).not.toBeNull();
...@@ -82,7 +83,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -82,7 +83,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('toggle todo state of expanded todo toggle', done => { it('toggle todo state of expanded todo toggle', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
setTimeout(() => { setImmediate(() => {
expect( expect(
document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(), document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
).toBe('Mark as done'); ).toBe('Mark as done');
...@@ -94,7 +95,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -94,7 +95,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('toggles todo button tooltip', done => { it('toggles todo button tooltip', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
setTimeout(() => { setImmediate(() => {
expect( expect(
document document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon') .querySelector('.js-issuable-todo.sidebar-collapsed-icon')
...@@ -108,7 +109,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -108,7 +109,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('marks todo as done', done => { it('marks todo as done', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
timeoutPromise() waitForPromises()
.then(() => { .then(() => {
expect( expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'), document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
...@@ -116,7 +117,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -116,7 +117,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
}) })
.then(timeoutPromise) .then(waitForPromises)
.then(() => { .then(() => {
expect( expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'), document.querySelector('.js-issuable-todo.sidebar-collapsed-icon .todo-undone'),
...@@ -133,7 +134,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -133,7 +134,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('updates aria-label to Mark as done', done => { it('updates aria-label to Mark as done', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
setTimeout(() => { setImmediate(() => {
expect( expect(
document document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon') .querySelector('.js-issuable-todo.sidebar-collapsed-icon')
...@@ -147,7 +148,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -147,7 +148,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('updates aria-label to add todo', done => { it('updates aria-label to add todo', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
timeoutPromise() waitForPromises()
.then(() => { .then(() => {
expect( expect(
document document
...@@ -157,7 +158,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => { ...@@ -157,7 +158,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click(); document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
}) })
.then(timeoutPromise) .then(waitForPromises)
.then(() => { .then(() => {
expect( expect(
document document
......
import CommentTypeToggle from '~/comment_type_toggle'; import CommentTypeToggle from '~/comment_type_toggle';
import DropLab from '~/droplab/drop_lab';
import InputSetter from '~/droplab/plugins/input_setter'; import InputSetter from '~/droplab/plugins/input_setter';
describe('CommentTypeToggle', function() { describe('CommentTypeToggle', () => {
describe('class constructor', function() { const testContext = {};
beforeEach(function() {
this.dropdownTrigger = {}; describe('class constructor', () => {
this.dropdownList = {}; beforeEach(() => {
this.noteTypeInput = {}; testContext.dropdownTrigger = {};
this.submitButton = {}; testContext.dropdownList = {};
this.closeButton = {}; testContext.noteTypeInput = {};
testContext.submitButton = {};
this.commentTypeToggle = new CommentTypeToggle({ testContext.closeButton = {};
dropdownTrigger: this.dropdownTrigger,
dropdownList: this.dropdownList, testContext.commentTypeToggle = new CommentTypeToggle({
noteTypeInput: this.noteTypeInput, dropdownTrigger: testContext.dropdownTrigger,
submitButton: this.submitButton, dropdownList: testContext.dropdownList,
closeButton: this.closeButton, noteTypeInput: testContext.noteTypeInput,
submitButton: testContext.submitButton,
closeButton: testContext.closeButton,
}); });
}); });
it('should set .dropdownTrigger', function() { it('should set .dropdownTrigger', () => {
expect(this.commentTypeToggle.dropdownTrigger).toBe(this.dropdownTrigger); expect(testContext.commentTypeToggle.dropdownTrigger).toBe(testContext.dropdownTrigger);
}); });
it('should set .dropdownList', function() { it('should set .dropdownList', () => {
expect(this.commentTypeToggle.dropdownList).toBe(this.dropdownList); expect(testContext.commentTypeToggle.dropdownList).toBe(testContext.dropdownList);
}); });
it('should set .noteTypeInput', function() { it('should set .noteTypeInput', () => {
expect(this.commentTypeToggle.noteTypeInput).toBe(this.noteTypeInput); expect(testContext.commentTypeToggle.noteTypeInput).toBe(testContext.noteTypeInput);
}); });
it('should set .submitButton', function() { it('should set .submitButton', () => {
expect(this.commentTypeToggle.submitButton).toBe(this.submitButton); expect(testContext.commentTypeToggle.submitButton).toBe(testContext.submitButton);
}); });
it('should set .closeButton', function() { it('should set .closeButton', () => {
expect(this.commentTypeToggle.closeButton).toBe(this.closeButton); expect(testContext.commentTypeToggle.closeButton).toBe(testContext.closeButton);
}); });
it('should set .reopenButton', function() { it('should set .reopenButton', () => {
expect(this.commentTypeToggle.reopenButton).toBe(this.reopenButton); expect(testContext.commentTypeToggle.reopenButton).toBe(testContext.reopenButton);
}); });
}); });
describe('initDroplab', function() { describe('initDroplab', () => {
beforeEach(function() { beforeEach(() => {
this.commentTypeToggle = { testContext.commentTypeToggle = {
dropdownTrigger: {}, dropdownTrigger: {},
dropdownList: {}, dropdownList: {},
noteTypeInput: {}, noteTypeInput: {},
...@@ -54,44 +57,38 @@ describe('CommentTypeToggle', function() { ...@@ -54,44 +57,38 @@ describe('CommentTypeToggle', function() {
closeButton: {}, closeButton: {},
setConfig: () => {}, setConfig: () => {},
}; };
this.config = {}; testContext.config = {};
this.droplab = jasmine.createSpyObj('droplab', ['init']); jest.spyOn(DropLab.prototype, 'init').mockImplementation();
jest.spyOn(DropLab.prototype, 'constructor').mockImplementation();
this.droplabConstructor = spyOnDependency(CommentTypeToggle, 'DropLab').and.returnValue( jest.spyOn(testContext.commentTypeToggle, 'setConfig').mockReturnValue(testContext.config);
this.droplab,
);
spyOn(this.commentTypeToggle, 'setConfig').and.returnValue(this.config);
CommentTypeToggle.prototype.initDroplab.call(this.commentTypeToggle);
});
it('should instantiate a DropLab instance', function() { CommentTypeToggle.prototype.initDroplab.call(testContext.commentTypeToggle);
expect(this.droplabConstructor).toHaveBeenCalled();
}); });
it('should set .droplab', function() { it('should instantiate a DropLab instance and set .droplab', () => {
expect(this.commentTypeToggle.droplab).toBe(this.droplab); expect(testContext.commentTypeToggle.droplab instanceof DropLab).toBe(true);
}); });
it('should call .setConfig', function() { it('should call .setConfig', () => {
expect(this.commentTypeToggle.setConfig).toHaveBeenCalled(); expect(testContext.commentTypeToggle.setConfig).toHaveBeenCalled();
}); });
it('should call DropLab.prototype.init', function() { it('should call DropLab.prototype.init', () => {
expect(this.droplab.init).toHaveBeenCalledWith( expect(DropLab.prototype.init).toHaveBeenCalledWith(
this.commentTypeToggle.dropdownTrigger, testContext.commentTypeToggle.dropdownTrigger,
this.commentTypeToggle.dropdownList, testContext.commentTypeToggle.dropdownList,
[InputSetter], [InputSetter],
this.config, testContext.config,
); );
}); });
}); });
describe('setConfig', function() { describe('setConfig', () => {
describe('if no .closeButton is provided', function() { describe('if no .closeButton is provided', () => {
beforeEach(function() { beforeEach(() => {
this.commentTypeToggle = { testContext.commentTypeToggle = {
dropdownTrigger: {}, dropdownTrigger: {},
dropdownList: {}, dropdownList: {},
noteTypeInput: {}, noteTypeInput: {},
...@@ -99,26 +96,28 @@ describe('CommentTypeToggle', function() { ...@@ -99,26 +96,28 @@ describe('CommentTypeToggle', function() {
reopenButton: {}, reopenButton: {},
}; };
this.setConfig = CommentTypeToggle.prototype.setConfig.call(this.commentTypeToggle); testContext.setConfig = CommentTypeToggle.prototype.setConfig.call(
testContext.commentTypeToggle,
);
}); });
it('should not add .closeButton related InputSetter config', function() { it('should not add .closeButton related InputSetter config', () => {
expect(this.setConfig).toEqual({ expect(testContext.setConfig).toEqual({
InputSetter: [ InputSetter: [
{ {
input: this.commentTypeToggle.noteTypeInput, input: testContext.commentTypeToggle.noteTypeInput,
valueAttribute: 'data-value', valueAttribute: 'data-value',
}, },
{ {
input: this.commentTypeToggle.submitButton, input: testContext.commentTypeToggle.submitButton,
valueAttribute: 'data-submit-text', valueAttribute: 'data-submit-text',
}, },
{ {
input: this.commentTypeToggle.reopenButton, input: testContext.commentTypeToggle.reopenButton,
valueAttribute: 'data-reopen-text', valueAttribute: 'data-reopen-text',
}, },
{ {
input: this.commentTypeToggle.reopenButton, input: testContext.commentTypeToggle.reopenButton,
valueAttribute: 'data-reopen-text', valueAttribute: 'data-reopen-text',
inputAttribute: 'data-alternative-text', inputAttribute: 'data-alternative-text',
}, },
...@@ -127,9 +126,9 @@ describe('CommentTypeToggle', function() { ...@@ -127,9 +126,9 @@ describe('CommentTypeToggle', function() {
}); });
}); });
describe('if no .reopenButton is provided', function() { describe('if no .reopenButton is provided', () => {
beforeEach(function() { beforeEach(() => {
this.commentTypeToggle = { testContext.commentTypeToggle = {
dropdownTrigger: {}, dropdownTrigger: {},
dropdownList: {}, dropdownList: {},
noteTypeInput: {}, noteTypeInput: {},
...@@ -137,26 +136,28 @@ describe('CommentTypeToggle', function() { ...@@ -137,26 +136,28 @@ describe('CommentTypeToggle', function() {
closeButton: {}, closeButton: {},
}; };
this.setConfig = CommentTypeToggle.prototype.setConfig.call(this.commentTypeToggle); testContext.setConfig = CommentTypeToggle.prototype.setConfig.call(
testContext.commentTypeToggle,
);
}); });
it('should not add .reopenButton related InputSetter config', function() { it('should not add .reopenButton related InputSetter config', () => {
expect(this.setConfig).toEqual({ expect(testContext.setConfig).toEqual({
InputSetter: [ InputSetter: [
{ {
input: this.commentTypeToggle.noteTypeInput, input: testContext.commentTypeToggle.noteTypeInput,
valueAttribute: 'data-value', valueAttribute: 'data-value',
}, },
{ {
input: this.commentTypeToggle.submitButton, input: testContext.commentTypeToggle.submitButton,
valueAttribute: 'data-submit-text', valueAttribute: 'data-submit-text',
}, },
{ {
input: this.commentTypeToggle.closeButton, input: testContext.commentTypeToggle.closeButton,
valueAttribute: 'data-close-text', valueAttribute: 'data-close-text',
}, },
{ {
input: this.commentTypeToggle.closeButton, input: testContext.commentTypeToggle.closeButton,
valueAttribute: 'data-close-text', valueAttribute: 'data-close-text',
inputAttribute: 'data-alternative-text', inputAttribute: 'data-alternative-text',
}, },
......
import $ from 'jquery'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager'; import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager';
describe('Filtered Search Dropdown Manager', () => { describe('Filtered Search Dropdown Manager', () => {
let mock;
beforeEach(() => { beforeEach(() => {
spyOn($, 'ajax'); mock = new MockAdapter(axios);
mock.onGet().reply(200);
}); });
describe('addWordToInput', () => { describe('addWordToInput', () => {
...@@ -32,7 +36,7 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -32,7 +36,7 @@ describe('Filtered Search Dropdown Manager', () => {
const token = document.querySelector('.tokens-container .js-visual-token'); const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('milestone'); expect(token.querySelector('.name').textContent).toBe('milestone');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
}); });
...@@ -42,7 +46,7 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -42,7 +46,7 @@ describe('Filtered Search Dropdown Manager', () => {
let token = document.querySelector('.tokens-container .js-visual-token'); let token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label'); expect(token.querySelector('.name').textContent).toBe('label');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label', tokenOperator: '=' }); FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label', tokenOperator: '=' });
...@@ -50,8 +54,8 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -50,8 +54,8 @@ describe('Filtered Search Dropdown Manager', () => {
token = document.querySelector('.tokens-container .js-visual-token'); token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label'); expect(token.querySelector('.name').textContent).toBe('label');
expect(token.querySelector('.operator').innerText).toBe('='); expect(token.querySelector('.operator').textContent).toBe('=');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
FilteredSearchDropdownManager.addWordToInput({ FilteredSearchDropdownManager.addWordToInput({
...@@ -64,9 +68,9 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -64,9 +68,9 @@ describe('Filtered Search Dropdown Manager', () => {
token = document.querySelector('.tokens-container .js-visual-token'); token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label'); expect(token.querySelector('.name').textContent).toBe('label');
expect(token.querySelector('.operator').innerText).toBe('='); expect(token.querySelector('.operator').textContent).toBe('=');
expect(token.querySelector('.value').innerText).toBe('none'); expect(token.querySelector('.value').textContent).toBe('none');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
}); });
}); });
...@@ -79,7 +83,7 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -79,7 +83,7 @@ describe('Filtered Search Dropdown Manager', () => {
const token = document.querySelector('.tokens-container .js-visual-token'); const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('author'); expect(token.querySelector('.name').textContent).toBe('author');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
}); });
...@@ -97,9 +101,9 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -97,9 +101,9 @@ describe('Filtered Search Dropdown Manager', () => {
const token = document.querySelector('.tokens-container .js-visual-token'); const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('author'); expect(token.querySelector('.name').textContent).toBe('author');
expect(token.querySelector('.operator').innerText).toBe('='); expect(token.querySelector('.operator').textContent).toBe('=');
expect(token.querySelector('.value').innerText).toBe('@root'); expect(token.querySelector('.value').textContent).toBe('@root');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
}); });
...@@ -116,9 +120,9 @@ describe('Filtered Search Dropdown Manager', () => { ...@@ -116,9 +120,9 @@ describe('Filtered Search Dropdown Manager', () => {
const token = document.querySelector('.tokens-container .js-visual-token'); const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true); expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label'); expect(token.querySelector('.name').textContent).toBe('label');
expect(token.querySelector('.operator').innerText).toBe('='); expect(token.querySelector('.operator').textContent).toBe('=');
expect(token.querySelector('.value').innerText).toBe('~\'"test me"\''); expect(token.querySelector('.value').textContent).toBe('~\'"test me"\'');
expect(getInputValue()).toBe(''); expect(getInputValue()).toBe('');
}); });
}); });
......
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens'; import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper';
describe('Filtered Search Visual Tokens', () => { describe('Filtered Search Visual Tokens', () => {
let mock;
const subject = FilteredSearchVisualTokens; const subject = FilteredSearchVisualTokens;
const findElements = tokenElement => { const findElements = tokenElement => {
...@@ -17,6 +20,9 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -17,6 +20,9 @@ describe('Filtered Search Visual Tokens', () => {
let bugLabelToken; let bugLabelToken;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet().reply(200);
setFixtures(` setFixtures(`
<ul class="tokens-container"> <ul class="tokens-container">
${FilteredSearchSpecHelper.createInputHTML()} ${FilteredSearchSpecHelper.createInputHTML()}
...@@ -248,15 +254,15 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -248,15 +254,15 @@ describe('Filtered Search Visual Tokens', () => {
}); });
it('contains name div', () => { it('contains name div', () => {
expect(tokenElement.querySelector('.name')).toEqual(jasmine.anything()); expect(tokenElement.querySelector('.name')).toEqual(expect.anything());
}); });
it('contains value container div', () => { it('contains value container div', () => {
expect(tokenElement.querySelector('.value-container')).toEqual(jasmine.anything()); expect(tokenElement.querySelector('.value-container')).toEqual(expect.anything());
}); });
it('contains value div', () => { it('contains value div', () => {
expect(tokenElement.querySelector('.value-container .value')).toEqual(jasmine.anything()); expect(tokenElement.querySelector('.value-container .value')).toEqual(expect.anything());
}); });
it('contains selectable class', () => { it('contains selectable class', () => {
...@@ -270,12 +276,12 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -270,12 +276,12 @@ describe('Filtered Search Visual Tokens', () => {
describe('remove token', () => { describe('remove token', () => {
it('contains remove-token button', () => { it('contains remove-token button', () => {
expect(tokenElement.querySelector('.value-container .remove-token')).toEqual( expect(tokenElement.querySelector('.value-container .remove-token')).toEqual(
jasmine.anything(), expect.anything(),
); );
}); });
it('contains fa-close icon', () => { it('contains fa-close icon', () => {
expect(tokenElement.querySelector('.remove-token .fa-close')).toEqual(jasmine.anything()); expect(tokenElement.querySelector('.remove-token .fa-close')).toEqual(expect.anything());
}); });
}); });
}); });
...@@ -453,7 +459,7 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -453,7 +459,7 @@ describe('Filtered Search Visual Tokens', () => {
valueContainer.dataset.originalValue = originalValue; valueContainer.dataset.originalValue = originalValue;
const avatar = document.createElement('img'); const avatar = document.createElement('img');
const valueElement = valueContainer.querySelector('.value'); const valueElement = valueContainer.querySelector('.value');
valueElement.insertAdjacentElement('afterbegin', avatar); valueElement.appendChild(avatar);
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
authorToken.outerHTML, authorToken.outerHTML,
); );
...@@ -573,7 +579,7 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -573,7 +579,7 @@ describe('Filtered Search Visual Tokens', () => {
it("tokenize's existing input", () => { it("tokenize's existing input", () => {
input.value = 'some text'; input.value = 'some text';
spyOn(subject, 'tokenizeInput').and.callThrough(); jest.spyOn(subject, 'tokenizeInput');
subject.editToken(token); subject.editToken(token);
...@@ -635,8 +641,8 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -635,8 +641,8 @@ describe('Filtered Search Visual Tokens', () => {
FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none'), FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none'),
); );
spyOn(subject, 'tokenizeInput').and.callFake(() => {}); jest.spyOn(subject, 'tokenizeInput').mockImplementation(() => {});
spyOn(subject, 'getLastVisualTokenBeforeInput').and.callThrough(); jest.spyOn(subject, 'getLastVisualTokenBeforeInput');
subject.moveInputToTheRight(); subject.moveInputToTheRight();
...@@ -711,12 +717,16 @@ describe('Filtered Search Visual Tokens', () => { ...@@ -711,12 +717,16 @@ describe('Filtered Search Visual Tokens', () => {
it('renders a author token value element', () => { it('renders a author token value element', () => {
const { tokenNameElement, tokenValueElement } = findElements(authorToken); const { tokenNameElement, tokenValueElement } = findElements(authorToken);
const tokenName = tokenNameElement.innerText; const tokenName = tokenNameElement.textContent;
const tokenValue = 'new value'; const tokenValue = 'new value';
subject.renderVisualTokenValue(authorToken, tokenName, tokenValue); subject.renderVisualTokenValue(authorToken, tokenName, tokenValue);
expect(tokenValueElement.innerText).toBe(tokenValue); jest.runOnlyPendingTimers();
setImmediate(() => {
expect(tokenValueElement.textContent).toBe(tokenValue);
});
}); });
}); });
}); });
...@@ -5,51 +5,56 @@ import '~/lib/utils/text_utility'; ...@@ -5,51 +5,56 @@ import '~/lib/utils/text_utility';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
describe('GLForm', () => { describe('GLForm', () => {
describe('when instantiated', function() { const testContext = {};
describe('when instantiated', () => {
beforeEach(done => { beforeEach(done => {
this.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>'); testContext.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>');
this.textarea = this.form.find('textarea'); testContext.textarea = testContext.form.find('textarea');
spyOn($.prototype, 'off').and.returnValue(this.textarea); jest.spyOn($.prototype, 'off').mockReturnValue(testContext.textarea);
spyOn($.prototype, 'on').and.returnValue(this.textarea); jest.spyOn($.prototype, 'on').mockReturnValue(testContext.textarea);
spyOn($.prototype, 'css'); jest.spyOn($.prototype, 'css').mockImplementation(() => {});
this.glForm = new GLForm(this.form, false); testContext.glForm = new GLForm(testContext.form, false);
setTimeout(() => {
$.prototype.off.calls.reset(); setImmediate(() => {
$.prototype.on.calls.reset(); $.prototype.off.mockClear();
$.prototype.css.calls.reset(); $.prototype.on.mockClear();
$.prototype.css.mockClear();
done(); done();
}); });
}); });
describe('setupAutosize', () => { describe('setupAutosize', () => {
beforeEach(done => { beforeEach(done => {
this.glForm.setupAutosize(); testContext.glForm.setupAutosize();
setTimeout(() => {
setImmediate(() => {
done(); done();
}); });
}); });
it('should register an autosize event handler on the textarea', () => { it('should register an autosize event handler on the textarea', () => {
expect($.prototype.off).toHaveBeenCalledWith('autosize:resized'); expect($.prototype.off).toHaveBeenCalledWith('autosize:resized');
expect($.prototype.on).toHaveBeenCalledWith('autosize:resized', jasmine.any(Function)); expect($.prototype.on).toHaveBeenCalledWith('autosize:resized', expect.any(Function));
}); });
it('should register a mouseup event handler on the textarea', () => { it('should register a mouseup event handler on the textarea', () => {
expect($.prototype.off).toHaveBeenCalledWith('mouseup.autosize'); expect($.prototype.off).toHaveBeenCalledWith('mouseup.autosize');
expect($.prototype.on).toHaveBeenCalledWith('mouseup.autosize', jasmine.any(Function)); expect($.prototype.on).toHaveBeenCalledWith('mouseup.autosize', expect.any(Function));
}); });
it('should set the resize css property to vertical', () => { it('should set the resize css property to vertical', () => {
jest.runOnlyPendingTimers();
expect($.prototype.css).toHaveBeenCalledWith('resize', 'vertical'); expect($.prototype.css).toHaveBeenCalledWith('resize', 'vertical');
}); });
}); });
describe('setHeightData', () => { describe('setHeightData', () => {
beforeEach(() => { beforeEach(() => {
spyOn($.prototype, 'data'); jest.spyOn($.prototype, 'data').mockImplementation(() => {});
spyOn($.prototype, 'outerHeight').and.returnValue(200); jest.spyOn($.prototype, 'outerHeight').mockReturnValue(200);
this.glForm.setHeightData(); testContext.glForm.setHeightData();
}); });
it('should set the height data attribute', () => { it('should set the height data attribute', () => {
...@@ -64,12 +69,12 @@ describe('GLForm', () => { ...@@ -64,12 +69,12 @@ describe('GLForm', () => {
describe('destroyAutosize', () => { describe('destroyAutosize', () => {
describe('when called', () => { describe('when called', () => {
beforeEach(() => { beforeEach(() => {
spyOn($.prototype, 'data'); jest.spyOn($.prototype, 'data').mockImplementation(() => {});
spyOn($.prototype, 'outerHeight').and.returnValue(200); jest.spyOn($.prototype, 'outerHeight').mockReturnValue(200);
spyOn(window, 'outerHeight').and.returnValue(400); window.outerHeight = () => 400;
spyOn(autosize, 'destroy'); jest.spyOn(autosize, 'destroy').mockImplementation(() => {});
this.glForm.destroyAutosize(); testContext.glForm.destroyAutosize();
}); });
it('should call outerHeight', () => { it('should call outerHeight', () => {
...@@ -81,7 +86,7 @@ describe('GLForm', () => { ...@@ -81,7 +86,7 @@ describe('GLForm', () => {
}); });
it('should call autosize destroy', () => { it('should call autosize destroy', () => {
expect(autosize.destroy).toHaveBeenCalledWith(this.textarea); expect(autosize.destroy).toHaveBeenCalledWith(testContext.textarea);
}); });
it('should set the data-height attribute', () => { it('should set the data-height attribute', () => {
...@@ -98,11 +103,11 @@ describe('GLForm', () => { ...@@ -98,11 +103,11 @@ describe('GLForm', () => {
}); });
it('should return undefined if the data-height equals the outerHeight', () => { it('should return undefined if the data-height equals the outerHeight', () => {
spyOn($.prototype, 'outerHeight').and.returnValue(200); jest.spyOn($.prototype, 'outerHeight').mockReturnValue(200);
spyOn($.prototype, 'data').and.returnValue(200); jest.spyOn($.prototype, 'data').mockReturnValue(200);
spyOn(autosize, 'destroy'); jest.spyOn(autosize, 'destroy').mockImplementation(() => {});
expect(this.glForm.destroyAutosize()).toBeUndefined(); expect(testContext.glForm.destroyAutosize()).toBeUndefined();
expect(autosize.destroy).not.toHaveBeenCalled(); expect(autosize.destroy).not.toHaveBeenCalled();
}); });
}); });
......
...@@ -28,7 +28,7 @@ describe('Global search input dropdown', () => { ...@@ -28,7 +28,7 @@ describe('Global search input dropdown', () => {
const groupName = 'Gitlab Org'; const groupName = 'Gitlab Org';
const removeBodyAttributes = function() { const removeBodyAttributes = () => {
const $body = $('body'); const $body = $('body');
$body.removeAttr('data-page'); $body.removeAttr('data-page');
...@@ -38,7 +38,7 @@ describe('Global search input dropdown', () => { ...@@ -38,7 +38,7 @@ describe('Global search input dropdown', () => {
// Add required attributes to body before starting the test. // Add required attributes to body before starting the test.
// section would be dashboard|group|project // section would be dashboard|group|project
const addBodyAttributes = function(section) { const addBodyAttributes = section => {
if (section == null) { if (section == null) {
section = 'dashboard'; section = 'dashboard';
} }
...@@ -57,12 +57,12 @@ describe('Global search input dropdown', () => { ...@@ -57,12 +57,12 @@ describe('Global search input dropdown', () => {
} }
}; };
const disableProjectIssues = function() { const disableProjectIssues = () => {
document.querySelector('.js-search-project-options').setAttribute('data-issues-disabled', true); document.querySelector('.js-search-project-options').setAttribute('data-issues-disabled', true);
}; };
// Mock `gl` object in window for dashboard specific page. App code will need it. // Mock `gl` object in window for dashboard specific page. App code will need it.
const mockDashboardOptions = function() { const mockDashboardOptions = () => {
window.gl || (window.gl = {}); window.gl || (window.gl = {});
return (window.gl.dashboardOptions = { return (window.gl.dashboardOptions = {
issuesPath: dashboardIssuesPath, issuesPath: dashboardIssuesPath,
...@@ -71,7 +71,7 @@ describe('Global search input dropdown', () => { ...@@ -71,7 +71,7 @@ describe('Global search input dropdown', () => {
}; };
// Mock `gl` object in window for project specific page. App code will need it. // Mock `gl` object in window for project specific page. App code will need it.
const mockProjectOptions = function() { const mockProjectOptions = () => {
window.gl || (window.gl = {}); window.gl || (window.gl = {});
return (window.gl.projectOptions = { return (window.gl.projectOptions = {
'gitlab-ce': { 'gitlab-ce': {
...@@ -82,7 +82,7 @@ describe('Global search input dropdown', () => { ...@@ -82,7 +82,7 @@ describe('Global search input dropdown', () => {
}); });
}; };
const mockGroupOptions = function() { const mockGroupOptions = () => {
window.gl || (window.gl = {}); window.gl || (window.gl = {});
return (window.gl.groupOptions = { return (window.gl.groupOptions = {
'gitlab-org': { 'gitlab-org': {
...@@ -93,7 +93,7 @@ describe('Global search input dropdown', () => { ...@@ -93,7 +93,7 @@ describe('Global search input dropdown', () => {
}); });
}; };
const assertLinks = function(list, issuesPath, mrsPath) { const assertLinks = (list, issuesPath, mrsPath) => {
if (issuesPath) { if (issuesPath) {
const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_username=${userName}"]`; const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_username=${userName}"]`;
const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_username=${userName}"]`; const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_username=${userName}"]`;
...@@ -113,7 +113,7 @@ describe('Global search input dropdown', () => { ...@@ -113,7 +113,7 @@ describe('Global search input dropdown', () => {
}; };
preloadFixtures('static/global_search_input.html'); preloadFixtures('static/global_search_input.html');
beforeEach(function() { beforeEach(() => {
loadFixtures('static/global_search_input.html'); loadFixtures('static/global_search_input.html');
window.gon = {}; window.gon = {};
...@@ -123,13 +123,13 @@ describe('Global search input dropdown', () => { ...@@ -123,13 +123,13 @@ describe('Global search input dropdown', () => {
return (widget = initGlobalSearchInput()); return (widget = initGlobalSearchInput());
}); });
afterEach(function() { afterEach(() => {
// Undo what we did to the shared <body> // Undo what we did to the shared <body>
removeBodyAttributes(); removeBodyAttributes();
window.gon = {}; window.gon = {};
}); });
it('should show Dashboard specific dropdown menu', function() { it('should show Dashboard specific dropdown menu', () => {
addBodyAttributes(); addBodyAttributes();
mockDashboardOptions(); mockDashboardOptions();
widget.searchInput.triggerHandler('focus'); widget.searchInput.triggerHandler('focus');
...@@ -137,7 +137,7 @@ describe('Global search input dropdown', () => { ...@@ -137,7 +137,7 @@ describe('Global search input dropdown', () => {
return assertLinks(list, dashboardIssuesPath, dashboardMRsPath); return assertLinks(list, dashboardIssuesPath, dashboardMRsPath);
}); });
it('should show Group specific dropdown menu', function() { it('should show Group specific dropdown menu', () => {
addBodyAttributes('group'); addBodyAttributes('group');
mockGroupOptions(); mockGroupOptions();
widget.searchInput.triggerHandler('focus'); widget.searchInput.triggerHandler('focus');
...@@ -145,7 +145,7 @@ describe('Global search input dropdown', () => { ...@@ -145,7 +145,7 @@ describe('Global search input dropdown', () => {
return assertLinks(list, groupIssuesPath, groupMRsPath); return assertLinks(list, groupIssuesPath, groupMRsPath);
}); });
it('should show Project specific dropdown menu', function() { it('should show Project specific dropdown menu', () => {
addBodyAttributes('project'); addBodyAttributes('project');
mockProjectOptions(); mockProjectOptions();
widget.searchInput.triggerHandler('focus'); widget.searchInput.triggerHandler('focus');
...@@ -153,7 +153,7 @@ describe('Global search input dropdown', () => { ...@@ -153,7 +153,7 @@ describe('Global search input dropdown', () => {
return assertLinks(list, projectIssuesPath, projectMRsPath); return assertLinks(list, projectIssuesPath, projectMRsPath);
}); });
it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() { it('should show only Project mergeRequest dropdown menu items when project issues are disabled', () => {
addBodyAttributes('project'); addBodyAttributes('project');
disableProjectIssues(); disableProjectIssues();
mockProjectOptions(); mockProjectOptions();
...@@ -162,7 +162,7 @@ describe('Global search input dropdown', () => { ...@@ -162,7 +162,7 @@ describe('Global search input dropdown', () => {
assertLinks(list, null, projectMRsPath); assertLinks(list, null, projectMRsPath);
}); });
it('should not show category related menu if there is text in the input', function() { it('should not show category related menu if there is text in the input', () => {
addBodyAttributes('project'); addBodyAttributes('project');
mockProjectOptions(); mockProjectOptions();
widget.searchInput.val('help'); widget.searchInput.val('help');
...@@ -173,12 +173,12 @@ describe('Global search input dropdown', () => { ...@@ -173,12 +173,12 @@ describe('Global search input dropdown', () => {
expect(list.find(link).length).toBe(0); expect(list.find(link).length).toBe(0);
}); });
it('should not submit the search form when selecting an autocomplete row with the keyboard', function() { it('should not submit the search form when selecting an autocomplete row with the keyboard', () => {
const ENTER = 13; const ENTER = 13;
const DOWN = 40; const DOWN = 40;
addBodyAttributes(); addBodyAttributes();
mockDashboardOptions(true); mockDashboardOptions(true);
const submitSpy = spyOnEvent('form', 'submit'); const submitSpy = jest.spyOn(document.querySelector('form'), 'submit');
widget.searchInput.triggerHandler('focus'); widget.searchInput.triggerHandler('focus');
widget.wrap.trigger($.Event('keydown', { which: DOWN })); widget.wrap.trigger($.Event('keydown', { which: DOWN }));
const enterKeyEvent = $.Event('keydown', { which: ENTER }); const enterKeyEvent = $.Event('keydown', { which: ENTER });
...@@ -186,16 +186,16 @@ describe('Global search input dropdown', () => { ...@@ -186,16 +186,16 @@ describe('Global search input dropdown', () => {
// This does not currently catch failing behavior. For security reasons, // This does not currently catch failing behavior. For security reasons,
// browsers will not trigger default behavior (form submit, in this // browsers will not trigger default behavior (form submit, in this
// example) on JavaScript-created keypresses. // example) on JavaScript-created keypresses.
expect(submitSpy).not.toHaveBeenTriggered(); expect(submitSpy).not.toHaveBeenCalled();
}); });
describe('disableDropdown', function() { describe('disableDropdown', () => {
beforeEach(function() { beforeEach(() => {
widget.enableDropdown(); widget.enableDropdown();
}); });
it('should close the Dropdown', function() { it('should close the Dropdown', () => {
const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown'); const toggleSpy = jest.spyOn(widget.dropdownToggle, 'dropdown');
widget.dropdown.addClass('show'); widget.dropdown.addClass('show');
widget.disableDropdown(); widget.disableDropdown();
...@@ -204,9 +204,9 @@ describe('Global search input dropdown', () => { ...@@ -204,9 +204,9 @@ describe('Global search input dropdown', () => {
}); });
}); });
describe('enableDropdown', function() { describe('enableDropdown', () => {
it('should open the Dropdown', function() { it('should open the Dropdown', () => {
const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown'); const toggleSpy = jest.spyOn(widget.dropdownToggle, 'dropdown');
widget.enableDropdown(); widget.enableDropdown();
expect(toggleSpy).toHaveBeenCalledWith('toggle'); expect(toggleSpy).toHaveBeenCalledWith('toggle');
......
...@@ -21,7 +21,9 @@ function testLabelClicks(labelOrder, done) { ...@@ -21,7 +21,9 @@ function testLabelClicks(labelOrder, done) {
.get(0) .get(0)
.click(); .click();
setTimeout(() => { jest.runOnlyPendingTimers();
setImmediate(() => {
const labelsInDropdown = $('.dropdown-content a'); const labelsInDropdown = $('.dropdown-content a');
expect(labelsInDropdown.length).toBe(10); expect(labelsInDropdown.length).toBe(10);
...@@ -38,11 +40,11 @@ function testLabelClicks(labelOrder, done) { ...@@ -38,11 +40,11 @@ function testLabelClicks(labelOrder, done) {
.get(0) .get(0)
.click(); .click();
setTimeout(() => { setImmediate(() => {
expect($('.sidebar-collapsed-icon').attr('data-original-title')).toBe(labelOrder); expect($('.sidebar-collapsed-icon').attr('data-original-title')).toBe(labelOrder);
done(); done();
}, 0); });
}, 0); });
} }
describe('Issue dropdown sidebar', () => { describe('Issue dropdown sidebar', () => {
......
/* eslint-disable dot-notation, no-return-assign, no-new, no-underscore-dangle */ /* eslint-disable no-return-assign, no-new, no-underscore-dangle */
import $ from 'jquery'; import $ from 'jquery';
import LineHighlighter from '~/line_highlighter'; import LineHighlighter from '~/line_highlighter';
describe('LineHighlighter', function() { describe('LineHighlighter', () => {
const testContext = {};
preloadFixtures('static/line_highlighter.html'); preloadFixtures('static/line_highlighter.html');
const clickLine = function(number, eventData = {}) { const clickLine = (number, eventData = {}) => {
if ($.isEmptyObject(eventData)) { if ($.isEmptyObject(eventData)) {
return $(`#L${number}`).click(); return $(`#L${number}`).click();
} }
const e = $.Event('click', eventData); const e = $.Event('click', eventData);
return $(`#L${number}`).trigger(e); return $(`#L${number}`).trigger(e);
}; };
beforeEach(function() { beforeEach(() => {
loadFixtures('static/line_highlighter.html'); loadFixtures('static/line_highlighter.html');
this['class'] = new LineHighlighter(); testContext.class = new LineHighlighter();
this.css = this['class'].highlightLineClass; testContext.css = testContext.class.highlightLineClass;
return (this.spies = { return (testContext.spies = {
__setLocationHash__: spyOn(this['class'], '__setLocationHash__').and.callFake(function() {}), __setLocationHash__: jest
.spyOn(testContext.class, '__setLocationHash__')
.mockImplementation(() => {}),
}); });
}); });
describe('behavior', function() { describe('behavior', () => {
it('highlights one line given in the URL hash', function() { it('highlights one line given in the URL hash', () => {
new LineHighlighter({ hash: '#L13' }); new LineHighlighter({ hash: '#L13' });
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
}); });
it('highlights one line given in the URL hash with given CSS class name', function() { it('highlights one line given in the URL hash with given CSS class name', () => {
const hiliter = new LineHighlighter({ hash: '#L13', highlightLineClass: 'hilite' }); const hiliter = new LineHighlighter({ hash: '#L13', highlightLineClass: 'hilite' });
expect(hiliter.highlightLineClass).toBe('hilite'); expect(hiliter.highlightLineClass).toBe('hilite');
...@@ -36,31 +40,34 @@ describe('LineHighlighter', function() { ...@@ -36,31 +40,34 @@ describe('LineHighlighter', function() {
expect($('#LC13')).not.toHaveClass('hll'); expect($('#LC13')).not.toHaveClass('hll');
}); });
it('highlights a range of lines given in the URL hash', function() { it('highlights a range of lines given in the URL hash', () => {
new LineHighlighter({ hash: '#L5-25' }); new LineHighlighter({ hash: '#L5-25' });
expect($(`.${this.css}`).length).toBe(21); expect($(`.${testContext.css}`).length).toBe(21);
for (let line = 5; line <= 25; line += 1) { for (let line = 5; line <= 25; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css); expect($(`#LC${line}`)).toHaveClass(testContext.css);
} }
}); });
it('scrolls to the first highlighted line on initial load', function() { it('scrolls to the first highlighted line on initial load', () => {
const spy = spyOn($, 'scrollTo'); const spy = jest.spyOn($, 'scrollTo');
new LineHighlighter({ hash: '#L5-25' }); new LineHighlighter({ hash: '#L5-25' });
expect(spy).toHaveBeenCalledWith('#L5', jasmine.anything()); expect(spy).toHaveBeenCalledWith('#L5', expect.anything());
}); });
it('discards click events', function() { it('discards click events', () => {
const spy = spyOnEvent('a[data-line-number]', 'click'); const clickSpy = jest.fn();
$('a[data-line-number]').click(clickSpy);
clickLine(13); clickLine(13);
expect(spy).toHaveBeenPrevented(); expect(clickSpy.mock.calls[0][0].isDefaultPrevented()).toEqual(true);
}); });
it('handles garbage input from the hash', function() { it('handles garbage input from the hash', () => {
const func = function() { const func = () => {
return new LineHighlighter({ fileHolderSelector: '#blob-content-holder' }); return new LineHighlighter({ fileHolderSelector: '#blob-content-holder' });
}; };
...@@ -70,7 +77,7 @@ describe('LineHighlighter', function() { ...@@ -70,7 +77,7 @@ describe('LineHighlighter', function() {
it('handles hashchange event', () => { it('handles hashchange event', () => {
const highlighter = new LineHighlighter(); const highlighter = new LineHighlighter();
spyOn(highlighter, 'highlightHash'); jest.spyOn(highlighter, 'highlightHash').mockImplementation(() => {});
window.dispatchEvent(new Event('hashchange'), 'L15'); window.dispatchEvent(new Event('hashchange'), 'L15');
...@@ -78,43 +85,43 @@ describe('LineHighlighter', function() { ...@@ -78,43 +85,43 @@ describe('LineHighlighter', function() {
}); });
}); });
describe('clickHandler', function() { describe('clickHandler', () => {
it('handles clicking on a child icon element', function() { it('handles clicking on a child icon element', () => {
const spy = spyOn(this['class'], 'setHash').and.callThrough(); const spy = jest.spyOn(testContext.class, 'setHash');
$('#L13 i') $('#L13 i')
.mousedown() .mousedown()
.click(); .click();
expect(spy).toHaveBeenCalledWith(13); expect(spy).toHaveBeenCalledWith(13);
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
}); });
describe('without shiftKey', function() { describe('without shiftKey', () => {
it('highlights one line when clicked', function() { it('highlights one line when clicked', () => {
clickLine(13); clickLine(13);
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
}); });
it('unhighlights previously highlighted lines', function() { it('unhighlights previously highlighted lines', () => {
clickLine(13); clickLine(13);
clickLine(20); clickLine(20);
expect($('#LC13')).not.toHaveClass(this.css); expect($('#LC13')).not.toHaveClass(testContext.css);
expect($('#LC20')).toHaveClass(this.css); expect($('#LC20')).toHaveClass(testContext.css);
}); });
it('sets the hash', function() { it('sets the hash', () => {
const spy = spyOn(this['class'], 'setHash').and.callThrough(); const spy = jest.spyOn(testContext.class, 'setHash');
clickLine(13); clickLine(13);
expect(spy).toHaveBeenCalledWith(13); expect(spy).toHaveBeenCalledWith(13);
}); });
}); });
describe('with shiftKey', function() { describe('with shiftKey', () => {
it('sets the hash', function() { it('sets the hash', () => {
const spy = spyOn(this['class'], 'setHash').and.callThrough(); const spy = jest.spyOn(testContext.class, 'setHash');
clickLine(13); clickLine(13);
clickLine(20, { clickLine(20, {
shiftKey: true, shiftKey: true,
...@@ -124,18 +131,18 @@ describe('LineHighlighter', function() { ...@@ -124,18 +131,18 @@ describe('LineHighlighter', function() {
expect(spy).toHaveBeenCalledWith(13, 20); expect(spy).toHaveBeenCalledWith(13, 20);
}); });
describe('without existing highlight', function() { describe('without existing highlight', () => {
it('highlights the clicked line', function() { it('highlights the clicked line', () => {
clickLine(13, { clickLine(13, {
shiftKey: true, shiftKey: true,
}); });
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
expect($(`.${this.css}`).length).toBe(1); expect($(`.${testContext.css}`).length).toBe(1);
}); });
it('sets the hash', function() { it('sets the hash', () => {
const spy = spyOn(this['class'], 'setHash'); const spy = jest.spyOn(testContext.class, 'setHash');
clickLine(13, { clickLine(13, {
shiftKey: true, shiftKey: true,
}); });
...@@ -144,34 +151,34 @@ describe('LineHighlighter', function() { ...@@ -144,34 +151,34 @@ describe('LineHighlighter', function() {
}); });
}); });
describe('with existing single-line highlight', function() { describe('with existing single-line highlight', () => {
it('uses existing line as last line when target is lesser', function() { it('uses existing line as last line when target is lesser', () => {
clickLine(20); clickLine(20);
clickLine(15, { clickLine(15, {
shiftKey: true, shiftKey: true,
}); });
expect($(`.${this.css}`).length).toBe(6); expect($(`.${testContext.css}`).length).toBe(6);
for (let line = 15; line <= 20; line += 1) { for (let line = 15; line <= 20; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css); expect($(`#LC${line}`)).toHaveClass(testContext.css);
} }
}); });
it('uses existing line as first line when target is greater', function() { it('uses existing line as first line when target is greater', () => {
clickLine(5); clickLine(5);
clickLine(10, { clickLine(10, {
shiftKey: true, shiftKey: true,
}); });
expect($(`.${this.css}`).length).toBe(6); expect($(`.${testContext.css}`).length).toBe(6);
for (let line = 5; line <= 10; line += 1) { for (let line = 5; line <= 10; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css); expect($(`#LC${line}`)).toHaveClass(testContext.css);
} }
}); });
}); });
describe('with existing multi-line highlight', function() { describe('with existing multi-line highlight', () => {
beforeEach(function() { beforeEach(() => {
clickLine(10, { clickLine(10, {
shiftKey: true, shiftKey: true,
}); });
...@@ -180,82 +187,82 @@ describe('LineHighlighter', function() { ...@@ -180,82 +187,82 @@ describe('LineHighlighter', function() {
}); });
}); });
it('uses target as first line when it is less than existing first line', function() { it('uses target as first line when it is less than existing first line', () => {
clickLine(5, { clickLine(5, {
shiftKey: true, shiftKey: true,
}); });
expect($(`.${this.css}`).length).toBe(6); expect($(`.${testContext.css}`).length).toBe(6);
for (let line = 5; line <= 10; line += 1) { for (let line = 5; line <= 10; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css); expect($(`#LC${line}`)).toHaveClass(testContext.css);
} }
}); });
it('uses target as last line when it is greater than existing first line', function() { it('uses target as last line when it is greater than existing first line', () => {
clickLine(15, { clickLine(15, {
shiftKey: true, shiftKey: true,
}); });
expect($(`.${this.css}`).length).toBe(6); expect($(`.${testContext.css}`).length).toBe(6);
for (let line = 10; line <= 15; line += 1) { for (let line = 10; line <= 15; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css); expect($(`#LC${line}`)).toHaveClass(testContext.css);
} }
}); });
}); });
}); });
}); });
describe('hashToRange', function() { describe('hashToRange', () => {
beforeEach(function() { beforeEach(() => {
this.subject = this['class'].hashToRange; testContext.subject = testContext.class.hashToRange;
}); });
it('extracts a single line number from the hash', function() { it('extracts a single line number from the hash', () => {
expect(this.subject('#L5')).toEqual([5, null]); expect(testContext.subject('#L5')).toEqual([5, null]);
}); });
it('extracts a range of line numbers from the hash', function() { it('extracts a range of line numbers from the hash', () => {
expect(this.subject('#L5-15')).toEqual([5, 15]); expect(testContext.subject('#L5-15')).toEqual([5, 15]);
}); });
it('returns [null, null] when the hash is not a line number', function() { it('returns [null, null] when the hash is not a line number', () => {
expect(this.subject('#foo')).toEqual([null, null]); expect(testContext.subject('#foo')).toEqual([null, null]);
}); });
}); });
describe('highlightLine', function() { describe('highlightLine', () => {
beforeEach(function() { beforeEach(() => {
this.subject = this['class'].highlightLine; testContext.subject = testContext.class.highlightLine;
}); });
it('highlights the specified line', function() { it('highlights the specified line', () => {
this.subject(13); testContext.subject(13);
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
}); });
it('accepts a String-based number', function() { it('accepts a String-based number', () => {
this.subject('13'); testContext.subject('13');
expect($('#LC13')).toHaveClass(this.css); expect($('#LC13')).toHaveClass(testContext.css);
}); });
}); });
describe('setHash', function() { describe('setHash', () => {
beforeEach(function() { beforeEach(() => {
this.subject = this['class'].setHash; testContext.subject = testContext.class.setHash;
}); });
it('sets the location hash for a single line', function() { it('sets the location hash for a single line', () => {
this.subject(5); testContext.subject(5);
expect(this.spies.__setLocationHash__).toHaveBeenCalledWith('#L5'); expect(testContext.spies.__setLocationHash__).toHaveBeenCalledWith('#L5');
}); });
it('sets the location hash for a range', function() { it('sets the location hash for a range', () => {
this.subject(5, 15); testContext.subject(5, 15);
expect(this.spies.__setLocationHash__).toHaveBeenCalledWith('#L5-15'); expect(testContext.spies.__setLocationHash__).toHaveBeenCalledWith('#L5-15');
}); });
}); });
}); });
...@@ -5,12 +5,16 @@ import MergeRequestTabs from '~/merge_request_tabs'; ...@@ -5,12 +5,16 @@ import MergeRequestTabs from '~/merge_request_tabs';
import '~/commit/pipelines/pipelines_bundle'; import '~/commit/pipelines/pipelines_bundle';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
import 'vendor/jquery.scrollTo'; import 'vendor/jquery.scrollTo';
import initMrPage from './helpers/init_vue_mr_page_helper'; import initMrPage from '../javascripts/helpers/init_vue_mr_page_helper';
describe('MergeRequestTabs', function() { jest.mock('~/lib/utils/webpack', () => ({
let mrPageMock; resetServiceWorkersPublicPath: jest.fn(),
}));
describe('MergeRequestTabs', () => {
const testContext = {};
const stubLocation = {}; const stubLocation = {};
const setLocation = function(stubs) { const setLocation = stubs => {
const defaults = { const defaults = {
pathname: '', pathname: '',
search: '', search: '',
...@@ -24,29 +28,25 @@ describe('MergeRequestTabs', function() { ...@@ -24,29 +28,25 @@ describe('MergeRequestTabs', function() {
'merge_requests/diff_comment.html', 'merge_requests/diff_comment.html',
); );
beforeEach(function() { beforeEach(() => {
mrPageMock = initMrPage(); initMrPage();
this.class = new MergeRequestTabs({ stubLocation });
testContext.class = new MergeRequestTabs({ stubLocation });
setLocation(); setLocation();
this.spies = { testContext.spies = {
history: spyOn(window.history, 'pushState').and.callFake(function() {}), history: jest.spyOn(window.history, 'pushState').mockImplementation(() => {}),
}; };
});
afterEach(function() { gl.mrWidget = {};
this.class.unbindEvents();
this.class.destroyPipelinesView();
mrPageMock.restore();
$('.js-merge-request-test').remove();
}); });
describe('opensInNewTab', function() { describe('opensInNewTab', () => {
const windowTarget = '_blank'; const windowTarget = '_blank';
let clickTabParams; let clickTabParams;
let tabUrl; let tabUrl;
beforeEach(function() { beforeEach(() => {
loadFixtures('merge_requests/merge_request_with_task_list.html'); loadFixtures('merge_requests/merge_request_with_task_list.html');
tabUrl = $('.commits-tab a').attr('href'); tabUrl = $('.commits-tab a').attr('href');
...@@ -68,76 +68,76 @@ describe('MergeRequestTabs', function() { ...@@ -68,76 +68,76 @@ describe('MergeRequestTabs', function() {
describe('meta click', () => { describe('meta click', () => {
let metakeyEvent; let metakeyEvent;
beforeEach(function() { beforeEach(() => {
metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true }); metakeyEvent = $.Event('click', { keyCode: 91, ctrlKey: true });
}); });
it('opens page when commits link is clicked', function() { it('opens page when commits link is clicked', () => {
spyOn(window, 'open').and.callFake(function(url, name) { jest.spyOn(window, 'open').mockImplementation((url, name) => {
expect(url).toEqual(tabUrl); expect(url).toEqual(tabUrl);
expect(name).toEqual(windowTarget); expect(name).toEqual(windowTarget);
}); });
this.class.bindEvents(); testContext.class.bindEvents();
$('.merge-request-tabs .commits-tab a').trigger(metakeyEvent); $('.merge-request-tabs .commits-tab a').trigger(metakeyEvent);
expect(window.open).toHaveBeenCalled(); expect(window.open).toHaveBeenCalled();
}); });
it('opens page when commits badge is clicked', function() { it('opens page when commits badge is clicked', () => {
spyOn(window, 'open').and.callFake(function(url, name) { jest.spyOn(window, 'open').mockImplementation((url, name) => {
expect(url).toEqual(tabUrl); expect(url).toEqual(tabUrl);
expect(name).toEqual(windowTarget); expect(name).toEqual(windowTarget);
}); });
this.class.bindEvents(); testContext.class.bindEvents();
$('.merge-request-tabs .commits-tab a .badge').trigger(metakeyEvent); $('.merge-request-tabs .commits-tab a .badge').trigger(metakeyEvent);
expect(window.open).toHaveBeenCalled(); expect(window.open).toHaveBeenCalled();
}); });
}); });
it('opens page tab in a new browser tab with Ctrl+Click - Windows/Linux', function() { it('opens page tab in a new browser tab with Ctrl+Click - Windows/Linux', () => {
spyOn(window, 'open').and.callFake(function(url, name) { jest.spyOn(window, 'open').mockImplementation((url, name) => {
expect(url).toEqual(tabUrl); expect(url).toEqual(tabUrl);
expect(name).toEqual(windowTarget); expect(name).toEqual(windowTarget);
}); });
this.class.clickTab({ ...clickTabParams, metaKey: true }); testContext.class.clickTab({ ...clickTabParams, metaKey: true });
expect(window.open).toHaveBeenCalled(); expect(window.open).toHaveBeenCalled();
}); });
it('opens page tab in a new browser tab with Cmd+Click - Mac', function() { it('opens page tab in a new browser tab with Cmd+Click - Mac', () => {
spyOn(window, 'open').and.callFake(function(url, name) { jest.spyOn(window, 'open').mockImplementation((url, name) => {
expect(url).toEqual(tabUrl); expect(url).toEqual(tabUrl);
expect(name).toEqual(windowTarget); expect(name).toEqual(windowTarget);
}); });
this.class.clickTab({ ...clickTabParams, ctrlKey: true }); testContext.class.clickTab({ ...clickTabParams, ctrlKey: true });
expect(window.open).toHaveBeenCalled(); expect(window.open).toHaveBeenCalled();
}); });
it('opens page tab in a new browser tab with Middle-click - Mac/PC', function() { it('opens page tab in a new browser tab with Middle-click - Mac/PC', () => {
spyOn(window, 'open').and.callFake(function(url, name) { jest.spyOn(window, 'open').mockImplementation((url, name) => {
expect(url).toEqual(tabUrl); expect(url).toEqual(tabUrl);
expect(name).toEqual(windowTarget); expect(name).toEqual(windowTarget);
}); });
this.class.clickTab({ ...clickTabParams, which: 2 }); testContext.class.clickTab({ ...clickTabParams, which: 2 });
expect(window.open).toHaveBeenCalled(); expect(window.open).toHaveBeenCalled();
}); });
}); });
describe('setCurrentAction', function() { describe('setCurrentAction', () => {
let mock; let mock;
beforeEach(function() { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock.onAny().reply({ data: {} }); mock.onAny().reply({ data: {} });
this.subject = this.class.setCurrentAction; testContext.subject = testContext.class.setCurrentAction;
}); });
afterEach(() => { afterEach(() => {
...@@ -145,53 +145,53 @@ describe('MergeRequestTabs', function() { ...@@ -145,53 +145,53 @@ describe('MergeRequestTabs', function() {
window.history.replaceState({}, '', '/'); window.history.replaceState({}, '', '/');
}); });
it('changes from commits', function() { it('changes from commits', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1/commits', pathname: '/foo/bar/-/merge_requests/1/commits',
}); });
expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1'); expect(testContext.subject('show')).toBe('/foo/bar/-/merge_requests/1');
expect(this.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs'); expect(testContext.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs');
}); });
it('changes from diffs', function() { it('changes from diffs', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1/diffs', pathname: '/foo/bar/-/merge_requests/1/diffs',
}); });
expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1'); expect(testContext.subject('show')).toBe('/foo/bar/-/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits'); expect(testContext.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
}); });
it('changes from diffs.html', function() { it('changes from diffs.html', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1/diffs.html', pathname: '/foo/bar/-/merge_requests/1/diffs.html',
}); });
expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1'); expect(testContext.subject('show')).toBe('/foo/bar/-/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits'); expect(testContext.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
}); });
it('changes from notes', function() { it('changes from notes', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1', pathname: '/foo/bar/-/merge_requests/1',
}); });
expect(this.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs'); expect(testContext.subject('diffs')).toBe('/foo/bar/-/merge_requests/1/diffs');
expect(this.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits'); expect(testContext.subject('commits')).toBe('/foo/bar/-/merge_requests/1/commits');
}); });
it('includes search parameters and hash string', function() { it('includes search parameters and hash string', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1/diffs', pathname: '/foo/bar/-/merge_requests/1/diffs',
search: '?view=parallel', search: '?view=parallel',
hash: '#L15-35', hash: '#L15-35',
}); });
expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1?view=parallel#L15-35'); expect(testContext.subject('show')).toBe('/foo/bar/-/merge_requests/1?view=parallel#L15-35');
}); });
it('replaces the current history state', function() { it('replaces the current history state', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1', pathname: '/foo/bar/-/merge_requests/1',
}); });
...@@ -204,9 +204,9 @@ describe('MergeRequestTabs', function() { ...@@ -204,9 +204,9 @@ describe('MergeRequestTabs', function() {
window.location.href, window.location.href,
); );
const newState = this.subject('commits'); const newState = testContext.subject('commits');
expect(this.spies.history).toHaveBeenCalledWith( expect(testContext.spies.history).toHaveBeenCalledWith(
{ {
url: newState, url: newState,
action: 'commits', action: 'commits',
...@@ -216,16 +216,16 @@ describe('MergeRequestTabs', function() { ...@@ -216,16 +216,16 @@ describe('MergeRequestTabs', function() {
); );
}); });
it('treats "show" like "notes"', function() { it('treats "show" like "notes"', () => {
setLocation({ setLocation({
pathname: '/foo/bar/-/merge_requests/1/commits', pathname: '/foo/bar/-/merge_requests/1/commits',
}); });
expect(this.subject('show')).toBe('/foo/bar/-/merge_requests/1'); expect(testContext.subject('show')).toBe('/foo/bar/-/merge_requests/1');
}); });
}); });
describe('expandViewContainer', function() { describe('expandViewContainer', () => {
beforeEach(() => { beforeEach(() => {
$('body').append( $('body').append(
'<div class="content-wrapper"><div class="container-fluid container-limited"></div></div>', '<div class="content-wrapper"><div class="container-fluid container-limited"></div></div>',
...@@ -236,59 +236,58 @@ describe('MergeRequestTabs', function() { ...@@ -236,59 +236,58 @@ describe('MergeRequestTabs', function() {
$('.content-wrapper').remove(); $('.content-wrapper').remove();
}); });
it('removes container-limited from containers', function() { it('removes container-limited from containers', () => {
this.class.expandViewContainer(); testContext.class.expandViewContainer();
expect($('.content-wrapper')).not.toContainElement('.container-limited'); expect($('.content-wrapper .container-limited')).toHaveLength(0);
}); });
it('does not add container-limited when fluid layout is prefered', function() { it('does not add container-limited when fluid layout is prefered', () => {
$('.content-wrapper .container-fluid').removeClass('container-limited'); $('.content-wrapper .container-fluid').removeClass('container-limited');
this.class.expandViewContainer(false); testContext.class.expandViewContainer(false);
expect($('.content-wrapper')).not.toContainElement('.container-limited'); expect($('.content-wrapper .container-limited')).toHaveLength(0);
}); });
it('does remove container-limited from breadcrumbs', function() { it('does remove container-limited from breadcrumbs', () => {
$('.container-limited').addClass('breadcrumbs'); $('.container-limited').addClass('breadcrumbs');
this.class.expandViewContainer(); testContext.class.expandViewContainer();
expect($('.content-wrapper')).toContainElement('.container-limited'); expect($('.content-wrapper .container-limited')).toHaveLength(1);
}); });
}); });
describe('tabShown', function() { describe('tabShown', () => {
const mainContent = document.createElement('div'); const mainContent = document.createElement('div');
const tabContent = document.createElement('div'); const tabContent = document.createElement('div');
beforeEach(function() { beforeEach(() => {
spyOn(mainContent, 'getBoundingClientRect').and.returnValue({ top: 10 }); jest.spyOn(mainContent, 'getBoundingClientRect').mockReturnValue({ top: 10 });
spyOn(tabContent, 'getBoundingClientRect').and.returnValue({ top: 100 }); jest.spyOn(tabContent, 'getBoundingClientRect').mockReturnValue({ top: 100 });
spyOn(document, 'querySelector').and.callFake(function(selector) { jest.spyOn(document, 'querySelector').mockImplementation(selector => {
return selector === '.content-wrapper' ? mainContent : tabContent; return selector === '.content-wrapper' ? mainContent : tabContent;
}); });
this.class.currentAction = 'commits'; testContext.class.currentAction = 'commits';
}); });
it('calls window scrollTo with options if document has scrollBehavior', function() { it('calls window scrollTo with options if document has scrollBehavior', () => {
document.documentElement.style.scrollBehavior = ''; document.documentElement.style.scrollBehavior = '';
spyOn(window, 'scrollTo'); jest.spyOn(window, 'scrollTo').mockImplementation(() => {});
this.class.tabShown('commits', 'foobar'); testContext.class.tabShown('commits', 'foobar');
expect(window.scrollTo.calls.first().args[0]).toEqual({ top: 39, behavior: 'smooth' }); expect(window.scrollTo.mock.calls[0][0]).toEqual({ top: 39, behavior: 'smooth' });
}); });
it('calls window scrollTo with two args if document does not have scrollBehavior', function() { it('calls window scrollTo with two args if document does not have scrollBehavior', () => {
spyOnProperty(document.documentElement, 'style', 'get').and.returnValue({}); jest.spyOn(document.documentElement, 'style', 'get').mockReturnValue({});
jest.spyOn(window, 'scrollTo').mockImplementation(() => {});
spyOn(window, 'scrollTo');
this.class.tabShown('commits', 'foobar'); testContext.class.tabShown('commits', 'foobar');
expect(window.scrollTo.calls.first().args).toEqual([0, 39]); expect(window.scrollTo.mock.calls[0]).toEqual([0, 39]);
}); });
}); });
}); });
...@@ -10,7 +10,7 @@ let $icon = null; ...@@ -10,7 +10,7 @@ let $icon = null;
let $page = null; let $page = null;
let $labelsIcon = null; let $labelsIcon = null;
const assertSidebarState = function(state) { const assertSidebarState = state => {
const shouldBeExpanded = state === 'expanded'; const shouldBeExpanded = state === 'expanded';
const shouldBeCollapsed = state === 'collapsed'; const shouldBeCollapsed = state === 'collapsed';
expect($aside.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded); expect($aside.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded);
...@@ -21,14 +21,13 @@ const assertSidebarState = function(state) { ...@@ -21,14 +21,13 @@ const assertSidebarState = function(state) {
expect($icon.hasClass('fa-angle-double-left')).toBe(shouldBeCollapsed); expect($icon.hasClass('fa-angle-double-left')).toBe(shouldBeCollapsed);
}; };
describe('RightSidebar', function() { describe('RightSidebar', () => {
describe('fixture tests', () => { describe('fixture tests', () => {
const fixtureName = 'issues/open-issue.html'; const fixtureName = 'issues/open-issue.html';
preloadFixtures(fixtureName); preloadFixtures(fixtureName);
loadJSONFixtures('todos/todos.json');
let mock; let mock;
beforeEach(function() { beforeEach(() => {
loadFixtures(fixtureName); loadFixtures(fixtureName);
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
new Sidebar(); // eslint-disable-line no-new new Sidebar(); // eslint-disable-line no-new
...@@ -43,7 +42,7 @@ describe('RightSidebar', function() { ...@@ -43,7 +42,7 @@ describe('RightSidebar', function() {
mock.restore(); mock.restore();
}); });
it('should expand/collapse the sidebar when arrow is clicked', function() { it('should expand/collapse the sidebar when arrow is clicked', () => {
assertSidebarState('expanded'); assertSidebarState('expanded');
$toggle.click(); $toggle.click();
assertSidebarState('collapsed'); assertSidebarState('collapsed');
...@@ -51,28 +50,29 @@ describe('RightSidebar', function() { ...@@ -51,28 +50,29 @@ describe('RightSidebar', function() {
assertSidebarState('expanded'); assertSidebarState('expanded');
}); });
it('should float over the page and when sidebar icons clicked', function() { it('should float over the page and when sidebar icons clicked', () => {
$labelsIcon.click(); $labelsIcon.click();
assertSidebarState('expanded'); assertSidebarState('expanded');
}); });
it('should collapse when the icon arrow clicked while it is floating on page', function() { it('should collapse when the icon arrow clicked while it is floating on page', () => {
$labelsIcon.click(); $labelsIcon.click();
assertSidebarState('expanded'); assertSidebarState('expanded');
$toggle.click(); $toggle.click();
assertSidebarState('collapsed'); assertSidebarState('collapsed');
}); });
it('should broadcast todo:toggle event when add todo clicked', function(done) { it('should broadcast todo:toggle event when add todo clicked', done => {
const todos = getJSONFixture('todos/todos.json'); const todos = getJSONFixture('todos/todos.json');
mock.onPost(/(.*)\/todos$/).reply(200, todos); mock.onPost(/(.*)\/todos$/).reply(200, todos);
const todoToggleSpy = spyOnEvent(document, 'todo:toggle'); const todoToggleSpy = jest.fn();
$(document).on('todo:toggle', todoToggleSpy);
$('.issuable-sidebar-header .js-issuable-todo').click(); $('.issuable-sidebar-header .js-issuable-todo').click();
setTimeout(() => { setImmediate(() => {
expect(todoToggleSpy.calls.count()).toEqual(1); expect(todoToggleSpy.mock.calls.length).toEqual(1);
done(); done();
}); });
......
...@@ -14,8 +14,8 @@ describe('Shortcuts', () => { ...@@ -14,8 +14,8 @@ describe('Shortcuts', () => {
beforeEach(() => { beforeEach(() => {
loadFixtures(fixtureName); loadFixtures(fixtureName);
spyOnEvent('.js-new-note-form .js-md-preview-button', 'focus'); jest.spyOn(document.querySelector('.js-new-note-form .js-md-preview-button'), 'focus');
spyOnEvent('.edit-note .js-md-preview-button', 'focus'); jest.spyOn(document.querySelector('.edit-note .js-md-preview-button'), 'focus');
new Shortcuts(); // eslint-disable-line no-new new Shortcuts(); // eslint-disable-line no-new
}); });
...@@ -25,22 +25,22 @@ describe('Shortcuts', () => { ...@@ -25,22 +25,22 @@ describe('Shortcuts', () => {
createEvent('KeyboardEvent', document.querySelector('.js-new-note-form .js-note-text')), createEvent('KeyboardEvent', document.querySelector('.js-new-note-form .js-note-text')),
); );
expect('focus').toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button'); expect(
document.querySelector('.js-new-note-form .js-md-preview-button').focus,
).toHaveBeenCalled();
}); });
it('focues preview button inside edit comment form', done => { it('focues preview button inside edit comment form', () => {
document.querySelector('.js-note-edit').click(); document.querySelector('.js-note-edit').click();
setTimeout(() => { Shortcuts.toggleMarkdownPreview(
Shortcuts.toggleMarkdownPreview( createEvent('KeyboardEvent', document.querySelector('.edit-note .js-note-text')),
createEvent('KeyboardEvent', document.querySelector('.edit-note .js-note-text')), );
);
expect('focus').not.toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button');
expect('focus').toHaveBeenTriggeredOn('.edit-note .js-md-preview-button');
done(); expect(
}); document.querySelector('.js-new-note-form .js-md-preview-button').focus,
).not.toHaveBeenCalled();
expect(document.querySelector('.edit-note .js-md-preview-button').focus).toHaveBeenCalled();
}); });
}); });
}); });
...@@ -26,10 +26,12 @@ describe('User Popovers', () => { ...@@ -26,10 +26,12 @@ describe('User Popovers', () => {
loadFixtures(fixtureTemplate); loadFixtures(fixtureTemplate);
const usersCacheSpy = () => Promise.resolve(dummyUser); const usersCacheSpy = () => Promise.resolve(dummyUser);
spyOn(UsersCache, 'retrieveById').and.callFake(userId => usersCacheSpy(userId)); jest.spyOn(UsersCache, 'retrieveById').mockImplementation(userId => usersCacheSpy(userId));
const userStatusCacheSpy = () => Promise.resolve(dummyUserStatus); const userStatusCacheSpy = () => Promise.resolve(dummyUserStatus);
spyOn(UsersCache, 'retrieveStatusById').and.callFake(userId => userStatusCacheSpy(userId)); jest
.spyOn(UsersCache, 'retrieveStatusById')
.mockImplementation(userId => userStatusCacheSpy(userId));
popovers = initUserPopovers(document.querySelectorAll(selector)); popovers = initUserPopovers(document.querySelectorAll(selector));
}); });
...@@ -53,6 +55,8 @@ describe('User Popovers', () => { ...@@ -53,6 +55,8 @@ describe('User Popovers', () => {
let userLink; let userLink;
beforeEach(() => { beforeEach(() => {
UsersCache.retrieveById.mockReset();
userLink = document.querySelector(selector); userLink = document.querySelector(selector);
triggerEvent('mouseenter', userLink); triggerEvent('mouseenter', userLink);
...@@ -68,7 +72,7 @@ describe('User Popovers', () => { ...@@ -68,7 +72,7 @@ describe('User Popovers', () => {
const [firstPopover] = popovers; const [firstPopover] = popovers;
expect(firstPopover.$props.user).toEqual( expect(firstPopover.$props.user).toEqual(
jasmine.objectContaining({ expect.objectContaining({
name, name,
userId, userId,
username, username,
......
import $ from 'jquery'; import $ from 'jquery';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
import Mousetrap from 'mousetrap'; import Mousetrap from 'mousetrap';
import ZenMode from '~/zen_mode'; import ZenMode from '~/zen_mode';
import initNotes from '~/init_notes'; import initNotes from '~/init_notes';
describe('ZenMode', () => { describe('ZenMode', () => {
let mock;
let zen; let zen;
let dropzoneForElementSpy; let dropzoneForElementSpy;
const fixtureName = 'snippets/show.html'; const fixtureName = 'snippets/show.html';
...@@ -28,10 +31,13 @@ describe('ZenMode', () => { ...@@ -28,10 +31,13 @@ describe('ZenMode', () => {
} }
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet().reply(200);
loadFixtures(fixtureName); loadFixtures(fixtureName);
initNotes(); initNotes();
dropzoneForElementSpy = spyOn(Dropzone, 'forElement').and.callFake(() => ({ dropzoneForElementSpy = jest.spyOn(Dropzone, 'forElement').mockImplementation(() => ({
enable: () => true, enable: () => true,
})); }));
zen = new ZenMode(); zen = new ZenMode();
...@@ -49,20 +55,20 @@ describe('ZenMode', () => { ...@@ -49,20 +55,20 @@ describe('ZenMode', () => {
$('.div-dropzone').addClass('js-invalid-dropzone'); $('.div-dropzone').addClass('js-invalid-dropzone');
exitZen(); exitZen();
expect(dropzoneForElementSpy.calls.count()).toEqual(0); expect(dropzoneForElementSpy.mock.calls.length).toEqual(0);
}); });
it('should call dropzone if element is dropzone valid', () => { it('should call dropzone if element is dropzone valid', () => {
$('.div-dropzone').removeClass('js-invalid-dropzone'); $('.div-dropzone').removeClass('js-invalid-dropzone');
exitZen(); exitZen();
expect(dropzoneForElementSpy.calls.count()).toEqual(2); expect(dropzoneForElementSpy.mock.calls.length).toEqual(2);
}); });
}); });
describe('on enter', () => { describe('on enter', () => {
it('pauses Mousetrap', () => { it('pauses Mousetrap', () => {
const mouseTrapPauseSpy = spyOn(Mousetrap, 'pause'); const mouseTrapPauseSpy = jest.spyOn(Mousetrap, 'pause');
enterZen(); enterZen();
expect(mouseTrapPauseSpy).toHaveBeenCalled(); expect(mouseTrapPauseSpy).toHaveBeenCalled();
...@@ -90,14 +96,14 @@ describe('ZenMode', () => { ...@@ -90,14 +96,14 @@ describe('ZenMode', () => {
beforeEach(enterZen); beforeEach(enterZen);
it('unpauses Mousetrap', () => { it('unpauses Mousetrap', () => {
const mouseTrapUnpauseSpy = spyOn(Mousetrap, 'unpause'); const mouseTrapUnpauseSpy = jest.spyOn(Mousetrap, 'unpause');
exitZen(); exitZen();
expect(mouseTrapUnpauseSpy).toHaveBeenCalled(); expect(mouseTrapUnpauseSpy).toHaveBeenCalled();
}); });
it('restores the scroll position', () => { it('restores the scroll position', () => {
spyOn(zen, 'scrollTo'); jest.spyOn(zen, 'scrollTo').mockImplementation(() => {});
exitZen(); exitZen();
expect(zen.scrollTo).toHaveBeenCalled(); expect(zen.scrollTo).toHaveBeenCalled();
......
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