From d53acfbae9df2f21dc2293eb90a03a742b4f5bcf Mon Sep 17 00:00:00 2001 From: Dave Lockhart Date: Tue, 20 Jun 2023 10:09:00 -0400 Subject: [PATCH] feat: basic keyboard and mouse commands (#29) --- src/browser/commands.js | 45 +++++++++++++++++++++ src/browser/focus.js | 12 ------ src/browser/index.js | 2 +- test/browser/commands.test.js | 76 +++++++++++++++++++++++++++++++++++ test/browser/fixture.test.js | 9 ++--- 5 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 src/browser/commands.js delete mode 100644 src/browser/focus.js create mode 100644 test/browser/commands.test.js diff --git a/src/browser/commands.js b/src/browser/commands.js new file mode 100644 index 00000000..c54aaa8f --- /dev/null +++ b/src/browser/commands.js @@ -0,0 +1,45 @@ +import { sendKeys as cmdSendKeys, sendMouse } from '@web/test-runner-commands'; + +function getElementPosition(elem) { + const { x, y, width, height } = elem.getBoundingClientRect(); + return { + x: Math.floor(x + window.scrollX + width / 2), + y: Math.floor(y + window.scrollY + height / 2), + }; +} + +export async function clickAt(x, y) { + await sendMouse({ type: 'click', position: [x, y] }); +} + +export async function clickElem(elem) { + const position = getElementPosition(elem); + return clickAt(position.x, position.y); +} + +export async function focusElem(elem) { + await cmdSendKeys({ press: 'Shift' }); // Tab moves focus, Escape causes dismissible things to close + elem.focus({ focusVisible: true }); +} + +export async function hoverAt(x, y) { + await sendMouse({ type: 'move', position: [x, y] }); +} + +export async function hoverElem(elem) { + const position = getElementPosition(elem); + return hoverAt(position.x, position.y); +} + +export async function sendKeys(action, keys) { + const val = {}; + val[action] = keys; + await cmdSendKeys(val); +} + +export async function sendKeysElem(action, keys, elem) { + if (elem) { + await focusElem(elem); + } + return sendKeys(action, keys); +} diff --git a/src/browser/focus.js b/src/browser/focus.js deleted file mode 100644 index 69379445..00000000 --- a/src/browser/focus.js +++ /dev/null @@ -1,12 +0,0 @@ -import { sendKeys, sendMouse } from '@web/test-runner-commands'; - -export async function focusWithKeyboard(element) { - await sendKeys({ press: 'Shift' }); // Tab moves focus, Escape causes dismissible things to close - element.focus({ focusVisible: true }); -} - -export async function focusWithMouse(element) { - const { x, y } = element.getBoundingClientRect(); - await sendMouse({ type: 'click', position: [Math.ceil(x), Math.ceil(y)] }); - await sendMouse({ type: 'move', position: [0, 0] }); -} diff --git a/src/browser/index.js b/src/browser/index.js index 085fb7da..ec084456 100644 --- a/src/browser/index.js +++ b/src/browser/index.js @@ -1,5 +1,5 @@ import './vdiff.js'; export { assert, aTimeout, defineCE, expect, html, nextFrame, oneEvent, waitUntil } from '@open-wc/testing'; -export { focusWithKeyboard, focusWithMouse } from './focus.js'; +export { clickAt, clickElem, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem } from './commands.js'; export { fixture } from './fixture.js'; diff --git a/test/browser/commands.test.js b/test/browser/commands.test.js new file mode 100644 index 00000000..104321dd --- /dev/null +++ b/test/browser/commands.test.js @@ -0,0 +1,76 @@ +import { clickAt, clickElem, expect, fixture, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem } from '../../src/browser/index.js'; +import { html } from 'lit'; +import { spy } from 'sinon'; + +describe('commands', () => { + + let elem; + beforeEach(async() => { + elem = await fixture(html``); + }); + + it('should click on element', async() => { + const clickSpy = spy(); + elem.addEventListener('click', clickSpy); + await clickElem(elem); + expect(clickSpy).to.be.calledOnce; + }); + + it('should click at position', async() => { + const clickPos = { x: 0, y: 0 }; + function onClick(e) { + clickPos.x = e.clientX; + clickPos.y = e.clientY; + } + window.addEventListener('click', onClick); + await clickAt(200, 300); + expect(clickPos.x).to.equal(200); + expect(clickPos.y).to.equal(300); + window.removeEventListener('click', onClick); + }); + + it('should focus on element', async() => { + let focussed = false; + elem.addEventListener('focus', () => focussed = true); + await focusElem(elem); + expect(focussed).to.be.true; + }); + + it('should hover over element', async() => { + let hovered = false; + elem.addEventListener('mouseover', () => hovered = true); + elem.addEventListener('mouseout', () => hovered = false); + await hoverElem(elem); + expect(hovered).to.be.true; + }); + + it('should hover at position', async() => { + const mousePos = { x: 0, y: 0 }; + function onMouseMove(e) { + mousePos.x = e.clientX; + mousePos.y = e.clientY; + } + window.addEventListener('mousemove', onMouseMove); + await hoverAt(50, 100); + expect(mousePos.x).to.equal(50); + expect(mousePos.y).to.equal(100); + window.removeEventListener('mousemove', onMouseMove); + }); + + it('should send keys to element', async() => { + await sendKeysElem('type', 'Hello', elem); + expect(elem.value).to.equal('Hello'); + }); + + it('should send keys to browser', async() => { + let key = undefined; + function onKeyDown(e) { + key = e.key; + } + window.addEventListener('keydown', onKeyDown); + await sendKeys('press', 'Escape'); + expect(key).to.equal('Escape'); + window.removeEventListener('keydown', onKeyDown); + }); + +}); diff --git a/test/browser/fixture.test.js b/test/browser/fixture.test.js index 6590c104..0312f331 100644 --- a/test/browser/fixture.test.js +++ b/test/browser/fixture.test.js @@ -1,9 +1,8 @@ -import { defineCE, expect, waitUntil } from '@open-wc/testing'; -import { html, LitElement } from 'lit'; +import { defineCE, expect, fixture, html, waitUntil } from '../../src/browser/index.js'; import { restore, stub } from 'sinon'; -import { fixture } from '../../src/browser/index.js'; -import { focusWithKeyboard } from '../../src/browser/focus.js'; +import { focusElem } from '../../src/browser/commands.js'; +import { LitElement } from 'lit'; import { sendMouse } from '@web/test-runner-commands'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; @@ -97,7 +96,7 @@ describe('fixture', () => { it('should reset focus', async() => { const elem = await fixture(html``); expect(document.activeElement).to.equal(document.body); - await focusWithKeyboard(elem); + await focusElem(elem); expect(document.activeElement).to.equal(elem); await fixture(html`
hello
`); expect(document.activeElement).to.equal(document.body);