Newer
Older
Mike Greiling
committed
/* eslint-disable comma-dangle, prefer-const, no-param-reassign, no-plusplus, semi, no-unused-expressions, arrow-spacing, max-len */
/* global Turbolinks */
/*= require jquery */
/*= require gl_dropdown */
/*= require turbolinks */
/*= require lib/utils/common_utils */
/*= require lib/utils/type_utility */
(() => {
const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
const SEARCH_INPUT_SELECTOR = '.dropdown-input-field';
const ITEM_SELECTOR = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES})`;
const FOCUSED_ITEM_SELECTOR = `${ITEM_SELECTOR} a.is-focused`;
const ARROW_KEYS = {
DOWN: 40,
UP: 38,
ENTER: 13,
ESC: 27
};
let navigateWithKeys = function navigateWithKeys(direction, steps, cb, i) {
i = i || 0;
if (!i) direction = direction.toUpperCase();
$('body').trigger({
type: 'keydown',
which: ARROW_KEYS[direction],
keyCode: ARROW_KEYS[direction]
});
i++;
if (i <= steps) {
navigateWithKeys(direction, steps, cb, i);
} else {
cb();
let remoteMock = function remoteMock(data, term, callback) {
remoteCallback = callback.bind({}, data);
}
describe('Dropdown', function describeDropdown() {
Mike Greiling
committed
preloadFixtures('static/gl_dropdown.html.raw');
function initDropDown(hasRemote, isFilterable) {
this.dropdownButtonElement = $('#js-project-dropdown', this.dropdownContainerElement).glDropdown({
selectable: true,
filterable: isFilterable,
data: hasRemote ? remoteMock.bind({}, this.projectsData) : this.projectsData,
}
beforeEach(() => {
Mike Greiling
committed
loadFixtures('static/gl_dropdown.html.raw');
this.dropdownContainerElement = $('.dropdown.inline');
this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement);
Mike Greiling
committed
this.projectsData = getJSONFixture('projects.json');
$('body').unbind('keydown');
this.dropdownContainerElement.unbind('keyup');
it('should open on click', () => {
initDropDown.call(this, false);
expect(this.dropdownContainerElement).not.toHaveClass('open');
this.dropdownButtonElement.click();
expect(this.dropdownContainerElement).toHaveClass('open');
});
describe('that is open', () => {
beforeEach(() => {
initDropDown.call(this, false, false);
this.dropdownButtonElement.click();
it('should select a following item on DOWN keypress', () => {
expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0);
let randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 1)) + 0);
navigateWithKeys('down', randomIndex, () => {
expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
expect($(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused');
it('should select a previous item on UP keypress', () => {
expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(0);
navigateWithKeys('down', (this.projectsData.length - 1), () => {
expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
let randomIndex = (Math.floor(Math.random() * (this.projectsData.length - 2)) + 0);
navigateWithKeys('up', randomIndex, () => {
expect($(FOCUSED_ITEM_SELECTOR, this.$dropdownMenuElement).length).toBe(1);
expect($(`${ITEM_SELECTOR}:eq(${((this.projectsData.length - 2) - randomIndex)}) a`, this.$dropdownMenuElement)).toHaveClass('is-focused');
it('should click the selected item on ENTER keypress', () => {
expect(this.dropdownContainerElement).toHaveClass('open')
let randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0
navigateWithKeys('down', randomIndex, () => {
spyOn(Turbolinks, 'visit').and.stub();
navigateWithKeys('enter', null, () => {
expect(this.dropdownContainerElement).not.toHaveClass('open');
let link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement);
expect(link).toHaveClass('is-active');
let linkedLocation = link.attr('href');
if (linkedLocation && linkedLocation !== '#') expect(Turbolinks.visit).toHaveBeenCalledWith(linkedLocation);
});
it('should close on ESC keypress', () => {
expect(this.dropdownContainerElement).toHaveClass('open');
this.dropdownContainerElement.trigger({
type: 'keyup',
which: ARROW_KEYS.ESC,
keyCode: ARROW_KEYS.ESC
});
expect(this.dropdownContainerElement).not.toHaveClass('open');
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
describe('opened and waiting for a remote callback', () => {
beforeEach(() => {
initDropDown.call(this, true, true);
this.dropdownButtonElement.click();
});
it('should not focus search input while remote task is not complete', ()=> {
expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR));
remoteCallback();
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
it('should focus search input after remote task is complete', ()=> {
remoteCallback();
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
it('should focus on input when opening for the second time', ()=> {
remoteCallback();
this.dropdownContainerElement.trigger({
type: 'keyup',
which: ARROW_KEYS.ESC,
keyCode: ARROW_KEYS.ESC
});
this.dropdownButtonElement.click();
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
});
describe('input focus with array data', () => {
it('should focus input when passing array data to drop down', ()=> {
initDropDown.call(this, false, true);
this.dropdownButtonElement.click();
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
});