From 9b4aa95bf86a6cece1d8376ed0397879230aff50 Mon Sep 17 00:00:00 2001 From: Dave Lockhart Date: Mon, 19 Aug 2024 14:28:26 -0400 Subject: [PATCH] feat: add dragDropElems (GAUD-6868) (#468) --- README.md | 27 ++++++ src/browser/commands.js | 9 ++ src/browser/index.js | 2 +- test/browser/commands.test.js | 172 ++++++++++++++++++++++------------ 4 files changed, 147 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 7e689a88..47774b9e 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,33 @@ it('should click at coordinate', async() => { }); ``` +Elements configured using the [Drag & Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) can be interacted with using `dragDropElems(sourceElem, destElem)`: + +```javascript +import { dragDropElems } from '@brightspace-ui/testing'; + +it('should drag & drop', async() => { + const rootElem = await fixture(html` +
+
+
+
+ `); + // NOTE: destination must have "dragover" and "drop" + // event listeners added for the drag & drop API to function + await dragDropElems( + rootElem.querySelector('#source'), + rootElem.querySelector('#target') + ); + // do assertions +}); + +it('should click at coordinate', async() => { + await clickAt(100, 200); + // do assertions +}); +``` + ### Using the Keyboard To place focus on an element using the keyboard, use `focusElem(elem)`. Doing so will trigger its `:focus-visible` CSS pseudo-class. diff --git a/src/browser/commands.js b/src/browser/commands.js index c4ff67af..ab9b5a56 100644 --- a/src/browser/commands.js +++ b/src/browser/commands.js @@ -24,6 +24,15 @@ export async function clickElem(elem) { return clickAt(position.x, position.y); } +export async function dragDropElems(elem, toElem) { + const fromPosition = getElementPosition(elem); + const toPosition = getElementPosition(toElem); + await sendMouse({ type: 'move', position: [fromPosition.x, fromPosition.y] }); + await sendMouse({ type: 'down' }); + await sendMouse({ type: 'move', position: [toPosition.x, toPosition.y] }); + await sendMouse({ type: 'up' }); +} + export async function focusElem(elem) { await cmdSendKeys({ press: 'Shift' }); // Tab moves focus, Escape causes dismissible things to close elem.focus({ focusVisible: true }); diff --git a/src/browser/index.js b/src/browser/index.js index 52898e33..317882fb 100644 --- a/src/browser/index.js +++ b/src/browser/index.js @@ -1,6 +1,6 @@ import './vdiff.js'; export { assert, aTimeout, defineCE, expect, html, nextFrame, oneDefaultPreventedEvent, oneEvent, waitUntil } from '@open-wc/testing'; -export { clickAt, clickElem, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from './commands.js'; +export { clickAt, clickElem, dragDropElems, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from './commands.js'; export { fixture } from './fixture.js'; export { runConstructor } from './constructor.js'; diff --git a/test/browser/commands.test.js b/test/browser/commands.test.js index 857f7209..fce6bcf9 100644 --- a/test/browser/commands.test.js +++ b/test/browser/commands.test.js @@ -1,87 +1,131 @@ -import { clickAt, clickElem, expect, fixture, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js'; +import { clickAt, clickElem, dragDropElems, expect, fixture, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js'; import { html } from 'lit'; import { spy } from 'sinon'; describe('commands', () => { - let elem; - const input = html``; - beforeEach(async() => { - elem = await fixture(input); - }); + describe('click/hover', () => { - it('should click on element', async() => { - const clickSpy = spy(); - elem.addEventListener('click', clickSpy); - await clickElem(elem); - expect(clickSpy).to.be.calledOnce; - }); + let elem; + beforeEach(async() => { + elem = await fixture(html``); + }); - 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 click on element', async() => { + const clickSpy = spy(); + elem.addEventListener('click', clickSpy); + await clickElem(elem); + expect(clickSpy).to.be.calledOnce; + }); - it('should focus on element', async() => { - let focussed = false; - elem.addEventListener('focus', () => focussed = true); - await focusElem(elem); - expect(focussed).to.be.true; - }); + 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 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 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 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(elem, 'type', 'Hello'); - expect(elem.value).to.equal('Hello'); + describe('keyboard/focus', async() => { + + let elem; + beforeEach(async() => { + elem = await fixture(html``); + }); + + it('should focus on element', async() => { + let focussed = false; + elem.addEventListener('focus', () => focussed = true); + await focusElem(elem); + expect(focussed).to.be.true; + }); + + it('should send keys to element', async() => { + await sendKeysElem(elem, 'type', 'Hello'); + 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); + }); + }); - 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); + describe('drag & drop', () => { + + it('should drag & drop element', (done) => { + fixture(html`
+
+
+
`).then(rootElem => { + + let dragSource; + const sourceElem = rootElem.querySelector('#source'); + sourceElem.addEventListener('dragstart', e => dragSource = e.target); + + const destElem = rootElem.querySelector('#dest'); + destElem.addEventListener('dragover', e => e.preventDefault()); + destElem.addEventListener('drop', (e) => { + e.preventDefault(); + expect(dragSource).to.equal(sourceElem); + done(); + }); + + dragDropElems(sourceElem, destElem); + + }); + }); + }); describe('mouseReset', () => { + const mousePos = { x: 0, y: 0 }; function onMouseMove(e) { mousePos.x = e.clientX; mousePos.y = e.clientY; } - beforeEach(() => { + const buttonTemplate = html``; + + let elem; + beforeEach(async() => { + elem = await fixture(buttonTemplate); window.addEventListener('mousemove', onMouseMove); }); @@ -99,7 +143,7 @@ describe('commands', () => { await action(elem); expect(mousePos.x).to.not.equal(0); expect(mousePos.y).to.not.equal(0); - await fixture(input); + await fixture(buttonTemplate); expect(mousePos.x).to.equal(0); expect(mousePos.y).to.equal(0); }); @@ -108,6 +152,10 @@ describe('commands', () => { describe('viewport', () => { + beforeEach(async() => { + await fixture(html`
`); + }); + it('should set width and height', async() => { await setViewport({ height: 200, width: 300 }); expect(window.innerHeight).to.equal(200);