From 63e05c36e32ce3679f11a97b4919fdd3b0602909 Mon Sep 17 00:00:00 2001 From: palash2601 Date: Mon, 15 Feb 2021 14:23:57 +0100 Subject: [PATCH] fix(combobox): displayoverlay on keydown event Co-authored-by: Thijs Louisse --- .changeset/four-days-pull.md | 5 + packages/combobox/src/LionCombobox.js | 24 +-- packages/combobox/test/lion-combobox.test.js | 152 ++++++++++++++---- .../listbox/test-suites/ListboxMixin.suite.js | 123 +++++++++----- 4 files changed, 221 insertions(+), 83 deletions(-) create mode 100644 .changeset/four-days-pull.md diff --git a/.changeset/four-days-pull.md b/.changeset/four-days-pull.md new file mode 100644 index 000000000..57da67109 --- /dev/null +++ b/.changeset/four-days-pull.md @@ -0,0 +1,5 @@ +--- +'@lion/combobox': patch +--- + +Combobox evaluates show condition after keyup(instead of keydown), so textbox value is updated diff --git a/packages/combobox/src/LionCombobox.js b/packages/combobox/src/LionCombobox.js index 955f1a15d..0d4b394e7 100644 --- a/packages/combobox/src/LionCombobox.js +++ b/packages/combobox/src/LionCombobox.js @@ -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, + }); } } diff --git a/packages/combobox/test/lion-combobox.test.js b/packages/combobox/test/lion-combobox.test.js index a3097fd91..f95242c75 100644 --- a/packages/combobox/test/lion-combobox.test.js +++ b/packages/combobox/test/lion-combobox.test.js @@ -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"> + Artichoke + Chard + Chicory + Victoria Plum + + `)); + + 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"> + Artichoke + Chard + Chicory + Victoria Plum + + `)); + + 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"> + Artichoke + Chard + Chicory + Victoria Plum + + `)); + + 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', () => { `)); - /** @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', ); diff --git a/packages/listbox/test-suites/ListboxMixin.suite.js b/packages/listbox/test-suites/ListboxMixin.suite.js index ab2c8fa70..bf68d1a37 100644 --- a/packages/listbox/test-suites/ListboxMixin.suite.js +++ b/packages/listbox/test-suites/ListboxMixin.suite.js @@ -14,6 +14,15 @@ import sinon from 'sinon'; const fixture = /** @type {(arg: TemplateResult) => Promise} */ (_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; });