From 3543018d9943d5e14ffcaa352339e04f6f6c4738 Mon Sep 17 00:00:00 2001 From: Dave Lockhart Date: Tue, 20 Jun 2023 12:38:37 -0400 Subject: [PATCH] switch to @brightspace-ui/testing mouse and keyboard commands (#3759) --- .../dropdown/test/dropdown-content.test.js | 14 +-- components/filter/test/filter.test.js | 9 +- .../list/test/list-item-drag-handle.test.js | 6 +- components/list/test/list.test.js | 22 ++--- components/menu/test/menu.test.js | 85 +++++++------------ components/switch/test/switch.test.js | 6 +- components/tooltip/test/tooltip.test.js | 16 ++-- directives/animate/test/animate.test.js | 6 +- package-lock.json | 8 +- package.json | 2 +- 10 files changed, 75 insertions(+), 99 deletions(-) diff --git a/components/dropdown/test/dropdown-content.test.js b/components/dropdown/test/dropdown-content.test.js index bcb470e572c..aa8a11a2b7e 100644 --- a/components/dropdown/test/dropdown-content.test.js +++ b/components/dropdown/test/dropdown-content.test.js @@ -1,7 +1,7 @@ import '../dropdown.js'; import '../dropdown-content.js'; import { aTimeout, expect, fixture, html, nextFrame, oneEvent } from '@open-wc/testing'; -import { focusWithKeyboard } from '@brightspace-ui/testing'; +import { focusElem } from '@brightspace-ui/testing'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; const normalFixture = html` @@ -226,7 +226,7 @@ describe('d2l-dropdown', () => { content.setAttribute('opened', true); await oneEvent(content, 'd2l-dropdown-open'); await nextFrame(); - setTimeout(() => focusWithKeyboard(dropdown.querySelector('#focusable_outside'))); + setTimeout(() => focusElem(dropdown.querySelector('#focusable_outside'))); await oneEvent(content, 'd2l-dropdown-close'); expect(content.opened).to.be.false; }); @@ -263,7 +263,7 @@ describe('d2l-dropdown', () => { await oneEvent(content, 'd2l-dropdown-open'); await nextFrame(); - await focusWithKeyboard(dropdown.querySelector('#focusable_outside')); + await focusElem(dropdown.querySelector('#focusable_outside')); await aTimeout(100); expect(content.opened).to.be.true; }); @@ -273,7 +273,7 @@ describe('d2l-dropdown', () => { await oneEvent(content, 'd2l-dropdown-open'); await nextFrame(); - await focusWithKeyboard(content.querySelector('#focusable_inside')); + await focusElem(content.querySelector('#focusable_inside')); await aTimeout(100); expect(content.opened).to.be.true; }); @@ -287,7 +287,7 @@ describe('d2l-dropdown', () => { // which causes focus to be lost and activeElement to become // document.body document.body.setAttribute('tabindex', '-1'); - await focusWithKeyboard(document.body); + await focusElem(document.body); await aTimeout(100); expect(content.opened).to.be.true; }); @@ -303,7 +303,7 @@ describe('d2l-dropdown', () => { // this simulates a click on an element inside the dropdown, // which causes focus to be lost and activeElement to become // the focusable ancestor of the dropdown - await focusWithKeyboard(focusableAncestor); + await focusElem(focusableAncestor); await aTimeout(100); expect(content.opened).to.be.true; }); @@ -653,7 +653,7 @@ describe('d2l-dropdown', () => { content.setAttribute('opened', true); await oneEvent(content, 'd2l-dropdown-open'); await nextFrame(); - setTimeout(() => focusWithKeyboard(dropdown.querySelector('#focusable_outside'))); + setTimeout(() => focusElem(dropdown.querySelector('#focusable_outside'))); await oneEvent(content, 'd2l-dropdown-close'); expect(content.opened).to.be.false; }); diff --git a/components/filter/test/filter.test.js b/components/filter/test/filter.test.js index fa1b4619361..ac9c2b615c3 100644 --- a/components/filter/test/filter.test.js +++ b/components/filter/test/filter.test.js @@ -495,10 +495,11 @@ describe('d2l-filter', () => { expect(dimensions[0].dimensionKey).to.equal('dim'); expect(dimensions[0].cleared).to.be.false; expect(dimensions[0].changes.length).to.equal(2); - expect(dimensions[0].changes[0].valueKey).to.equal('2'); - expect(dimensions[0].changes[0].selected).to.be.true; - expect(dimensions[0].changes[1].valueKey).to.equal('1'); - expect(dimensions[0].changes[1].selected).to.be.false; + + const change1 = dimensions[0].changes.find(e => e.valueKey === '1'); + const change2 = dimensions[0].changes.find(e => e.valueKey === '2'); + expect(change2.selected).to.be.true; + expect(change1.selected).to.be.false; expect(elem._dimensions[0].values[0].selected).to.be.false; expect(elem._dimensions[0].values[1].selected).to.be.true; diff --git a/components/list/test/list-item-drag-handle.test.js b/components/list/test/list-item-drag-handle.test.js index 9ef0808fe17..81742d00639 100644 --- a/components/list/test/list-item-drag-handle.test.js +++ b/components/list/test/list-item-drag-handle.test.js @@ -1,7 +1,7 @@ import { expect, fixture, html, oneEvent } from '@open-wc/testing'; import { dragActions } from '../list-item-drag-handle.js'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; -import { sendKeys } from '@web/test-runner-commands'; +import { sendKeysElem } from '@brightspace-ui/testing'; describe('ListItemDragHandle', () => { @@ -90,9 +90,9 @@ describe('ListItemDragHandle', () => { async function dispatchKeyEvent(el, key, shiftKey = false) { if (shiftKey) { - await sendKeys({ press: `Shift+${key}` }); + await sendKeysElem('press', `Shift+${key}`, el); } else { - await sendKeys({ press: key }); + await sendKeysElem('press', key, el); } } diff --git a/components/list/test/list.test.js b/components/list/test/list.test.js index c66b0ab7677..47dfea5db08 100644 --- a/components/list/test/list.test.js +++ b/components/list/test/list.test.js @@ -4,9 +4,8 @@ import '../list-item.js'; import '../list-item-button.js'; import '../list-item-content.js'; import { expect, fixture, html, oneEvent, waitUntil } from '@open-wc/testing'; -import { focusWithKeyboard } from '@brightspace-ui/testing'; +import { focusElem, sendKeysElem } from '@brightspace-ui/testing'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; -import { sendKeys } from '@web/test-runner-commands'; const awaitListElementUpdates = async(rootElement, queries) => { await rootElement.updateComplete; @@ -114,11 +113,10 @@ describe('d2l-list', () => { const listItem = elem.querySelector('[key="L2-2"]'); const listItemLayout = elem.querySelector('[key="L2-2"]').shadowRoot.querySelector('d2l-list-item-generic-layout'); - await focusWithKeyboard(listItem); + await focusElem(listItem); await waitUntil(() => listItem.hasAttribute('_focusing'), 'List item should be focused', { timeout: 3000 }); - await focusWithKeyboard(listItemLayout); - setTimeout(() => sendKeys({ down: testCase.keyPress })); + setTimeout(() => sendKeysElem('down', testCase.keyPress, listItemLayout)); await oneEvent(listItemLayout, 'keydown'); expect(listItem.hasAttribute('_focusing')).to.be.true; @@ -157,15 +155,14 @@ describe('d2l-list', () => { const listItem = elem.querySelector('[key="L2-2"]'); const listItemLayout = elem.querySelector('[key="L2-2"]').shadowRoot.querySelector('d2l-list-item-generic-layout'); - await focusWithKeyboard(listItem); - await waitUntil(() => listItem.hasAttribute('_focusing'), 'List item should be focused', { timeout: 3000 }); + await focusElem(listItem); + await waitUntil(() => listItem.hasAttribute('_focusing'), 'Initial item should be focused', { timeout: 3000 }); - await focusWithKeyboard(listItemLayout); - setTimeout(() => sendKeys({ down: testCase.keyPress })); + setTimeout(() => sendKeysElem('down', testCase.keyPress, listItemLayout)); await oneEvent(listItemLayout, 'keydown'); const focusedElement = elem.querySelector(`[key=${testCase.expectedFocus}`); - expect(focusedElement.hasAttribute('_focusing')).to.be.true; + await waitUntil(() => focusedElement.hasAttribute('_focusing'), 'Next item should be focused', { timeout: 3000 }); }); }); @@ -185,11 +182,10 @@ describe('d2l-list', () => { const listItem = elem.querySelector('[key="L1-2"]'); const listItemLayout = elem.querySelector('[key="L1-2"]').shadowRoot.querySelector('d2l-list-item-generic-layout'); - await focusWithKeyboard(listItem); + await focusElem(listItem); await waitUntil(() => listItem.hasAttribute('_focusing'), 'List item should be focused', { timeout: 3000 }); - await focusWithKeyboard(listItemLayout); - setTimeout(() => sendKeys({ down: 'ArrowUp' })); + setTimeout(() => sendKeysElem('down', 'ArrowUp', listItemLayout)); await oneEvent(listItemLayout, 'keydown'); expect(listItem.hasAttribute('_focusing')).to.be.true; diff --git a/components/menu/test/menu.test.js b/components/menu/test/menu.test.js index c3f0a67eeb0..1d23ecc6378 100644 --- a/components/menu/test/menu.test.js +++ b/components/menu/test/menu.test.js @@ -2,18 +2,12 @@ import '../menu.js'; import '../menu-item.js'; import '../menu-item-radio.js'; import './custom-slots.js'; +import { clickElem, focusElem, sendKeysElem, waitUntil } from '@brightspace-ui/testing'; import { defineCE, expect, fixture, html, nextFrame, oneEvent } from '@open-wc/testing'; import { LitElement } from 'lit'; import { MenuItemMixin } from '../menu-item-mixin.js'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; -function dispatchKeyEvent(elem, key) { - const eventObj = document.createEvent('Events'); - eventObj.initEvent('keydown', true, true); - eventObj.keyCode = key; - elem.dispatchEvent(eventObj); -} - describe('d2l-menu', () => { describe('accessibility', () => { @@ -82,57 +76,48 @@ describe('d2l-menu', () => { } }); - it('focuses on first visible menu item when focus() is called', () => { - elem.focus(); + it('focuses on first visible menu item when focus() is called', async() => { + await focusElem(elem); expect(document.activeElement).to.equal(elem.querySelector('#a1')); }); - it('moves focus to next focusable item when down arrow is pressed', () => { - dispatchKeyEvent(elem.querySelector('#c1'), 40); + it('moves focus to next focusable item when down arrow is pressed', async() => { + await sendKeysElem('press', 'ArrowDown', elem.querySelector('#c1')); expect(document.activeElement).to.equal(elem.querySelector('#d1')); }); - it('moves focus to previous focusable item when up arrow is pressed', () => { - dispatchKeyEvent(elem.querySelector('#d1'), 38); + it('moves focus to previous focusable item when up arrow is pressed', async() => { + await sendKeysElem('press', 'ArrowUp', elem.querySelector('#d1')); expect(document.activeElement).to.equal(elem.querySelector('#c1')); }); - it('moves focus to first focusable item when down arrow is pressed on last focusable item', () => { - dispatchKeyEvent(elem.querySelector('#d1'), 40); + it('moves focus to first focusable item when down arrow is pressed on last focusable item', async() => { + await sendKeysElem('press', 'ArrowDown', elem.querySelector('#d1')); expect(document.activeElement).to.equal(elem.querySelector('#a1')); }); - it('moves focus to last focusable item when up arrow is pressed on first focusable item', () => { - dispatchKeyEvent(elem.querySelector('#a1'), 38); + it('moves focus to last focusable item when up arrow is pressed on first focusable item', async() => { + await sendKeysElem('press', 'ArrowUp', elem.querySelector('#a1')); expect(document.activeElement).to.equal(elem.querySelector('#d1')); }); - it('sets focus to disabled menu items', () => { - dispatchKeyEvent(elem.querySelector('#a1'), 40); + it('sets focus to disabled menu items', async() => { + await sendKeysElem('press', 'ArrowDown', elem.querySelector('#a1')); expect(document.activeElement).to.equal(elem.querySelector('#b1')); }); - it('sets focus to next item that starts with character pressed', () => { - const eventObj = document.createEvent('Events'); - eventObj.initEvent('keypress', true, true); - eventObj.charCode = 99; - elem.querySelector('#a1').dispatchEvent(eventObj); + it('sets focus to next item that starts with character pressed', async() => { + await sendKeysElem('press', 'c', elem.querySelector('#a1')); expect(document.activeElement).to.equal(elem.querySelector('#c1')); }); - it('sets focus to next item that starts with uppercase character pressed', () => { - const eventObj = document.createEvent('Events'); - eventObj.initEvent('keypress', true, true); - eventObj.charCode = 67; - elem.querySelector('#a1').dispatchEvent(eventObj); + it('sets focus to next item that starts with uppercase character pressed', async() => { + await sendKeysElem('press', 'C', elem.querySelector('#a1')); expect(document.activeElement).to.equal(elem.querySelector('#c1')); }); - it('sets focus by rolling over to beginning of menu when searching if necessary', () => { - const eventObj = document.createEvent('Events'); - eventObj.initEvent('keypress', true, true); - eventObj.charCode = 98; - elem.querySelector('#c1').dispatchEvent(eventObj); + it('sets focus by rolling over to beginning of menu when searching if necessary', async() => { + await sendKeysElem('press', 'b', elem.querySelector('#c1')); expect(document.activeElement).to.equal(elem.querySelector('#b1')); }); @@ -146,7 +131,7 @@ describe('d2l-menu', () => { `); await nextFrame(); - elem.focus(); + await focusElem(elem); await expect(document.activeElement).to.equal(elem.querySelector('#r3')); }); @@ -176,51 +161,47 @@ describe('d2l-menu', () => { }); it('shows nested menu when opener is clicked', async() => { - setTimeout(() => elem.querySelector('#b1').click()); + setTimeout(() => clickElem(elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); expect(nestedMenu.isActive()).to.be.true; }); it('sets focus to d2l-menu-item-return when nested menu is displayed', async() => { - setTimeout(() => elem.querySelector('#b1').click()); + setTimeout(() => clickElem(elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); - let focused = (document.activeElement.tagName === 'D2L-MENU-ITEM-RETURN'); - if (!focused) { - focused = (document.activeElement === nestedMenu); - } - expect(focused).to.be.true; + await waitUntil(() => { + return (document.activeElement.tagName === 'D2L-MENU-ITEM-RETURN') || + (document.activeElement === nestedMenu); + }, 'Focus on return'); }); it('shows nested menu when right arrow is pressed on opener', async() => { - setTimeout(() => dispatchKeyEvent(elem.querySelector('#b1'), 39)); + setTimeout(() => sendKeysElem('press', 'ArrowRight', elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); expect(nestedMenu.isActive()).to.be.true; }); it('hides nested menu when left arrow is pressed in nested menu', async() => { - setTimeout(() => elem.querySelector('#b1').click()); + setTimeout(() => clickElem(elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); - setTimeout(() => dispatchKeyEvent(elem.querySelector('#b2'), 37)); + setTimeout(() => sendKeysElem('press', 'ArrowLeft', elem.querySelector('#b2'))); await oneEvent(elem, 'd2l-hierarchical-view-hide-complete'); expect(elem.isActive()).to.be.true; }); it('hides nested menu when escape is pressed in nested menu', async() => { - setTimeout(() => elem.querySelector('#b1').click()); + setTimeout(() => clickElem(elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); - const eventObj = document.createEvent('Events'); - eventObj.initEvent('keydown', true, true); - eventObj.keyCode = 27; - setTimeout(() => elem.querySelector('#b2').dispatchEvent(eventObj)); + setTimeout(() => sendKeysElem('press', 'Escape', elem.querySelector('#b2'))); await oneEvent(elem, 'd2l-hierarchical-view-hide-complete'); expect(elem.isActive()).to.be.true; }); it('hides nested menu when d2l-menu-item-return is clicked', async() => { - setTimeout(() => elem.querySelector('#b1').click()); + setTimeout(() => clickElem(elem.querySelector('#b1'))); await oneEvent(elem, 'd2l-hierarchical-view-show-complete'); const returnItem = elem.querySelector('#nestedMenu')._getMenuItemReturn(); - setTimeout(() => returnItem.click()); + setTimeout(() => clickElem(returnItem)); await oneEvent(elem, 'd2l-hierarchical-view-hide-complete'); expect(elem.isActive()).to.be.true; }); diff --git a/components/switch/test/switch.test.js b/components/switch/test/switch.test.js index d1a86eb6001..25c75609dd6 100644 --- a/components/switch/test/switch.test.js +++ b/components/switch/test/switch.test.js @@ -2,7 +2,7 @@ import '../switch.js'; import { expect, fixture, html, oneEvent } from '@open-wc/testing'; import { getComposedActiveElement } from '../../../helpers/focus.js'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; -import { sendKeys } from '@web/test-runner-commands'; +import { sendKeysElem } from '@brightspace-ui/testing'; const switchFixture = html``; @@ -41,9 +41,7 @@ describe('d2l-switch', () => { ['Space', 'Enter'].forEach((key) => { it(`should toggle when ${key} is pressed`, async() => { const elem = await fixture(switchFixture); - setTimeout(() => elem.focus()); - await oneEvent(elem, 'focus'); - setTimeout(() => sendKeys({ press: key })); + setTimeout(() => sendKeysElem('press', key, elem)); await oneEvent(elem, 'change'); expect(elem.on).to.be.true; }); diff --git a/components/tooltip/test/tooltip.test.js b/components/tooltip/test/tooltip.test.js index 0872bb065f3..8a0ffa8e50f 100644 --- a/components/tooltip/test/tooltip.test.js +++ b/components/tooltip/test/tooltip.test.js @@ -1,6 +1,6 @@ import '../tooltip.js'; import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing'; -import { focusWithKeyboard } from '@brightspace-ui/testing'; +import { focusElem } from '@brightspace-ui/testing'; import { runConstructor } from '../../../tools/constructor-test-helper.js'; const basicFixture = html` @@ -113,7 +113,7 @@ describe('d2l-tooltip', () => { describe('show-hide', () => { it('should show when target is focused', async() => { - await focusWithKeyboard(tooltipFixture.querySelector('#explicit-target')); + await focusElem(tooltipFixture.querySelector('#explicit-target')); await oneEvent(tooltipFixture, 'd2l-tooltip-show'); expect(tooltip.showing).to.be.true; }); @@ -126,7 +126,7 @@ describe('d2l-tooltip', () => { it('should hide from blur when target is focused', async() => { const target = tooltipFixture.querySelector('#explicit-target'); - await focusWithKeyboard(target); + await focusElem(target); await oneEvent(tooltipFixture, 'd2l-tooltip-show'); setTimeout(() => target.blur()); @@ -149,7 +149,7 @@ describe('d2l-tooltip', () => { const target = tooltipFixture.querySelector('#explicit-target'); target.dispatchEvent(new Event('mouseenter')); await oneEvent(tooltipFixture, 'd2l-tooltip-show'); - await focusWithKeyboard(target); + await focusElem(target); target.dispatchEvent(new Event('mouseleave')); await aTimeout(100); @@ -161,7 +161,7 @@ describe('d2l-tooltip', () => { const target = tooltipFixture.querySelector('#explicit-target'); target.dispatchEvent(new Event('mouseenter')); await oneEvent(tooltipFixture, 'd2l-tooltip-show'); - await focusWithKeyboard(target); + await focusElem(target); target.blur(); await aTimeout(100); @@ -177,7 +177,7 @@ describe('d2l-tooltip', () => { const target = tooltipFixture.querySelector('#explicit-target'); setTimeout(() => { if (testCase.focus) { - focusWithKeyboard(target); + focusElem(target); } if (testCase.hover) { target.dispatchEvent(new Event('mouseenter')); @@ -199,7 +199,7 @@ describe('d2l-tooltip', () => { it('should show if added to a target that already has focus', async() => { const target = tooltipFixture.querySelector('#explicit-target'); - await focusWithKeyboard(target); + await focusElem(target); const dynamicTooltip = document.createElement('d2l-tooltip'); dynamicTooltip.for = target.id; @@ -283,7 +283,7 @@ describe('d2l-tooltip', () => { const target = tooltipFixture.querySelector('#explicit-target'); target.dispatchEvent(new Event('mouseenter')); await oneEvent(tooltipFixture, 'd2l-tooltip-show'); - await focusWithKeyboard(target); + await focusElem(target); setTimeout(() => target.dispatchEvent(new Event('mouseleave'))); await oneEvent(tooltipFixture, 'd2l-tooltip-hide'); diff --git a/directives/animate/test/animate.test.js b/directives/animate/test/animate.test.js index 02efae08b33..a93a1c29e5c 100644 --- a/directives/animate/test/animate.test.js +++ b/directives/animate/test/animate.test.js @@ -1,5 +1,5 @@ +import { clickElem, focusElem } from '@brightspace-ui/testing'; import { expect, fixture, oneEvent } from '@open-wc/testing'; -import { focusWithKeyboard, focusWithMouse } from '@brightspace-ui/testing'; import { hide, show } from '../animate.js'; import { html, LitElement } from 'lit'; import { getComposedActiveElement } from '../../../helpers/focus.js'; @@ -77,7 +77,7 @@ describe('animate directive', () => { it('should move focus when element with visible focus is hidden', async() => { const elem = await fixture(html``); - await focusWithKeyboard(elem.shadowRoot.querySelector('#first')); + await focusElem(elem.shadowRoot.querySelector('#first')); elem.animate = true; await oneEvent(elem, 'd2l-animate-test-focus-animate-complete'); @@ -88,7 +88,7 @@ describe('animate directive', () => { it('should not move focus when element with non-visible focus is hidden', async() => { const elem = await fixture(html``); - await focusWithMouse(elem.shadowRoot.querySelector('#first')); + await clickElem(elem.shadowRoot.querySelector('#first')); elem.animate = true; await oneEvent(elem, 'd2l-animate-test-focus-animate-complete'); diff --git a/package-lock.json b/package-lock.json index 9cde4cf70d9..ab14b7d8176 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "devDependencies": { "@babel/eslint-parser": "^7", "@brightspace-ui/stylelint-config": "^0.8", - "@brightspace-ui/testing": "^0.7", + "@brightspace-ui/testing": "^0.9", "@open-wc/semantic-dom-diff": "^0.20", "@open-wc/testing": "^3", "@rollup/plugin-dynamic-import-vars": "^2", @@ -477,9 +477,9 @@ } }, "node_modules/@brightspace-ui/testing": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@brightspace-ui/testing/-/testing-0.7.0.tgz", - "integrity": "sha512-lPNWEiGjohBxYDCSR6loeO5bRzMYisFlEsoOxi8pOcIYKWa/y1drMD+9NPpdhXQdX7oqKzae2NC6U3G7mJnMhg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@brightspace-ui/testing/-/testing-0.9.0.tgz", + "integrity": "sha512-6Ck5eeMPn4J9RM/0S/H0Wvd/z+2r5xcq/erTWLiZrMdQoVJKe1g+t0o+I8LnaxERjR1P5uC2SZPD3Swtyg+QmQ==", "dev": true, "dependencies": { "@open-wc/testing": "^3", diff --git a/package.json b/package.json index f189d0f9c6b..b96c7214345 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "devDependencies": { "@babel/eslint-parser": "^7", "@brightspace-ui/stylelint-config": "^0.8", - "@brightspace-ui/testing": "^0.7", + "@brightspace-ui/testing": "^0.9", "@open-wc/semantic-dom-diff": "^0.20", "@open-wc/testing": "^3", "@rollup/plugin-dynamic-import-vars": "^2",