mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-20 14:29:51 -04:00
Merge pull request #3047 from alphagov/add-js-tests-for-radio-select
Add js tests for radio select
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
(function(Modules) {
|
(function(global) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var Modules = global.GOVUK.Modules;
|
||||||
|
var Hogan = global.Hogan;
|
||||||
|
|
||||||
let states = {
|
let states = {
|
||||||
'initial': Hogan.compile(`
|
'initial': Hogan.compile(`
|
||||||
<div class="radio-select-column">
|
<div class="radio-select-column">
|
||||||
@@ -30,7 +33,7 @@
|
|||||||
<label for="{{id}}">{{label}}</label>
|
<label for="{{id}}">{{label}}</label>
|
||||||
</div>
|
</div>
|
||||||
{{/choices}}
|
{{/choices}}
|
||||||
<input type='button' class='js-reset-button js-reset-button-block' value='Done' />
|
<input type='button' class='js-done-button js-done-button-block' value='Done' />
|
||||||
</div>
|
</div>
|
||||||
`),
|
`),
|
||||||
'chosen': Hogan.compile(`
|
'chosen': Hogan.compile(`
|
||||||
@@ -54,11 +57,8 @@
|
|||||||
`)
|
`)
|
||||||
};
|
};
|
||||||
|
|
||||||
let focusSelected = function() {
|
let focusSelected = function(component) {
|
||||||
setTimeout(
|
$('[type=radio]:checked', component).focus();
|
||||||
() => $('[type=radio]:checked').next('label').blur().trigger('focus').addClass('selected'),
|
|
||||||
50
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Modules.RadioSelect = function() {
|
Modules.RadioSelect = function() {
|
||||||
@@ -79,6 +79,35 @@
|
|||||||
});
|
});
|
||||||
let categories = $component.data('categories').split(',');
|
let categories = $component.data('categories').split(',');
|
||||||
let name = $component.find('input').eq(0).attr('name');
|
let name = $component.find('input').eq(0).attr('name');
|
||||||
|
let mousedownOption = null;
|
||||||
|
const reset = () => {
|
||||||
|
render('initial', {
|
||||||
|
'categories': categories,
|
||||||
|
'name': name
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const selectOption = (value) => {
|
||||||
|
render('chosen', {
|
||||||
|
'choices': choices.filter(
|
||||||
|
element => element.value == value
|
||||||
|
),
|
||||||
|
'name': name
|
||||||
|
});
|
||||||
|
focusSelected(component);
|
||||||
|
};
|
||||||
|
const trackMouseup = (event) => {
|
||||||
|
const parentNode = event.target.parentNode;
|
||||||
|
|
||||||
|
if (parentNode === mousedownOption) {
|
||||||
|
const value = $('input', parentNode).attr('value');
|
||||||
|
|
||||||
|
selectOption(value);
|
||||||
|
|
||||||
|
// clear tracking
|
||||||
|
mousedownOption = null;
|
||||||
|
$(document).off('mouseup', trackMouseup);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$component
|
$component
|
||||||
.on('click', '.js-category-button', function(event) {
|
.on('click', '.js-category-button', function(event) {
|
||||||
@@ -92,51 +121,54 @@
|
|||||||
),
|
),
|
||||||
'name': name
|
'name': name
|
||||||
});
|
});
|
||||||
focusSelected();
|
focusSelected(component);
|
||||||
|
|
||||||
})
|
})
|
||||||
.on('click', '.js-option', function(event) {
|
.on('mousedown', '.js-option', function(event) {
|
||||||
|
mousedownOption = this;
|
||||||
// stop click being triggered by keyboard events
|
|
||||||
if (!event.pageX) return true;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
let value = $('input', this).attr('value');
|
|
||||||
render('chosen', {
|
|
||||||
'choices': choices.filter(
|
|
||||||
element => element.value == value
|
|
||||||
),
|
|
||||||
'name': name
|
|
||||||
});
|
|
||||||
focusSelected();
|
|
||||||
|
|
||||||
|
// mouseup on the same option completes the click action
|
||||||
|
$(document).on('mouseup', trackMouseup);
|
||||||
})
|
})
|
||||||
|
// space and enter, clicked on a radio confirm that option was selected
|
||||||
.on('keydown', 'input[type=radio]', function(event) {
|
.on('keydown', 'input[type=radio]', function(event) {
|
||||||
|
|
||||||
// intercept keypresses which aren’t enter or space
|
// allow keypresses which aren’t enter or space through
|
||||||
if (event.which !== 13 && event.which !== 32) {
|
if (event.which !== 13 && event.which !== 32) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let value = $(this).attr('value');
|
let value = $(this).attr('value');
|
||||||
render('chosen', {
|
selectOption(value);
|
||||||
'choices': choices.filter(
|
|
||||||
element => element.value == value
|
})
|
||||||
),
|
.on('click', '.js-done-button', function(event) {
|
||||||
'name': name
|
|
||||||
});
|
event.preventDefault();
|
||||||
focusSelected();
|
let $selection = $('input[type=radio]:checked', this.parentNode);
|
||||||
|
if ($selection.length) {
|
||||||
|
|
||||||
|
render('chosen', {
|
||||||
|
'choices': choices.filter(
|
||||||
|
element => element.value == $selection.eq(0).attr('value')
|
||||||
|
),
|
||||||
|
'name': name
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
focusSelected(component);
|
||||||
|
|
||||||
})
|
})
|
||||||
.on('click', '.js-reset-button', function(event) {
|
.on('click', '.js-reset-button', function(event) {
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
render('initial', {
|
reset();
|
||||||
'categories': categories,
|
focusSelected(component);
|
||||||
'name': name
|
|
||||||
});
|
|
||||||
focusSelected();
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,4 +183,4 @@
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
})(window.GOVUK.Modules);
|
})(window);
|
||||||
|
|||||||
@@ -14,15 +14,16 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.js-reset-button,
|
.js-done-button,
|
||||||
.js-category-button {
|
.js-category-button,
|
||||||
|
.js-reset-button {
|
||||||
|
|
||||||
@include button($grey-3);
|
@include button($grey-3);
|
||||||
margin-right: $gutter-half;
|
margin-right: $gutter-half;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.js-reset-button-block {
|
.js-done-button-block {
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|||||||
413
tests/javascripts/radioSelect.test.js
Normal file
413
tests/javascripts/radioSelect.test.js
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
const helpers = require('./support/helpers');
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
window.Hogan = require('hogan.js');
|
||||||
|
require('../../app/assets/javascripts/radioSelect.js');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
require('./support/teardown.js');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RadioSelect', () => {
|
||||||
|
const CATEGORIES = [
|
||||||
|
'Later today',
|
||||||
|
'Tomorrow',
|
||||||
|
'Friday',
|
||||||
|
'Saturday'
|
||||||
|
];
|
||||||
|
const HOURS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];
|
||||||
|
let originalOptionsForAllCategories;
|
||||||
|
|
||||||
|
const getDataFromOption = (option) => {
|
||||||
|
return {
|
||||||
|
value: option.querySelector('input').getAttribute('value'),
|
||||||
|
label: option.querySelector('label').textContent.trim()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickButtonForCategory = (category) => {
|
||||||
|
|
||||||
|
// click the button for this category
|
||||||
|
const categoryButton = document.querySelector(`.radio-select-column:nth-child(2) input[value="${category}"]`);
|
||||||
|
helpers.triggerEvent(categoryButton, 'click');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const options = () => {
|
||||||
|
let result = '';
|
||||||
|
|
||||||
|
const getHourLabel = (hour) => {
|
||||||
|
let label = hour;
|
||||||
|
|
||||||
|
if (hour === 12) {
|
||||||
|
return 'midday';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hour === 24) {
|
||||||
|
return 'midnight';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${hour}${hour > 12 ? 'am' : 'pm'}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hours = (day, start) => {
|
||||||
|
let result = '';
|
||||||
|
let hours = HOURS;
|
||||||
|
let dayAsNumber = {
|
||||||
|
'Later today': 22,
|
||||||
|
'Tomorrow': 23,
|
||||||
|
'Friday': 24,
|
||||||
|
'Saturday': 25
|
||||||
|
}[day];
|
||||||
|
|
||||||
|
if (start !== undefined) {
|
||||||
|
hours = hours.slice(start - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hours.forEach((hour, idx) => {
|
||||||
|
const hourLabel = getHourLabel(hour);
|
||||||
|
|
||||||
|
result +=
|
||||||
|
`<div class="multiple-choice">
|
||||||
|
<input id="scheduled_for-${idx}" name="scheduled_for" type="radio" value="2019-05-${dayAsNumber}T${hour}:00:00.459156">
|
||||||
|
<label for="scheduled_for-${idx}">
|
||||||
|
${day} at ${hourLabel}
|
||||||
|
</label>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CATEGORIES.forEach((day, idx) => {
|
||||||
|
if (idx === 0) {
|
||||||
|
result += hours(day, 11);
|
||||||
|
} else {
|
||||||
|
result += hours(day);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.body.innerHTML = `
|
||||||
|
<fieldset>
|
||||||
|
<legend class="form-label">
|
||||||
|
When should Notify send these messages?
|
||||||
|
</legend>
|
||||||
|
<div class="radio-select" data-module="radio-select" data-categories="${CATEGORIES.join(',')}">
|
||||||
|
<div class="radio-select-column">
|
||||||
|
<div class="multiple-choice">
|
||||||
|
<input checked="" id="scheduled_for-0" name="scheduled_for" type="radio" value="">
|
||||||
|
<label for="scheduled_for-0">
|
||||||
|
Now
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="radio-select-column">
|
||||||
|
${options()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>`;
|
||||||
|
|
||||||
|
originalOptionsForAllCategories = Array.from(document.querySelector('.radio-select-column:nth-child(2) .multiple-choice'))
|
||||||
|
.map(option => getDataFromOption(option));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the page has loaded it should have a button for each category", () => {
|
||||||
|
|
||||||
|
let categoryButtons;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
categoryButtons = document.querySelectorAll('.radio-select-column:nth-child(2) .js-category-button');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("the number of buttons should match the categories", () => {
|
||||||
|
|
||||||
|
expect(categoryButtons.length).toBe(CATEGORIES.length);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("each button's text should match their category", () => {
|
||||||
|
|
||||||
|
// check the buttons have the right text
|
||||||
|
CATEGORIES.forEach((category, idx) => {
|
||||||
|
expect(categoryButtons[idx].getAttribute('value')).toEqual(category);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("category buttons", () => {
|
||||||
|
|
||||||
|
CATEGORIES.forEach((category, idx) => {
|
||||||
|
|
||||||
|
describe(`clicking the button for ${category} should`, () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
// get all the options in the original page for this category
|
||||||
|
originalOptionsForCategory = originalOptionsForAllCategories.filter(option => option.label === category);
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
clickButtonForCategory(category);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("show the options for it, with the right label and value", () => {
|
||||||
|
|
||||||
|
// check options this reveals against those originally in the page for this category
|
||||||
|
const options = document.querySelector('.radio-select-column:nth-child(2) .multiple-choice');
|
||||||
|
|
||||||
|
const optionsThatMatchOriginals = Array.from(options).filter((option, idx) => {
|
||||||
|
const optionData = getDataFromOption(option);
|
||||||
|
const originalOption = originalOptionsForCategory[idx];
|
||||||
|
|
||||||
|
return optionData.value === originalOption.value && optionData.label === originalOption.label;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(optionsThatMatchOriginals.length).toEqual(originalOptionsForCategory.length);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("keep focus on the default time slot", () => {
|
||||||
|
|
||||||
|
expect(document.activeElement).toBe(document.getElementById('scheduled_for-0'));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test(`clicking the button for a category should add a 'Done' button below its options`, () => {
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
clickButtonForCategory(CATEGORIES[0]);
|
||||||
|
|
||||||
|
const button = document.querySelector('.radio-select-column:nth-child(2) input[type=button]');
|
||||||
|
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
expect(button.getAttribute('value')).toEqual('Done');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("after clicking the button to select that category", () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
// start module
|
||||||
|
window.GOVUK.modules.start();
|
||||||
|
|
||||||
|
clickButtonForCategory(CATEGORIES[0]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("clicking on an option with the mouse/trackpad should", () => {
|
||||||
|
|
||||||
|
let optionsColumn;
|
||||||
|
let firstOptionPositionSpy;
|
||||||
|
let firstOptionLabel;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
const firstOption = optionsColumn.querySelector('input[type=radio]');
|
||||||
|
firstOptionLabel = firstOption.parentNode.querySelector('label').textContent.trim();
|
||||||
|
|
||||||
|
helpers.clickElementWithMouse(firstOption);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("remove all the other options", () => {
|
||||||
|
|
||||||
|
// module replaces the column node so this needs querying again
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
expect(optionsColumn.querySelectorAll('input[type=radio]').length).toEqual(1);
|
||||||
|
expect(optionsColumn.querySelector('label').textContent.trim()).toEqual(firstOptionLabel);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add a button for choosing a different time", () => {
|
||||||
|
|
||||||
|
const button = document.querySelector('.radio-select-column:nth-child(3) input[type=button]');
|
||||||
|
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
expect(button.getAttribute('value')).toEqual('Choose a different time');
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
test("focus the selected option", () => {
|
||||||
|
|
||||||
|
selectedOption = document.querySelector('.radio-select-column:nth-child(2) input[checked=checked]');
|
||||||
|
|
||||||
|
expect(document.activeElement).toBe(selectedOption);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("selecting an option with the space key should", () => {
|
||||||
|
|
||||||
|
let optionsColumn;
|
||||||
|
let secondOptionLabel;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
const options = optionsColumn.querySelectorAll('input[type=radio]');
|
||||||
|
secondOptionLabel = options[1].parentNode.querySelector('label').textContent.trim();
|
||||||
|
|
||||||
|
helpers.moveSelectionToRadio(options[1], { 'direction': 'down' });
|
||||||
|
helpers.activateRadioWithSpace(options[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("remove all the other options", () => {
|
||||||
|
|
||||||
|
// module replaces the column node so this needs querying again
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
expect(optionsColumn.querySelectorAll('input[type=radio]').length).toEqual(1);
|
||||||
|
expect(optionsColumn.querySelector('label').textContent.trim()).toEqual(secondOptionLabel);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add a button for choosing a different time", () => {
|
||||||
|
|
||||||
|
const button = document.querySelector('.radio-select-column:nth-child(3) input[type=button]');
|
||||||
|
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
expect(button.getAttribute('value')).toEqual('Choose a different time');
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("selecting an option with the enter key should", () => {
|
||||||
|
|
||||||
|
let optionsColumn;
|
||||||
|
let secondOptionLabel;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
const options = optionsColumn.querySelectorAll('input[type=radio]');
|
||||||
|
secondOptionLabel = options[1].parentNode.querySelector('label').textContent.trim();
|
||||||
|
|
||||||
|
// simulate events for arrow key press moving selection to 2nd option
|
||||||
|
// event for down arrow key press
|
||||||
|
helpers.triggerEvent(options[1], 'keydown', {
|
||||||
|
eventInit: { which: 40 }
|
||||||
|
});
|
||||||
|
// click event fired from option radio being activated
|
||||||
|
helpers.triggerEvent(options[1], 'click', {
|
||||||
|
eventInit: { pageX: 0 }
|
||||||
|
});
|
||||||
|
|
||||||
|
// simulate events for enter key press to confirm selection
|
||||||
|
// event for enter key press
|
||||||
|
helpers.triggerEvent(options[1], 'keydown', {
|
||||||
|
eventInit: { which: 13 }
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("remove all the other options", () => {
|
||||||
|
|
||||||
|
// module replaces the column node so this needs querying again
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
expect(optionsColumn.querySelectorAll('input[type=radio]').length).toEqual(1);
|
||||||
|
expect(optionsColumn.querySelector('label').textContent.trim()).toEqual(secondOptionLabel);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add a button for choosing a different time", () => {
|
||||||
|
|
||||||
|
const button = document.querySelector('.radio-select-column:nth-child(3) input[type=button]');
|
||||||
|
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
expect(button.getAttribute('value')).toEqual('Choose a different time');
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("clicking the 'Done' button should choose whatever time is selected", () => {
|
||||||
|
|
||||||
|
let optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
const secondOption = optionsColumn.querySelectorAll('input[type=radio]')[1];
|
||||||
|
const secondOptionLabel = document.querySelector('label[for=' + secondOption.getAttribute('id')).textContent.trim();
|
||||||
|
const doneButton = document.querySelector('.radio-select-column:nth-child(2) input[type=button]');
|
||||||
|
|
||||||
|
// select second option
|
||||||
|
secondOption.checked = true;
|
||||||
|
secondOption.setAttribute('checked', '');
|
||||||
|
|
||||||
|
helpers.triggerEvent(doneButton, 'click');
|
||||||
|
|
||||||
|
optionsColumn = document.querySelector('.radio-select-column:nth-child(2)');
|
||||||
|
|
||||||
|
expect(optionsColumn.querySelectorAll('input[type=radio]').length).toEqual(1);
|
||||||
|
expect(optionsColumn.querySelector('label').textContent.trim()).toEqual(secondOptionLabel);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("after selecting an option clicking the 'Choose a different time' button should", () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
|
||||||
|
// select the first option
|
||||||
|
const firstOption = document.querySelector('.radio-select-column:nth-child(2) input[type=radio]');
|
||||||
|
|
||||||
|
helpers.clickElementWithMouse(firstOption);
|
||||||
|
|
||||||
|
// click the 'Choose a different time' button
|
||||||
|
const resetButton = document.querySelector('.radio-select-column:nth-child(3) input[type=button]');
|
||||||
|
helpers.triggerEvent(resetButton, 'click');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reset the module", () => {
|
||||||
|
|
||||||
|
categoryButtons = document.querySelectorAll('.radio-select-column:nth-child(2) .js-category-button');
|
||||||
|
|
||||||
|
expect(categoryButtons.length).toEqual(CATEGORIES.length);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus the default option", () => {
|
||||||
|
|
||||||
|
expect(document.activeElement).toBe(document.getElementById('scheduled_for-0'));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,12 +1,104 @@
|
|||||||
const triggerEvent = (el, evtType) => {
|
const triggerEvent = (el, evtType, options) => {
|
||||||
const evt = new Event(evtType, {
|
const eventInit = {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true
|
cancelable: true
|
||||||
});
|
};
|
||||||
|
let setPositionData = () => {
|
||||||
|
const browserUI = {
|
||||||
|
leftFrameBorder: 0,
|
||||||
|
topHeight: 100
|
||||||
|
};
|
||||||
|
const cursorOffset = {
|
||||||
|
x: 5,
|
||||||
|
y: 5
|
||||||
|
};
|
||||||
|
const elBoundingBox = el.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (!eventInit.clientX) { eventInit.clientX = elBoundingBox.left + cursorOffset.x; }
|
||||||
|
if (!eventInit.clientY) { eventInit.clientY = elBoundingBox.top + cursorOffset.y; }
|
||||||
|
if (!eventInit.pageX) { eventInit.pageX = elBoundingBox.left + cursorOffset.x; }
|
||||||
|
if (!eventInit.pageY) { eventInit.pageY = elBoundingBox.top + cursorOffset.y; }
|
||||||
|
if (!eventInit.screenX) { eventInit.screenX = eventInit.clientX + browserUI.leftFrameBorder; }
|
||||||
|
if (!eventInit.screenY) { eventInit.screenY = eventInit.clientY + browserUI.topHeight; }
|
||||||
|
if (!eventInit.offsetX) { eventInit.offsetX = cursorOffset.x; }
|
||||||
|
if (!eventInit.offsetY) { eventInit.offsetY = cursorOffset.y; }
|
||||||
|
};
|
||||||
|
let Instance;
|
||||||
|
|
||||||
|
// mixin any specified event properties with the defaults
|
||||||
|
if (options && ('eventInit' in options)) {
|
||||||
|
Object.assign(eventInit, options.eventInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use event interface if specified
|
||||||
|
if (options && ('interface' in options)) {
|
||||||
|
Instance = options.interface;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// otherwise, derive from the event type
|
||||||
|
switch (evtType) {
|
||||||
|
case 'click':
|
||||||
|
// click events are part of the MouseEvent interface
|
||||||
|
Instance = window.MouseEvent;
|
||||||
|
break;
|
||||||
|
case 'mousedown':
|
||||||
|
Instance = window.MouseEvent;
|
||||||
|
break;
|
||||||
|
case 'mouseup':
|
||||||
|
Instance = window.MouseEvent;
|
||||||
|
break;
|
||||||
|
case 'keydown':
|
||||||
|
Instance = window.KeyboardEvent;
|
||||||
|
break;
|
||||||
|
case 'keyup':
|
||||||
|
Instance = window.KeyboardEvent;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Instance = Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evtType === 'click') {
|
||||||
|
// hack for click events to simulate details of pointer interaction
|
||||||
|
setPositionData();
|
||||||
|
}
|
||||||
|
|
||||||
|
const evt = new Instance(evtType, eventInit);
|
||||||
|
|
||||||
el.dispatchEvent(evt);
|
el.dispatchEvent(evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function clickElementWithMouse (el) {
|
||||||
|
triggerEvent(el, 'mousedown');
|
||||||
|
triggerEvent(el, 'mouseup');
|
||||||
|
triggerEvent(el, 'click');
|
||||||
|
};
|
||||||
|
|
||||||
|
function moveSelectionToRadio (el, options) {
|
||||||
|
// movement within a radio group with arrow keys fires no keyboard events
|
||||||
|
|
||||||
|
// click event fired from option radio being activated
|
||||||
|
triggerEvent(el, 'click', {
|
||||||
|
eventInit: { pageX: 0 }
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function activateRadioWithSpace (el) {
|
||||||
|
|
||||||
|
// simulate events for space key press to confirm selection
|
||||||
|
// event for space key press
|
||||||
|
triggerEvent(el, 'keydown', {
|
||||||
|
eventInit: { which: 32 }
|
||||||
|
});
|
||||||
|
// click event fired from option radio being activated
|
||||||
|
triggerEvent(el, 'click', {
|
||||||
|
eventInit: { pageX: 0 }
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class ElementQuery {
|
class ElementQuery {
|
||||||
constructor (el) {
|
constructor (el) {
|
||||||
this.el = el;
|
this.el = el;
|
||||||
@@ -141,5 +233,8 @@ const element = function (el) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.triggerEvent = triggerEvent;
|
exports.triggerEvent = triggerEvent;
|
||||||
|
exports.clickElementWithMouse = clickElementWithMouse;
|
||||||
|
exports.moveSelectionToRadio = moveSelectionToRadio;
|
||||||
|
exports.activateRadioWithSpace = activateRadioWithSpace;
|
||||||
exports.element = element;
|
exports.element = element;
|
||||||
exports.WindowMock = WindowMock;
|
exports.WindowMock = WindowMock;
|
||||||
|
|||||||
Reference in New Issue
Block a user