From 98649322be61deac5481fc9ced829eb64ca8bac4 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Wed, 26 Aug 2026 18:27:37 -0400 Subject: [PATCH 1/4] GAUD-10597 - Add drag test command --- src/browser/commands.js | 16 ++++++++ src/browser/index.js | 2 +- test/browser/commands.test.js | 69 ++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/browser/commands.js b/src/browser/commands.js index 3d9883be..dd7af392 100644 --- a/src/browser/commands.js +++ b/src/browser/commands.js @@ -40,6 +40,22 @@ export async function dragDropElems(elem, toElem) { await sendMouse({ type: 'up' }); } +export async function dragElemBy(elem, offsetX = 0, offsetY = 0) { + const pixels = 10; // Mimic dragging by moving in 10px increments to the target position + const numSteps = Math.ceil(Math.max(Math.abs(offsetX), Math.abs(offsetY)) / pixels); + + const position = getElementPosition(elem); + await sendMouse({ type: 'move', position: [position.x, position.y] }); + + await sendMouse({ type: 'down' }); + for (let i = 1; i <= numSteps; i++) { + const dx = Math.sign(offsetX) * Math.min(Math.abs(offsetX), pixels * i); + const dy = Math.sign(offsetY) * Math.min(Math.abs(offsetY), pixels * i); + await sendMouse({ type: 'move', position: [position.x + dx, position.y + dy] }); + } + 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 cc27b0ac..2a709401 100644 --- a/src/browser/index.js +++ b/src/browser/index.js @@ -2,6 +2,6 @@ import './vdiff.js'; import './axe.js'; export { assert, aTimeout, defineCE, expect, html, nextFrame, oneDefaultPreventedEvent, oneEvent, waitUntil } from '@open-wc/testing'; -export { clickAt, clickElem, clickElemAt, dragDropElems, focusElem, hoverAt, hoverElem, hoverElemAt, sendKeys, sendKeysElem, setViewport } from './commands.js'; +export { clickAt, clickElem, clickElemAt, dragDropElems, dragElemBy, focusElem, hoverAt, hoverElem, hoverElemAt, sendKeys, sendKeysElem, setViewport } from './commands.js'; export { fixture, waitForElem } from './fixture.js'; export { runConstructor } from './constructor.js'; diff --git a/test/browser/commands.test.js b/test/browser/commands.test.js index 7162ce3a..02f4e457 100644 --- a/test/browser/commands.test.js +++ b/test/browser/commands.test.js @@ -1,9 +1,10 @@ -import { clickAt, clickElem, clickElemAt, dragDropElems, expect, fixture, focusElem, hoverAt, hoverElem, hoverElemAt, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js'; +import { clickAt, clickElem, clickElemAt, dragDropElems, dragElemBy, expect, fixture, focusElem, hoverAt, hoverElem, hoverElemAt, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js'; import { html } from 'lit'; import { spy } from 'sinon'; describe('commands', () => { const buttonTemplate = html``; + const dragTemplate = html`
`; const draggableTemplate = html`
@@ -19,6 +20,7 @@ describe('commands', () => { let elem, focusSource, hovered, key, keys; const clickPos = { x: 0, y: 0 }; const mousePos = { x: 0, y: 0 }; + const pointerEvents = []; function onClick(e) { clickPos.x = e.clientX; @@ -41,6 +43,14 @@ describe('commands', () => { mousePos.y = e.clientY; } + function onPointer(e) { + pointerEvents.push({ + type: e.type, + x: e.clientX, + y: e.clientY + }); + } + function onMouseOver() { hovered = true; } @@ -53,12 +63,22 @@ describe('commands', () => { window.addEventListener('click', onClick); window.addEventListener('keydown', onKeyDown); window.addEventListener('mousemove', onMouseMove); + window.addEventListener('pointerdown', onPointer); + window.addEventListener('pointermove', onPointer); + window.addEventListener('pointerup', onPointer); + }); + + beforeEach(() => { + pointerEvents.length = 0; }); after(() => { window.removeEventListener('click', onClick); window.removeEventListener('keydown', onKeyDown); window.removeEventListener('mousemove', onMouseMove); + window.removeEventListener('pointerdown', onPointer); + window.removeEventListener('pointermove', onPointer); + window.removeEventListener('pointerup', onPointer); }); describe('click/hover', () => { @@ -194,6 +214,53 @@ describe('commands', () => { }); + describe('drag', () => { + const getDragMoves = (events) => events.slice(1).filter(e => e.type === 'pointermove').map(e => ({ x: e.x, y: e.y })); + + beforeEach(async() => { + elem = await fixture(dragTemplate); + pointerEvents.length = 0; + }); + + it('should start dragging from the center of element and fire pointer events throughout the full drag flow', async() => { + await dragElemBy(elem, 20, 20); + expect(pointerEvents).to.deep.equal([ + { type: 'pointermove', x: 100, y: 100 }, // Move to element center + { type: 'pointerdown', x: 100, y: 100 }, // Start drag + { type: 'pointermove', x: 110, y: 110 }, // Drag 10px + { type: 'pointermove', x: 120, y: 120 }, // Drag 10px + { type: 'pointerup', x: 120, y: 120 }, // End drag + ]); + }); + + it('should move to the target offset in 10px increments to the max', async() => { + await dragElemBy(elem, 25, 0); + expect(getDragMoves(pointerEvents)).to.deep.equal([ + { x: 110, y: 100 }, + { x: 120, y: 100 }, + { x: 125, y: 100 }, + ]); + }); + + it('should clamp the shorter axis while the longer axis keeps stepping', async() => { + await dragElemBy(elem, 30, 15); + expect(getDragMoves(pointerEvents)).to.deep.equal([ + { x: 110, y: 110 }, + { x: 120, y: 115 }, + { x: 130, y: 115 }, + ]); + }); + + it('should drag in negative directions', async() => { + await dragElemBy(elem, -25, -25); + expect(getDragMoves(pointerEvents)).to.deep.equal([ + { x: 90, y: 90 }, + { x: 80, y: 80 }, + { x: 75, y: 75 }, + ]); + }); + }); + describe('drag & drop', () => { it('should drag & drop element', (done) => { From ce66d5b862fdadb6de805706153fff434be490cd Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:43:39 -0400 Subject: [PATCH 2/4] Alternative way to do the tests (#1070) --- test/browser/commands.test.js | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/test/browser/commands.test.js b/test/browser/commands.test.js index 02f4e457..abbdc6db 100644 --- a/test/browser/commands.test.js +++ b/test/browser/commands.test.js @@ -20,7 +20,6 @@ describe('commands', () => { let elem, focusSource, hovered, key, keys; const clickPos = { x: 0, y: 0 }; const mousePos = { x: 0, y: 0 }; - const pointerEvents = []; function onClick(e) { clickPos.x = e.clientX; @@ -43,14 +42,6 @@ describe('commands', () => { mousePos.y = e.clientY; } - function onPointer(e) { - pointerEvents.push({ - type: e.type, - x: e.clientX, - y: e.clientY - }); - } - function onMouseOver() { hovered = true; } @@ -63,22 +54,12 @@ describe('commands', () => { window.addEventListener('click', onClick); window.addEventListener('keydown', onKeyDown); window.addEventListener('mousemove', onMouseMove); - window.addEventListener('pointerdown', onPointer); - window.addEventListener('pointermove', onPointer); - window.addEventListener('pointerup', onPointer); - }); - - beforeEach(() => { - pointerEvents.length = 0; }); after(() => { window.removeEventListener('click', onClick); window.removeEventListener('keydown', onKeyDown); window.removeEventListener('mousemove', onMouseMove); - window.removeEventListener('pointerdown', onPointer); - window.removeEventListener('pointermove', onPointer); - window.removeEventListener('pointerup', onPointer); }); describe('click/hover', () => { @@ -215,16 +196,35 @@ describe('commands', () => { }); describe('drag', () => { - const getDragMoves = (events) => events.slice(1).filter(e => e.type === 'pointermove').map(e => ({ x: e.x, y: e.y })); + const allPointerEvents = [], dragMoveEvents = []; + let dragStarted = false; + function onPointer(e) { + allPointerEvents.push({ type: e.type, x: e.clientX, y: e.clientY }); + if (e.type === 'pointerdown') dragStarted = true; + else if (e.type === 'pointerup') dragStarted = false; + else if (e.type === 'pointermove' && dragStarted) dragMoveEvents.push({ x: e.clientX, y: e.clientY }); + } beforeEach(async() => { elem = await fixture(dragTemplate); - pointerEvents.length = 0; + + window.addEventListener('pointerdown', onPointer); + window.addEventListener('pointermove', onPointer); + window.addEventListener('pointerup', onPointer); + }); + + afterEach(() => { + allPointerEvents.length = 0; + dragMoveEvents.length = 0; + + window.removeEventListener('pointerdown', onPointer); + window.removeEventListener('pointermove', onPointer); + window.removeEventListener('pointerup', onPointer); }); it('should start dragging from the center of element and fire pointer events throughout the full drag flow', async() => { await dragElemBy(elem, 20, 20); - expect(pointerEvents).to.deep.equal([ + expect(allPointerEvents).to.deep.equal([ { type: 'pointermove', x: 100, y: 100 }, // Move to element center { type: 'pointerdown', x: 100, y: 100 }, // Start drag { type: 'pointermove', x: 110, y: 110 }, // Drag 10px @@ -235,7 +235,7 @@ describe('commands', () => { it('should move to the target offset in 10px increments to the max', async() => { await dragElemBy(elem, 25, 0); - expect(getDragMoves(pointerEvents)).to.deep.equal([ + expect(dragMoveEvents).to.deep.equal([ { x: 110, y: 100 }, { x: 120, y: 100 }, { x: 125, y: 100 }, @@ -244,7 +244,7 @@ describe('commands', () => { it('should clamp the shorter axis while the longer axis keeps stepping', async() => { await dragElemBy(elem, 30, 15); - expect(getDragMoves(pointerEvents)).to.deep.equal([ + expect(dragMoveEvents).to.deep.equal([ { x: 110, y: 110 }, { x: 120, y: 115 }, { x: 130, y: 115 }, @@ -253,7 +253,7 @@ describe('commands', () => { it('should drag in negative directions', async() => { await dragElemBy(elem, -25, -25); - expect(getDragMoves(pointerEvents)).to.deep.equal([ + expect(dragMoveEvents).to.deep.equal([ { x: 90, y: 90 }, { x: 80, y: 80 }, { x: 75, y: 75 }, From 7b0470c2e4c8171922bc0dde724993d24f2170c3 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Thu, 27 Aug 2026 12:06:20 -0400 Subject: [PATCH 3/4] Rename variable, adjust comment --- src/browser/commands.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/browser/commands.js b/src/browser/commands.js index dd7af392..37bb3d89 100644 --- a/src/browser/commands.js +++ b/src/browser/commands.js @@ -41,16 +41,16 @@ export async function dragDropElems(elem, toElem) { } export async function dragElemBy(elem, offsetX = 0, offsetY = 0) { - const pixels = 10; // Mimic dragging by moving in 10px increments to the target position - const numSteps = Math.ceil(Math.max(Math.abs(offsetX), Math.abs(offsetY)) / pixels); + const dragIncrementSize = 10; // To mimic real user dragging + const numSteps = Math.ceil(Math.max(Math.abs(offsetX), Math.abs(offsetY)) / dragIncrementSize); const position = getElementPosition(elem); await sendMouse({ type: 'move', position: [position.x, position.y] }); await sendMouse({ type: 'down' }); for (let i = 1; i <= numSteps; i++) { - const dx = Math.sign(offsetX) * Math.min(Math.abs(offsetX), pixels * i); - const dy = Math.sign(offsetY) * Math.min(Math.abs(offsetY), pixels * i); + const dx = Math.sign(offsetX) * Math.min(Math.abs(offsetX), dragIncrementSize * i); + const dy = Math.sign(offsetY) * Math.min(Math.abs(offsetY), dragIncrementSize * i); await sendMouse({ type: 'move', position: [position.x + dx, position.y + dy] }); } await sendMouse({ type: 'up' }); From 17539b633eaf2819d24bf8e4559f1d0f31491bea Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Thu, 27 Aug 2026 12:26:16 -0400 Subject: [PATCH 4/4] Better test cleanup, add a few missing tests --- test/browser/commands.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/browser/commands.test.js b/test/browser/commands.test.js index abbdc6db..3cdbcd4f 100644 --- a/test/browser/commands.test.js +++ b/test/browser/commands.test.js @@ -214,12 +214,13 @@ describe('commands', () => { }); afterEach(() => { - allPointerEvents.length = 0; - dragMoveEvents.length = 0; - window.removeEventListener('pointerdown', onPointer); window.removeEventListener('pointermove', onPointer); window.removeEventListener('pointerup', onPointer); + + allPointerEvents.length = 0; + dragMoveEvents.length = 0; + dragStarted = false; }); it('should start dragging from the center of element and fire pointer events throughout the full drag flow', async() => { @@ -293,6 +294,8 @@ describe('commands', () => { { command: 'clickElem', action: (elem) => clickElem(elem) }, { command: 'clickAt', action: () => clickAt(5, 10) }, { command: 'clickElemAt', action: (elem) => clickElemAt(elem, 10, 10) }, + { command: 'dragDropElems', action: (elem) => dragDropElems(elem, elem) }, + { command: 'dragElemBy', action: (elem) => dragElemBy(elem, 10, 10) }, { command: 'hoverElem', action: (elem) => hoverElem(elem) }, { command: 'hoverAt', action: () => hoverAt(5, 10) }, { command: 'hoverElemAt', action: (elem) => hoverElemAt(elem, 10, 10) },