fix(combobox): displayoverlay on keydown event

Co-authored-by: Thijs Louisse <Thijs.Louisse@ing.com>
This commit is contained in:
palash2601 2021-02-15 14:23:57 +01:00 committed by Thijs Louisse
parent 3aa4783326
commit 63e05c36e3
4 changed files with 221 additions and 83 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/combobox': patch
---
Combobox evaluates show condition after keyup(instead of keydown), so textbox value is updated

View file

@ -390,8 +390,12 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
*/
// eslint-disable-next-line class-methods-use-this
_showOverlayCondition({ lastKey }) {
const doNotOpenOn = ['Tab', 'Esc', 'Enter'];
return lastKey && !doNotOpenOn.includes(lastKey);
// when no keyboard action involved (on focused change), return current opened state
if (!lastKey) {
return this.opened;
}
const doNotShowOn = ['Tab', 'Esc', 'Enter'];
return !doNotShowOn.includes(lastKey);
}
/**
@ -699,7 +703,7 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
*/
_setupOpenCloseListeners() {
super._setupOpenCloseListeners();
this._inputNode.addEventListener('keydown', this.__requestShowOverlay);
this._inputNode.addEventListener('keyup', this.__requestShowOverlay);
}
/**
@ -707,7 +711,7 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
*/
_teardownOpenCloseListeners() {
super._teardownOpenCloseListeners();
this._inputNode.removeEventListener('keydown', this.__requestShowOverlay);
this._inputNode.removeEventListener('keyup', this.__requestShowOverlay);
}
/**
@ -806,13 +810,9 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
* @param {KeyboardEvent} [ev]
*/
__requestShowOverlay(ev) {
if (
this._showOverlayCondition({
lastKey: ev && ev.key,
currentValue: this._inputNode.value,
})
) {
this.opened = true;
}
this.opened = this._showOverlayCondition({
lastKey: ev && ev.key,
currentValue: this._inputNode.value,
});
}
}

View file

