form-js
Version:
Create better ui form elements. Supports IE9+, all modern browsers, and mobile.
886 lines (842 loc) • 47.4 kB
JavaScript
"use strict";
var Sinon = require('sinon');
var QUnit = require('qunit');
var Dropdown = require('../src/dropdown');
var TestUtils = require('test-utils');
var DeviceManager = require('device-manager');
module.exports = (function (){
var deviceManagerIsMobileStub, redrawOptionsContainerStub;
QUnit.module('Dropdown', {
setup: function () {
deviceManagerIsMobileStub = Sinon.stub(DeviceManager, 'isMobile');
redrawOptionsContainerStub = Sinon.stub(Dropdown.prototype, 'redrawOptionsContainer');
// be default assume desktop
deviceManagerIsMobileStub.returns(false);
},
teardown: function () {
redrawOptionsContainerStub.restore();
deviceManagerIsMobileStub.restore();
}
});
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
QUnit.test('initialize, setup, and destruction', function() {
QUnit.expect(6);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerClass = 'my-options-container';
var uiOptionsClass = 'my-option';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var originalDisplayType = 'inline-block';
selectEl.style.display = originalDisplayType; // set to inline block to test if put back on destroy
var customWrapperClass = 'my-wrapper';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerClass: uiOptionsContainerClass,
optionsClass: uiOptionsClass,
selectedValueContainerClass: uiSelectedValueContainerClass,
customWrapperClass: customWrapperClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
QUnit.equal(selectEl.nextSibling, uiEl, 'ui element container html has been built and added as a sibling of the original form select element');
QUnit.ok(fixture.getElementsByClassName(customWrapperClass)[0].contains(selectEl), 'a wrapper was added as the parent element of the select form element');
QUnit.equal(uiEl.getElementsByClassName(uiSelectedValueContainerClass).length, 1, 'ui selected value container html was added as a child of the ui element container');
var uiSelectedValueContainer = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
QUnit.equal(uiSelectedValueContainer.getAttribute('data-value'), '', 'ui selected value container has no data-value initially');
QUnit.equal(uiSelectedValueContainer.textContent, '', 'ui selected value container has no inner text content (display value) initially');
dropdown.destroy();
QUnit.equal(fixture.childNodes[0], selectEl, 'after destroy(), wrapper class been removed and form element was placed back as a child node of original parent');
});
QUnit.test('initializing when a dropdown item is pre-selected', function() {
QUnit.expect(4);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var formOptionEls = selectEl.getElementsByTagName('option');
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerClass = 'my-options-container';
var uiOptionsClass = 'my-option';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var uiOptionsSelectedClass = 'my-option-selected';
formOptionEls[1].setAttribute('selected', 'selected'); // set the second dropdown as selected
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerClass: uiOptionsContainerClass,
optionsClass: uiOptionsClass,
selectedValueContainerClass: uiSelectedValueContainerClass,
optionsSelectedClass: uiOptionsSelectedClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
QUnit.ok(uiEl.getElementsByClassName(uiOptionsClass)[1].classList.contains(uiOptionsSelectedClass), 'on init, second ui option contains selected class since second item was pre-selected before instantiation');
QUnit.ok(!uiEl.getElementsByClassName(uiOptionsClass)[0].classList.contains(uiOptionsSelectedClass), 'first ui option does not contain selected class');
QUnit.ok(!uiEl.getElementsByClassName(uiOptionsClass)[2].classList.contains(uiOptionsSelectedClass), 'third ui option does not contain selected class');
QUnit.equal(uiSelectedValueContainerEl.getAttribute('data-value'), formOptionEls[1].value, 'ui selected value container data value has been updated to second options value');
dropdown.destroy();
});
QUnit.test('clicking through ui dropdown selections', function() {
QUnit.expect(5);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var formOptionEls = selectEl.getElementsByTagName('option');
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerClass = 'my-options-container';
var uiOptionsClass = 'my-option';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var onChangeSpy = Sinon.spy();
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerClass: uiOptionsContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
optionsClass: uiOptionsClass,
selectedValueContainerClass: uiSelectedValueContainerClass,
onChange: onChangeSpy
});
var selectChangeSpy = Sinon.spy();
selectEl.onchange = selectChangeSpy;
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiOptionsContainerEl = uiEl.getElementsByClassName(uiOptionsContainerClass)[0];
var uiOptionEls = uiOptionsContainerEl.getElementsByClassName(uiOptionsClass);
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
QUnit.ok(!uiEl.classList.contains(uiOptionsContainerActiveClass), 'on initialize, options container element does NOT have active class');
// click on selected value container to show options
uiSelectedValueContainerEl.dispatchEvent(TestUtils.createEvent('click'));
QUnit.ok(uiEl.classList.contains(uiOptionsContainerActiveClass), 'after clicking on selected value container element, options container now has active class');
// click on second option element
uiOptionEls[1].dispatchEvent(TestUtils.createEvent('click'));
QUnit.equal(dropdown.getValue(), formOptionEls[1].value, 'after clicking on second item, getValue() returns data value of second item correctly');
QUnit.equal(uiSelectedValueContainerEl.getAttribute('data-value'), formOptionEls[1].value, 'selected value container reflects the second item data value');
QUnit.deepEqual(onChangeSpy.args[0], [formOptionEls[1].value, selectEl, uiEl, selectChangeSpy.args[0][0]], 'onChange callback was fired with correct args');
dropdown.destroy();
});
QUnit.test('get option element by its data and display value', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var options = selectEl.getElementsByTagName('option');
var dropdown = new Dropdown({el: selectEl});
QUnit.equal(dropdown.getOptionByDisplayValue(options[1].innerHTML), options[1], 'calling getOptionByDisplayValue() with second items display value returns the second item option el');
QUnit.equal(dropdown.getOptionByDataValue(options[1].value), options[1], 'calling getOptionByDataValue() with second items display value returns the second item option el');
dropdown.destroy();
});
QUnit.test('get ui option element by its data', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var options = selectEl.getElementsByTagName('option');
var optionsClass = 'my-opt';
var dropdown = new Dropdown({el: selectEl, optionsClass: optionsClass});
var uiOptions = dropdown.getUIElement().getElementsByClassName(optionsClass);
QUnit.equal(dropdown.getUIOptionByDataValue(options[1].value), uiOptions[1], 'getUIOptionByDataValue() with second items data value returns the second ui option el');
dropdown.destroy();
});
QUnit.test('disabled class should be applied to ui element when initialized with a select that is disabled', function() {
QUnit.expect(1);
// need the first item to be blank or browser will automatically select the first item
var html = '<select disabled>' +
'<option value=""></option>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiDisabledClass = 'ui-disabled';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
disabledClass: uiDisabledClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
QUnit.ok(uiEl.classList.contains(uiDisabledClass), 'on initialize, ui element has disabled class because select element was disabled upon instantiation');
dropdown.destroy();
});
QUnit.test('disabled classes should be applied when disable() is called', function() {
QUnit.expect(1);
// need the first item to be blank or browser will automatically select the first item
var html = '<select>' +
'<option value=""></option>' +
'</select>';
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiDisabledClass = 'ui-disabled';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
disabledClass: uiDisabledClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
dropdown.disable();
QUnit.ok(uiEl.classList.contains(uiDisabledClass), 'after disable() call, ui element has disabled class');
dropdown.destroy();
});
QUnit.test('clicking on ui element after disable() call should not apply active class to ui options container', function() {
QUnit.expect(1);
// need the first item to be blank or browser will automatically select the first item
var html = '<select>' +
'<option value=""></option>' +
'</select>';
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
dropdown.disable();
uiSelectedValueContainerEl.dispatchEvent(TestUtils.createEvent('click'));
QUnit.ok(!uiEl.classList.contains(uiOptionsContainerActiveClass), 'after clicking on selected value container element while disabled, active class is not applied to ui element');
dropdown.destroy();
});
QUnit.test('disabled classes should be removed when enabled() is called after disabling', function() {
QUnit.expect(2);
// need the first item to be blank or browser will automatically select the first item
var html = '<select>' +
'<option value=""></option>' +
'</select>';
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiDisabledClass = 'ui-disabled';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
disabledClass: uiDisabledClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
dropdown.disable();
dropdown.enable();
QUnit.ok(!uiEl.classList.contains(uiDisabledClass), 'after enable(), ui element has disabled class has been removed');
QUnit.ok(!selectEl.disabled, 'select element disabled property returns false');
dropdown.destroy();
});
QUnit.test('new value changed on select dropdown updates its ui counterpart', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var formOptionEls = selectEl.getElementsByTagName('option');
var dropdown = new Dropdown({
el: selectEl
});
var valueContainer = fixture.getElementsByClassName('dropdown-value-container')[0];
QUnit.equal(valueContainer.getAttribute('data-value'), '', 'when change event is triggered with a new value on select element, ui element is updated');
// trigger change event and set to second items value
selectEl.value = formOptionEls[1].value;
selectEl.dispatchEvent(TestUtils.createEvent('change'));
QUnit.equal(valueContainer.getAttribute('data-value'), formOptionEls[1].value, 'when change event is triggered with a new value on select element, ui element is updated');
dropdown.destroy();
});
QUnit.test('clicking a ui dropdown selection should remove active class from dropdown container element', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerClass = 'my-options-container';
var uiOptionsClass = 'my-option';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerClass: uiOptionsContainerClass,
optionsClass: uiOptionsClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiOptionEls = uiEl.getElementsByClassName(uiOptionsClass);
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
// click on selected value container to show options
uiSelectedValueContainerEl.dispatchEvent(TestUtils.createEvent('click'));
// click on second option element
uiOptionEls[1].dispatchEvent(TestUtils.createEvent('click'));
QUnit.ok(!uiEl.classList.contains(uiOptionsContainerActiveClass), 'after clicking on an option ui item, dropdown container no longer has active class');
dropdown.destroy();
});
QUnit.test('ui selected display value is set to selected option\'s display value when initializing with the disabled select option with a selected option', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var testDisplayValue = 'My Placeholder';
var html =
'<select disabled>' +
'<option value="" selected>' + testDisplayValue + '</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var formOption = selectEl.getElementsByTagName('option')[0];
formOption.setAttribute('selected', 'selected'); // set the second dropdown as selected
var uiSelectedValueContainerClass = 'my-selected-val-container';
var dropdown = new Dropdown({el: selectEl, selectedValueContainerClass: uiSelectedValueContainerClass});
var uiSelectedValueContainerEl = fixture.getElementsByClassName(uiSelectedValueContainerClass)[0];
QUnit.equal(uiSelectedValueContainerEl.textContent, testDisplayValue, 'ui selected display value container display value was set to the selected options display value');
dropdown.destroy();
});
QUnit.test('clicking anywhere outside the ui element when its ui options container element is open should hide the ui options container element', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
// click on selected value container to show options
uiSelectedValueContainerEl.dispatchEvent(TestUtils.createEvent('click'));
// click outside
fixture.dispatchEvent(TestUtils.createEvent('click'));
QUnit.ok(!uiEl.classList.contains(uiOptionsContainerActiveClass), 'since click was NOT in ui options container, ui options container element no longer has active class');
dropdown.destroy();
});
QUnit.test('clicking on the ui element and anywhere inside of it while ui options container is open does NOT close ui options container', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
var uiEl = fixture.getElementsByClassName(uiContainerClass)[0];
var uiSelectedValueContainerEl = uiEl.getElementsByClassName(uiSelectedValueContainerClass)[0];
// click on selected value container to show options
uiSelectedValueContainerEl.dispatchEvent(TestUtils.createEvent('click'));
// click outside
QUnit.ok(uiEl.classList.contains(uiOptionsContainerActiveClass), 'ui options container element still has active class after clicking anywhere inside of ui options container');
dropdown.destroy();
});
QUnit.test('clicking on another ui dropdown element inside of the same form should hide the ui options container element', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var html =
'<form>' +
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>' +
'<select>' +
'<option value="Apple">Apple</option>' +
'<option value="Orange">Orange</option>' +
'</select>' +
'</form>';
var formEl = TestUtils.createHtmlElement(html);
fixture.appendChild(formEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsContainerActiveClass = 'active-options-container';
var uiSelectedValueContainerClass = 'my-selected-val-container';
var selectEls = formEl.getElementsByTagName('select');
var firstDropdown = new Dropdown({
el: selectEls[0],
containerClass: uiContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
var secondDropdown = new Dropdown({
el: selectEls[1],
containerClass: uiContainerClass,
optionsContainerActiveClass: uiOptionsContainerActiveClass,
selectedValueContainerClass: uiSelectedValueContainerClass
});
// click on selected value container of first element to show its options
var firstUIElement = fixture.getElementsByClassName(uiContainerClass)[0];
firstUIElement.getElementsByClassName(uiSelectedValueContainerClass)[0].dispatchEvent(TestUtils.createEvent('click'));
// click on selected value container of second element to show its options
var secondUIElement = fixture.getElementsByClassName(uiContainerClass)[1];
secondUIElement.getElementsByClassName(uiSelectedValueContainerClass)[0].dispatchEvent(TestUtils.createEvent('click'));
QUnit.ok(!firstUIElement.classList.contains(uiOptionsContainerActiveClass), 'clicking on second ui value container closes the first');
firstDropdown.destroy();
secondDropdown.destroy();
});
QUnit.test('updateOptions() should create new form and UI elements from objects in the array that it is passed', function() {
QUnit.expect(4);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsClass = 'my-option';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsClass: uiOptionsClass
});
var newOptions = [{dataValue: 'TW', displayValue: 'Twitter'}];
dropdown.updateOptions(newOptions);
var formOptionElements = fixture.getElementsByTagName('option');
var uiOptionElements = fixture.getElementsByClassName(uiOptionsClass);
QUnit.equal(formOptionElements[3].getAttribute('value'), newOptions[0].dataValue, 'after updating options, new form element was added with correct data value');
QUnit.equal(formOptionElements[3].textContent, newOptions[0].displayValue, 'new form element has correct display value');
QUnit.equal(uiOptionElements[3].getAttribute('data-value'), newOptions[0].dataValue, 'new ui element was added with correct data value');
QUnit.equal(uiOptionElements[3].innerHTML, newOptions[0].displayValue, 'first new ui element has correct display value');
dropdown.destroy();
});
QUnit.test('passing replace true to updateOptions() should clear out options before adding new ones', function() {
QUnit.expect(5);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsClass = 'my-option';
var clearOptionsSpy = Sinon.spy(Dropdown.prototype, 'clearOptions');
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsClass: uiOptionsClass
});
var newOptions = [{dataValue: 'TW', displayValue: 'Twitter'}];
dropdown.updateOptions(newOptions, {replace: true});
var formOptionElements = fixture.getElementsByTagName('option');
var uiOptionElements = fixture.getElementsByClassName(uiOptionsClass);
QUnit.equal(clearOptionsSpy.callCount, 1, 'clearOptions was called');
QUnit.equal(formOptionElements[0].getAttribute('value'), newOptions[0].dataValue, 'new form element was added as first index with correct data value');
QUnit.equal(formOptionElements[0].textContent, newOptions[0].displayValue, 'new form element has correct display value');
QUnit.equal(uiOptionElements[0].getAttribute('data-value'), newOptions[0].dataValue, 'new ui element was added as first index with correct data value');
QUnit.equal(uiOptionElements[0].innerHTML, newOptions[0].displayValue, 'first new ui element has correct display value');
clearOptionsSpy.restore();
dropdown.destroy();
});
QUnit.test('clearOptions() should clear all form and ui options in the dropdown', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiContainerClass = 'my-ui-container';
var uiOptionsClass = 'my-option';
var dropdown = new Dropdown({
el: selectEl,
containerClass: uiContainerClass,
optionsClass: uiOptionsClass
});
dropdown.clearOptions();
var formOptionElements = fixture.getElementsByTagName('option');
var uiOptionElements = fixture.getElementsByClassName(uiOptionsClass);
QUnit.equal(formOptionElements.length, 0, 'all form elements have been cleared');
QUnit.equal(uiOptionElements.length, 0, 'all ui elements have been cleared');
dropdown.destroy();
});
QUnit.test('ui dropdown element should be given a default tabindex attribute of zero on initialize when form element does not have one to make it focusable', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
QUnit.equal(dropdown.getUIElement().getAttribute('tabindex'), 0, 'ui dropdown was given a default tabindex of 0');
dropdown.destroy();
});
QUnit.test('ui dropdown element should have same tabindex value as the form element on initialize', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var ti = 34;
var html = '<select tabindex="' + ti + '"></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
QUnit.equal(dropdown.getUIElement().getAttribute('tabindex'), ti, 'tabindex attribute from form element was set on the ui element');
dropdown.destroy();
});
QUnit.test('tabindex of form element should be set to -1 on initialize and set back when destroyed', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var ti = 5;
var html = '<select tabindex="' + ti + '"></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
QUnit.equal(dropdown.getFormElement().getAttribute('tabindex'), -1, 'tabindex attribute on form element was set to -1');
dropdown.destroy();
QUnit.equal(dropdown.getFormElement().getAttribute('tabindex'), ti, 'tabindex attribute on form element was set back to its original value on destroy');
});
QUnit.test('tabindex of form element should NOT be set to -1 on initialize when on a mobile device', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
deviceManagerIsMobileStub.returns(true);
var ti = 5;
var html = '<select tabindex="' + ti + '"></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
QUnit.equal(dropdown.getFormElement().getAttribute('tabindex'), ti, 'tabindex attribute on form element was NOT set to -1 because mobile devices should use native select element');
QUnit.ok(!dropdown.getUIElement().getAttribute('tabindex'), 'ui element has no tabindex value');
dropdown.destroy();
});
QUnit.test('callback assigned to onFocus of initialize options should be called when select element is focused', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var focusSpy = Sinon.spy();
var dropdown = new Dropdown({
el: selectEl,
onFocus: focusSpy
});
QUnit.equal(focusSpy.callCount, 0, 'onFocus callback was NOT yet triggered because it isnt initially focused');
// trigger focus
selectEl.dispatchEvent(TestUtils.createEvent('focus'));
QUnit.equal(focusSpy.callCount, 1, 'onFocus callback was triggered after select element became focused');
dropdown.destroy();
selectEl.dispatchEvent(TestUtils.createEvent('focus'));
QUnit.equal(focusSpy.callCount, 1, 'onFocus callback was NOT triggered after destroy when select element is focused again');
});
QUnit.test('callback assigned to onBlur of initialize options should be called when select element loses focus', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var blurSpy = Sinon.spy();
var dropdown = new Dropdown({
el: selectEl,
onBlur: blurSpy
});
QUnit.equal(blurSpy.callCount, 0, 'onBlur callback was NOT triggered because it isnt blurred yet');
// trigger focus
selectEl.dispatchEvent(TestUtils.createEvent('focus'));
// trigger blur
selectEl.dispatchEvent(TestUtils.createEvent('blur'));
QUnit.equal(blurSpy.callCount, 1, 'onBlur callback was triggered after select element became focused');
dropdown.destroy();
// trigger focus
selectEl.dispatchEvent(TestUtils.createEvent('focus'));
// trigger blur
selectEl.dispatchEvent(TestUtils.createEvent('blur'));
QUnit.equal(blurSpy.callCount, 1, 'onBlur callback was NOT triggered after destroy when select element is focused then blurred again');
});
QUnit.test('callback assigned to onFocus of initialize options should be called when ui element is focused', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var focusSpy = Sinon.spy();
var dropdown = new Dropdown({
el: selectEl,
onFocus: focusSpy
});
var uiEl = dropdown.getUIElement();
QUnit.equal(focusSpy.callCount, 0, 'onFocus callback was NOT yet triggered because it isnt initially focused');
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
QUnit.equal(focusSpy.callCount, 1, 'onFocus callback was triggered after element became focused');
dropdown.destroy();
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
QUnit.equal(focusSpy.callCount, 1, 'onFocus callback was NOT triggered after destroy when element is focused again');
});
QUnit.test('callback assigned to onBlur of initialize options should be called when ui element loses focus', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var blurSpy = Sinon.spy();
var dropdown = new Dropdown({
el: selectEl,
onBlur: blurSpy
});
var uiEl = dropdown.getUIElement();
QUnit.equal(blurSpy.callCount, 0, 'onBlur callback was NOT triggered because it isnt blurred yet');
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// trigger blur
uiEl.dispatchEvent(TestUtils.createEvent('blur'));
QUnit.equal(blurSpy.callCount, 1, 'onBlur callback was triggered after select element became focused');
dropdown.destroy();
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// trigger blur
uiEl.dispatchEvent(TestUtils.createEvent('blur'));
QUnit.equal(blurSpy.callCount, 1, 'onBlur callback was NOT triggered after destroy when select element is focused then blurred again');
});
QUnit.test('calling showOptionsContainer() the first time should set first option as selected if there is not a pre-selected option', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="">Default</option>' +
'<option value="FB">Facebook</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var uiOptionsClass = 'my-option';
var myOptionSelected = 'opt-selected';
var dropdown = new Dropdown({
el: selectEl,
optionsClass: uiOptionsClass,
optionsSelected: myOptionSelected
});
dropdown.showOptionsContainer();
var uiOptionEls = dropdown.getUIElement().getElementsByClassName(uiOptionsClass);
QUnit.ok(!uiOptionEls[0].classList.contains(myOptionSelected), 'after calling showOptionsContainer() first ui option element is set to selected');
dropdown.destroy();
});
QUnit.test('pressing up key while ui options container is not showing shows the container and does not cycle through options', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var showOptionsContainerStub = Sinon.stub(Dropdown.prototype, 'showOptionsContainer');
var highlighter = 'highlited';
var dropdown = new Dropdown({el: selectEl, optionsHighlightedClass: highlighter});
var uiEl = dropdown.getUIElement();
QUnit.equal(showOptionsContainerStub.callCount, 0, 'showOptionsContainer() method was called because no key was pressed');
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
var keyEvent = TestUtils.createEvent('keyup');
// up arrow key
keyEvent.keyCode = 38;
uiEl.dispatchEvent(keyEvent);
QUnit.equal(showOptionsContainerStub.callCount, 1, 'showOptionsContainer() method was called when up key was pressed');
QUnit.equal(uiEl.getElementsByClassName(highlighter).length, 0, 'no ui options elements were highlighted');
dropdown.destroy();
showOptionsContainerStub.restore();
});
QUnit.test('pressing up key while ui options container is open when it does not have a previous sibling adds highlights to last ui option element', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var highlighter = 'highlited';
var optionsContainerClass = 'my-options';
var dropdown = new Dropdown({
el: selectEl,
optionsHighlightedClass: highlighter,
optionsContainerClass: optionsContainerClass
});
var uiEl = dropdown.getUIElement();
var uiOptionsContainerEl = uiEl.getElementsByClassName(optionsContainerClass)[0];
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// open container
dropdown.showOptionsContainer();
var keyEvent = TestUtils.createEvent('keyup');
// up arrow key
keyEvent.keyCode = 38;
uiEl.dispatchEvent(keyEvent);
QUnit.deepEqual(uiOptionsContainerEl.getElementsByClassName(highlighter)[0], uiOptionsContainerEl.lastChild, 'last ui options element was highlighted');
dropdown.destroy();
});
QUnit.test('pressing up key while on an ui option element moves highlight class to previous ui option', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB" selected>Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var highlighter = 'highlited';
var optionsContainerClass = 'my-options';
var dropdown = new Dropdown({
el: selectEl,
optionsHighlightedClass: highlighter,
optionsContainerClass: optionsContainerClass
});
var uiEl = dropdown.getUIElement();
var uiOptionsContainerEl = uiEl.getElementsByClassName(optionsContainerClass)[0];
var uiOptionEls = uiOptionsContainerEl.childNodes;
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// open container
dropdown.showOptionsContainer();
// second option element will automatically be highlighted since it is the selected one
var keyEvent = TestUtils.createEvent('keyup');
// up arrow key
keyEvent.keyCode = 38;
uiEl.dispatchEvent(keyEvent);
QUnit.ok(uiOptionEls[0].classList.contains(highlighter), 'when highlight is on the second option, pressing up highlights first option');
QUnit.ok(!uiOptionEls[1].classList.contains(highlighter), 'highlight class was removed from second option');
dropdown.destroy();
});
QUnit.test('pressing down key while ui options container is not showing shows the container and does not cycle through options', function() {
QUnit.expect(3);
var fixture = document.getElementById('qunit-fixture');
var html = '<select></select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var showOptionsContainerStub = Sinon.stub(Dropdown.prototype, 'showOptionsContainer');
var highlighter = 'highlited';
var dropdown = new Dropdown({el: selectEl, optionsHighlightedClass: highlighter});
var uiEl = dropdown.getUIElement();
QUnit.equal(showOptionsContainerStub.callCount, 0, 'showOptionsContainer() method was called because no key was pressed');
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
var keyEvent = TestUtils.createEvent('keyup');
// down arrow key
keyEvent.keyCode = 40;
uiEl.dispatchEvent(keyEvent);
QUnit.equal(showOptionsContainerStub.callCount, 1, 'showOptionsContainer() method was called when up key was pressed');
QUnit.equal(uiEl.getElementsByClassName(highlighter).length, 0, 'no ui options elements were highlighted');
dropdown.destroy();
showOptionsContainerStub.restore();
});
QUnit.test('pressing down key while ui options container is open when it does not have a next sibling adds highlights to first ui option element', function() {
QUnit.expect(1);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG" selected>Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var highlighter = 'highlited';
var optionsContainerClass = 'my-options';
var dropdown = new Dropdown({
el: selectEl,
optionsHighlightedClass: highlighter,
optionsContainerClass: optionsContainerClass
});
var uiEl = dropdown.getUIElement();
var uiOptionsContainerEl = uiEl.getElementsByClassName(optionsContainerClass)[0];
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// open container
dropdown.showOptionsContainer();
var keyEvent = TestUtils.createEvent('keyup');
// down arrow key
keyEvent.keyCode = 40;
uiEl.dispatchEvent(keyEvent);
QUnit.deepEqual(uiOptionsContainerEl.getElementsByClassName(highlighter)[0], uiOptionsContainerEl.firstChild, 'first ui options element was highlighted');
dropdown.destroy();
});
QUnit.test('pressing down key while on an ui option element moves highlight class to next ui option', function() {
QUnit.expect(2);
var fixture = document.getElementById('qunit-fixture');
var html =
'<select>' +
'<option value="AAPL">Apple</option>' +
'<option value="FB">Facebook</option>' +
'<option value="GOOG">Google</option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
fixture.appendChild(selectEl);
var highlighter = 'highlited';
var optionsContainerClass = 'my-options';
var dropdown = new Dropdown({
el: selectEl,
optionsHighlightedClass: highlighter,
optionsContainerClass: optionsContainerClass
});
var uiEl = dropdown.getUIElement();
var uiOptionsContainerEl = uiEl.getElementsByClassName(optionsContainerClass)[0];
var uiOptionEls = uiOptionsContainerEl.childNodes;
// trigger focus
uiEl.dispatchEvent(TestUtils.createEvent('focus'));
// open container
dropdown.showOptionsContainer();
// first option element will automatically
// be highlighted since it is the selected one
var keyEvent = TestUtils.createEvent('keyup');
// down arrow key
keyEvent.keyCode = 40;
uiEl.dispatchEvent(keyEvent);
QUnit.ok(uiOptionEls[1].classList.contains(highlighter), 'when highlight is on the first option, pressing down highlights second option');
QUnit.ok(!uiOptionEls[0].classList.contains(highlighter), 'highlight class was removed from first option');
dropdown.destroy();
});
QUnit.test('getValue() should return current value of dropdown', function() {
QUnit.expect(1);
var val = 'myTestVal';
var html = '<select><option value="' + val + '"></option></select>';
var selectEl = TestUtils.createHtmlElement(html);
document.getElementById('qunit-fixture').appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
dropdown.setValue(val);
QUnit.equal(dropdown.getValue(), val);
dropdown.destroy();
});
QUnit.test('clear() should remove selected dropdown item', function() {
QUnit.expect(1);
var val = 'myTestVal';
var html =
'<select>' +
'<option value=""></option>' +
'<option value="' + val + '"></option>' +
'</select>';
var selectEl = TestUtils.createHtmlElement(html);
document.getElementById('qunit-fixture').appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
dropdown.setValue(val);
dropdown.clear();
QUnit.equal(selectEl.value, '');
dropdown.destroy();
});
QUnit.test('clear() does nothing if there is no dropdown option with a value that matches an empty string', function() {
QUnit.expect(1);
var val = 'myTestVal';
var html = '<select><option value="' + val + '"></option></select>';
var selectEl = TestUtils.createHtmlElement(html);
document.getElementById('qunit-fixture').appendChild(selectEl);
var dropdown = new Dropdown({el: selectEl});
dropdown.setValue(val);
dropdown.clear();
QUnit.equal(selectEl.value, val);
dropdown.destroy();
});
})();