@ -20,9 +20,19 @@ function mimicUserTyping(el, value) {
// eslint-disable-next-line no-param-reassign
el._inputNode.value = value;
el._inputNode.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
el._inputNode.dispatchEvent(new KeyboardEvent('keyup', { key: value }));
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: value }));
}
/**
* @param {HTMLInputElement} el
* @param {string} key
*/
function mimicKeyPress(el, key) {
el.dispatchEvent(new KeyboardEvent('keydown', { key }));
el.dispatchEvent(new KeyboardEvent('keyup', { key }));
}
/**
* @param {LionCombobox} el
* @param {string[]} values
@ -53,7 +63,7 @@ async function mimicUserTypingAdvanced(el, values) {
inputNode.value += key;
}
inputNode.dispatchEvent(new KeyboardEvent('keydown', { key }));
mimicKeyPress(inputNode, key);
el._inputNode.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
el.updateComplete.then(() => {
@ -264,7 +274,7 @@ describe('lion-combobox', () => {
expect(el.opened).to.equal(false);
});
it('shows overlay again after select and char keydown', async () => {
it('shows overlay again after select and char keyup', async () => {
/**
* Scenario:
* [1] user focuses textbox: overlay hidden
@ -348,7 +358,7 @@ describe('lion-combobox', () => {
expect(el.opened).to.equal(true);
expect(el._inputNode.value).to.equal('Artichoke');
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab' }));
mimicKeyPress(el._inputNode, 'Tab');
expect(el.opened).to.equal(false);
expect(el._inputNode.value).to.equal('Artichoke');
});
@ -405,6 +415,79 @@ describe('lion-combobox', () => {
await el.updateComplete;
expect(el.opened).to.equal(true);
});
it('allows to control overlay visibility via "_showOverlayCondition": should not display overlay if currentValue length condition is not fulfilled', async () => {
class ShowOverlayConditionCombobox extends LionCombobox {
/** @param {{ currentValue: string, lastKey:string }} options */
_showOverlayCondition(options) {
return options.currentValue.length > 3 && super._showOverlayCondition(options);
}
}
const tagName = defineCE(ShowOverlayConditionCombobox);
const tag = unsafeStatic(tagName);
const el = /** @type {LionCombobox} */ (await fixture(html`
<${tag} name="foo">
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
</${tag}>
`));
mimicUserTyping(el, 'aaa');
expect(el.opened).to.be.false;
});
it('allows to control overlay visibility via "_showOverlayCondition": should display overlay if currentValue length condition is fulfilled', async () => {
class ShowOverlayConditionCombobox extends LionCombobox {
/** @param {{ currentValue: string, lastKey:string }} options */
_showOverlayCondition(options) {
return options.currentValue.length > 3 && super._showOverlayCondition(options);
}
}
const tagName = defineCE(ShowOverlayConditionCombobox);
const tag = unsafeStatic(tagName);
const el = /** @type {LionCombobox} */ (await fixture(html`
<${tag} name="foo">
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
</${tag}>
`));
mimicUserTyping(el, 'aaaa');
expect(el.opened).to.be.true;
});
it('allows to control overlay visibility via "_showOverlayCondition": should not display overlay if currentValue length condition is not fulfilled after once fulfilled', async () => {
class ShowOverlayConditionCombobox extends LionCombobox {
/** @param {{ currentValue: string, lastKey:string }} options */
_showOverlayCondition(options) {
return options.currentValue.length > 3 && super._showOverlayCondition(options);
}
}
const tagName = defineCE(ShowOverlayConditionCombobox);
const tag = unsafeStatic(tagName);
const el = /** @type {LionCombobox} */ (await fixture(html`
<${tag} name="foo">
<lion-option .choiceValue="${'Artichoke'}">Artichoke</lion-option>
<lion-option .choiceValue="${'Chard'}">Chard</lion-option>
<lion-option .choiceValue="${'Chicory'}">Chicory</lion-option>
<lion-option .choiceValue="${'Victoria Plum'}">Victoria Plum</lion-option>
</${tag}>
`));
mimicUserTyping(el, 'aaaa');
expect(el.opened).to.be.true;
mimicUserTyping(el, 'aaa');
await el.updateComplete;
expect(el.opened).to.be.false;
});
});
describe('Accessibility', () => {
@ -488,7 +571,7 @@ describe('lion-combobox', () => {
expect(el.checkedIndex).to.equal(0);
// Simulate backspace deleting the char at the end of the string
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));
mimicKeyPress(el._inputNode, 'Backspace');
el._inputNode.dispatchEvent(new Event('input'));
const arr = el._inputNode.value.split('');
arr.splice(el._inputNode.value.length - 1, 1);
@ -1123,11 +1206,11 @@ describe('lion-combobox', () => {
expect(el.activeIndex).to.equal(1);
});
it('changes whether active index is set to the closest match automatically depending on autocomplete', async () => {
it('changes whether activeIndex is set to the closest match automatically depending on autocomplete', async () => {
/**
* Automatic selection (setting activeIndex to closest matching option) in lion is set for inline & both autocomplete,
* because it is unavoidable there
* For list & none autocomplete, it is turned off and manual selection is required.
* Automatic selection (setting activeIndex to closest matching option) in lion is set for
* 'inline' & 'both' autocomplete, because it is unavoidable there
* For 'list' & 'none' autocomplete, it is turned off and manual selection is required.
* TODO: Make this configurable for list & none autocomplete?
*/
const el = /** @type {LionCombobox} */ (await fixture(html`
@ -1139,49 +1222,64 @@ describe('lion-combobox', () => {
</lion-combobox>
`));
/** @param {LionCombobox} elm */
function reset(elm) {
/**
* @param {LionCombobox} elm
* @param {'none'|'list'|'inline'|'both'} autocomplete
*/
async function setup(elm, autocomplete) {
// eslint-disable-next-line no-param-reassign
elm.autocomplete = autocomplete;
// eslint-disable-next-line no-param-reassign
elm.activeIndex = -1;
// eslint-disable-next-line no-param-reassign
elm.checkedIndex = -1;
// eslint-disable-next-line no-param-reassign
elm.opened = true;
await elm.updateComplete;
}
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
// Example 1. List Autocomplete with Manual Selection:
// does not set active at all until user selects
reset(el);
el.autocomplete = 'none';
await setup(el, 'none');
mimicUserTyping(/** @type {LionCombobox} */ (el), 'cha');
await el.updateComplete;
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
expect(el.activeIndex).to.equal(-1);
expect(el.opened).to.be.true;
mimicKeyPress(el._inputNode, 'Enter');
expect(el.opened).to.be.false;
expect(el.activeIndex).to.equal(-1);
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
// Example 2. List Autocomplete with Automatic Selection:
// does not set active at all until user selects
reset(el);
el.autocomplete = 'list';
await setup(el, 'list');
mimicUserTyping(/** @type {LionCombobox} */ (el), 'cha');
await el.updateComplete;
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
expect(el.activeIndex).to.equal(-1);
expect(el.opened).to.be.true;
expect(el.activeIndex).to.equal(-1);
mimicKeyPress(el._inputNode, 'Enter');
expect(el.activeIndex).to.equal(-1);
expect(el.opened).to.be.false;
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
// Example 3. List with Inline Autocomplete (mostly, but with aria-autocomplete="inline")
reset(el);
el.autocomplete = 'inline';
await setup(el, 'inline');
mimicUserTyping(/** @type {LionCombobox} */ (el), '');
await el.updateComplete;
mimicUserTyping(/** @type {LionCombobox} */ (el), 'cha');
await el.updateComplete;
await el.updateComplete;
expect(el.opened).to.be.true;
expect(el.activeIndex).to.equal(1);
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(el._inputNode, 'Enter');
await el.updateComplete;
await el.updateComplete;
@ -1190,13 +1288,12 @@ describe('lion-combobox', () => {
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
// Example 3. List with Inline Autocomplete
reset(el);
el.autocomplete = 'both';
await setup(el, 'both');
mimicUserTyping(/** @type {LionCombobox} */ (el), '');
await el.updateComplete;
mimicUserTyping(/** @type {LionCombobox} */ (el), 'cha');
await el.updateComplete;
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(el._inputNode, 'Enter');
expect(el.activeIndex).to.equal(1);
expect(el.opened).to.be.false;
});
@ -1225,7 +1322,7 @@ describe('lion-combobox', () => {
// select artichoke
mimicUserTyping(/** @type {LionCombobox} */ (el), 'artichoke');
await el.updateComplete;
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(el._inputNode, 'Enter');
mimicUserTyping(/** @type {LionCombobox} */ (el), '');
await el.updateComplete;
@ -1247,10 +1344,10 @@ describe('lion-combobox', () => {
// Select something
mimicUserTyping(/** @type {LionCombobox} */ (el), 'cha');
await el.updateComplete;
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(el._inputNode, 'Enter');
expect(el.activeIndex).to.equal(1);
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
mimicKeyPress(el._inputNode, 'Escape');
await el.updateComplete;
expect(el._inputNode.textContent).to.equal('');
@ -1293,7 +1390,8 @@ describe('lion-combobox', () => {
mimicUserTyping(/** @type {LionCombobox} */ (el), 'ch');
await el.updateComplete;
expect(el._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(null);
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(el._inputNode, 'ArrowDown');
expect(el._activeDescendantOwnerNode.getAttribute('aria-activedescendant')).to.equal(
'artichoke-option',
);

View file

@ -14,6 +14,15 @@ import sinon from 'sinon';
const fixture = /** @type {(arg: TemplateResult) => Promise<LionListbox>} */ (_fixture);
/**
* @param {HTMLElement} el
* @param {string} key
*/
function mimicKeyPress(el, key) {
el.dispatchEvent(new KeyboardEvent('keydown', { key }));
el.dispatchEvent(new KeyboardEvent('keyup', { key }));
}
/**
* @param {LionListbox} lionListboxEl
*/
@ -382,7 +391,8 @@ export function runListboxMixinSuite(customConfig = {}) {
el.activeIndex = 0;
await el.updateComplete;
expect(activeDescendantOwner.getAttribute('aria-activedescendant')).to.equal('first');
activeDescendantOwner.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(activeDescendantOwner, 'ArrowDown');
// activeDescendantOwner.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
await el.updateComplete;
expect(activeDescendantOwner.getAttribute('aria-activedescendant')).to.equal('second');
});
@ -537,12 +547,17 @@ export function runListboxMixinSuite(customConfig = {}) {
// Normalize
el.activeIndex = 0;
const options = el.formElements;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
// mimicKeyPress(listbox, 'ArrowUp');
mimicKeyPress(listbox, 'ArrowUp');
expect(options[0].active).to.be.true;
expect(options[1].active).to.be.false;
expect(options[2].active).to.be.false;
el.activeIndex = 2;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
// mimicKeyPress(listbox, 'ArrowDown');
mimicKeyPress(listbox, 'ArrowDown');
expect(options[0].active).to.be.false;
expect(options[1].active).to.be.false;
expect(options[2].active).to.be.true;
@ -563,14 +578,20 @@ export function runListboxMixinSuite(customConfig = {}) {
el.activeIndex = 0;
expect(el.activeIndex).to.equal(0);
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
mimicKeyPress(el._inputNode, 'ArrowUp');
await el.updateComplete;
expect(el.activeIndex).to.equal(2);
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(el._inputNode, 'ArrowDown');
expect(el.activeIndex).to.equal(0);
// Extra check: regular navigation
el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
// el._inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(el._inputNode, 'ArrowDown');
expect(el.activeIndex).to.equal(1);
});
});
@ -590,8 +611,8 @@ export function runListboxMixinSuite(customConfig = {}) {
el.activeIndex = 0;
const options = el.formElements;
el.checkedIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'ArrowDown');
mimicKeyPress(listbox, 'Enter');
expect(options[1].checked).to.be.true;
});
});
@ -613,14 +634,16 @@ export function runListboxMixinSuite(customConfig = {}) {
el.activeIndex = 0;
const options = el.formElements;
el.checkedIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
mimicKeyPress(listbox, 'ArrowDown');
mimicKeyPress(listbox, ' ');
expect(options[1].checked).to.be.true;
el.checkedIndex = 0;
// @ts-ignore allow protected member access in test
el._listboxReceivesNoFocus = true;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
mimicKeyPress(listbox, 'ArrowDown');
mimicKeyPress(listbox, ' ');
expect(options[1].checked).to.be.false;
});
});
@ -668,9 +691,9 @@ export function runListboxMixinSuite(customConfig = {}) {
}
el.activeIndex = 2;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home' }));
mimicKeyPress(listbox, 'Home');
expect(el.activeIndex).to.equal(0);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'End' }));
mimicKeyPress(listbox, 'End');
expect(el.activeIndex).to.equal(3);
});
it('navigates through open lists with [ArrowDown] [ArrowUp] keys activates the option', async () => {
@ -690,10 +713,11 @@ export function runListboxMixinSuite(customConfig = {}) {
el.selectionFollowsFocus = false;
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(-1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(-1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
mimicKeyPress(listbox, 'ArrowUp');
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(-1);
});
@ -718,21 +742,24 @@ export function runListboxMixinSuite(customConfig = {}) {
expect(options[0].active).to.be.true;
expect(options[1].active).to.be.false;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(options[0].active).to.be.false;
expect(options[1].active).to.be.true;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
mimicKeyPress(listbox, 'ArrowUp');
expect(options[0].active).to.be.true;
expect(options[1].active).to.be.false;
// No response to horizontal arrows...
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }));
mimicKeyPress(listbox, 'ArrowRight');
expect(options[0].active).to.be.true;
expect(options[1].active).to.be.false;
el.activeIndex = 1;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
mimicKeyPress(listbox, 'ArrowLeft');
expect(options[0].active).to.be.false;
expect(options[1].active).to.be.true;
});
@ -753,18 +780,21 @@ export function runListboxMixinSuite(customConfig = {}) {
await el.updateComplete;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }));
mimicKeyPress(listbox, 'ArrowRight');
expect(el.activeIndex).to.equal(1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
mimicKeyPress(listbox, 'ArrowLeft');
expect(el.activeIndex).to.equal(0);
// No response to vertical arrows...
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(0);
el.activeIndex = 1;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
mimicKeyPress(listbox, 'ArrowUp');
expect(el.activeIndex).to.equal(1);
});
@ -834,13 +864,13 @@ export function runListboxMixinSuite(customConfig = {}) {
// Enter
el.activeIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
el.activeIndex = 1;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
expect(options[0].checked).to.equal(true);
expect(el.modelValue).to.eql(['Artichoke', 'Chard']);
// also deselect
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
expect(options[0].checked).to.equal(true);
expect(el.modelValue).to.eql(['Artichoke']);
@ -855,13 +885,16 @@ export function runListboxMixinSuite(customConfig = {}) {
// Space
el.activeIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
mimicKeyPress(listbox, ' ');
el.activeIndex = 1;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
mimicKeyPress(listbox, ' ');
expect(options[0].checked).to.equal(true);
expect(el.modelValue).to.eql(['Artichoke', 'Chard']);
// also deselect
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }));
mimicKeyPress(listbox, ' ');
expect(options[0].checked).to.equal(true);
expect(el.modelValue).to.eql(['Artichoke']);
});
@ -925,11 +958,12 @@ export function runListboxMixinSuite(customConfig = {}) {
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(0);
expectOnlyGivenOneOptionToBeChecked(options, 0);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(1);
expectOnlyGivenOneOptionToBeChecked(options, 1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }));
mimicKeyPress(listbox, 'ArrowUp');
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(0);
expectOnlyGivenOneOptionToBeChecked(options, 0);
@ -964,11 +998,13 @@ export function runListboxMixinSuite(customConfig = {}) {
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(0);
expectOnlyGivenOneOptionToBeChecked(options, 0);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }));
mimicKeyPress(listbox, 'ArrowRight');
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(1);
expectOnlyGivenOneOptionToBeChecked(options, 1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
mimicKeyPress(listbox, 'ArrowLeft');
expect(el.activeIndex).to.equal(0);
expect(el.checkedIndex).to.equal(0);
expectOnlyGivenOneOptionToBeChecked(options, 0);
@ -990,9 +1026,9 @@ export function runListboxMixinSuite(customConfig = {}) {
}
expect(el.modelValue).to.equal('30');
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home' }));
mimicKeyPress(listbox, 'Home');
expect(el.modelValue).to.equal('10');
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'End' }));
mimicKeyPress(listbox, 'End');
expect(el.modelValue).to.equal('40');
});
});
@ -1009,7 +1045,7 @@ export function runListboxMixinSuite(customConfig = {}) {
await el.updateComplete;
const { checkedIndex } = el;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.checkedIndex).to.equal(checkedIndex);
});
@ -1065,11 +1101,11 @@ export function runListboxMixinSuite(customConfig = {}) {
// Normalize activeIndex across multiple implementers of ListboxMixinSuite
el.activeIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(0);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
// Checked index stays where it was
expect(el.checkedIndex).to.equal(0);
});
@ -1087,11 +1123,11 @@ export function runListboxMixinSuite(customConfig = {}) {
// Normalize activeIndex across multiple implementers of ListboxMixinSuite
el.activeIndex = 0;
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(1);
expect(el.checkedIndex).to.equal(-1);
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));
mimicKeyPress(listbox, 'ArrowDown');
expect(el.activeIndex).to.equal(2);
expect(el.checkedIndex).to.equal(2);
});
@ -1318,8 +1354,7 @@ export function runListboxMixinSuite(customConfig = {}) {
// Allow options that behave like anchors (think of Google Search) to trigger the anchor behavior
const activeOption = el.formElements[1];
const clickSpy = sinon.spy(activeOption, 'click');
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
expect(clickSpy).to.have.been.calledOnce;
});
@ -1339,7 +1374,7 @@ export function runListboxMixinSuite(customConfig = {}) {
const activeOption = el.formElements[0];
const clickSpy = sinon.spy(activeOption, 'click');
listbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
mimicKeyPress(listbox, 'Enter');
expect(clickSpy).to.not.have.been.called;
});