From 9f36b9daf3f999710cada0b5e55bd286b351f207 Mon Sep 17 00:00:00 2001 From: filtered <176114999+webfiltered@users.noreply.github.com> Date: Tue, 4 Mar 2025 01:34:42 +1100 Subject: [PATCH] [Test] Add ComfyMouse fixture for Playwright tests (#2826) --- browser_tests/fixtures/ComfyMouse.ts | 97 ++++++++++++++++++++++++++++ browser_tests/fixtures/ComfyPage.ts | 10 ++- browser_tests/interaction.spec.ts | 28 ++++---- 3 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 browser_tests/fixtures/ComfyMouse.ts diff --git a/browser_tests/fixtures/ComfyMouse.ts b/browser_tests/fixtures/ComfyMouse.ts new file mode 100644 index 000000000..306f4352b --- /dev/null +++ b/browser_tests/fixtures/ComfyMouse.ts @@ -0,0 +1,97 @@ +import type { Mouse } from '@playwright/test' + +import type { ComfyPage } from './ComfyPage' +import type { Position } from './types' + +/** + * Used for drag and drop ops + * @see + * - {@link Mouse.down} + * - {@link Mouse.move} + * - {@link Mouse.up} + */ +export interface DragOptions { + button?: 'left' | 'right' | 'middle' + clickCount?: number + steps?: number +} + +/** + * Wraps mouse drag and drop to work with a canvas-based app. + * + * Requires the next frame animated before and after all steps, giving the + * canvas time to render the changes before screenshots are taken. + */ +export class ComfyMouse implements Omit { + static defaultSteps = 5 + static defaultOptions: DragOptions = { steps: ComfyMouse.defaultSteps } + + constructor(readonly comfyPage: ComfyPage) {} + + /** The normal Playwright {@link Mouse} property from {@link ComfyPage.page}. */ + get mouse() { + return this.comfyPage.page.mouse + } + + async nextFrame() { + await this.comfyPage.nextFrame() + } + + /** Drags from current location to a new location and hovers there (no pointerup event) */ + async drag(to: Position, options = ComfyMouse.defaultOptions) { + const { steps, ...downOptions } = options + + await this.mouse.down(downOptions) + await this.nextFrame() + + await this.move(to, { steps }) + await this.nextFrame() + } + + async drop(options = ComfyMouse.defaultOptions) { + await this.mouse.up(options) + await this.nextFrame() + } + + async dragAndDrop( + from: Position, + to: Position, + options = ComfyMouse.defaultOptions + ) { + const { steps } = options + + await this.nextFrame() + + await this.move(from, { steps }) + await this.drag(to, options) + await this.drop(options) + } + + /** @see {@link Mouse.move} */ + async move(to: Position, options = ComfyMouse.defaultOptions) { + await this.mouse.move(to.x, to.y, options) + await this.nextFrame() + } + + //#region Pass-through + async click(...args: Parameters) { + return await this.mouse.click(...args) + } + + async dblclick(...args: Parameters) { + return await this.mouse.dblclick(...args) + } + + async down(...args: Parameters) { + return await this.mouse.down(...args) + } + + async up(...args: Parameters) { + return await this.mouse.up(...args) + } + + async wheel(...args: Parameters) { + return await this.mouse.wheel(...args) + } + //#endregion Pass-through +} diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 6ee0d2139..52f03629f 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -11,6 +11,7 @@ import type { useWorkspaceStore } from '../../src/stores/workspaceStore' import { NodeBadgeMode } from '../../src/types/nodeSource' import { ComfyActionbar } from '../helpers/actionbar' import { ComfyTemplates } from '../helpers/templates' +import { ComfyMouse } from './ComfyMouse' import { ComfyNodeSearchBox } from './components/ComfyNodeSearchBox' import { SettingDialog } from './components/SettingDialog' import { @@ -910,7 +911,10 @@ export class ComfyPage { } } -export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({ +export const comfyPageFixture = base.extend<{ + comfyPage: ComfyPage + comfyMouse: ComfyMouse +}>({ comfyPage: async ({ page, request }, use, testInfo) => { const comfyPage = new ComfyPage(page, request) @@ -941,6 +945,10 @@ export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({ await comfyPage.setup() await use(comfyPage) + }, + comfyMouse: async ({ comfyPage }, use) => { + const comfyMouse = new ComfyMouse(comfyPage) + use(comfyMouse) } }) diff --git a/browser_tests/interaction.spec.ts b/browser_tests/interaction.spec.ts index 3a197ddc0..350ef3582 100644 --- a/browser_tests/interaction.spec.ts +++ b/browser_tests/interaction.spec.ts @@ -140,20 +140,14 @@ test.describe('Node Interaction', () => { }) test('Auto snap&highlight when dragging link over node', async ({ - comfyPage + comfyPage, + comfyMouse }) => { await comfyPage.setSetting('Comfy.Node.AutoSnapLinkToSlot', true) await comfyPage.setSetting('Comfy.Node.SnapHighlightsNode', true) - await comfyPage.page.mouse.move( - comfyPage.clipTextEncodeNode1InputSlot.x, - comfyPage.clipTextEncodeNode1InputSlot.y - ) - await comfyPage.page.mouse.down() - await comfyPage.page.mouse.move( - comfyPage.clipTextEncodeNode2InputSlot.x, - comfyPage.clipTextEncodeNode2InputSlot.y - ) + await comfyMouse.move(comfyPage.clipTextEncodeNode1InputSlot) + await comfyMouse.drag(comfyPage.clipTextEncodeNode2InputSlot) await expect(comfyPage.canvas).toHaveScreenshot('snapped-highlighted.png') }) }) @@ -506,24 +500,24 @@ test.describe('Canvas Interaction', () => { expect(await getCursorStyle()).toBe('default') }) - test('Can pan when dragging a link', async ({ comfyPage }) => { + test('Can pan when dragging a link', async ({ comfyPage, comfyMouse }) => { const posSlot1 = comfyPage.clipTextEncodeNode1InputSlot - await comfyPage.page.mouse.move(posSlot1.x, posSlot1.y) - await comfyPage.page.mouse.down() + await comfyMouse.move(posSlot1) const posEmpty = comfyPage.emptySpace - await comfyPage.page.mouse.move(posEmpty.x, posEmpty.y) + await comfyMouse.drag(posEmpty) await expect(comfyPage.canvas).toHaveScreenshot('dragging-link1.png') + await comfyPage.page.keyboard.down('Space') - await comfyPage.page.mouse.move(posEmpty.x + 100, posEmpty.y + 100) + await comfyMouse.mouse.move(posEmpty.x + 100, posEmpty.y + 100) // Canvas should be panned. await expect(comfyPage.canvas).toHaveScreenshot( 'panning-when-dragging-link.png' ) await comfyPage.page.keyboard.up('Space') - await comfyPage.page.mouse.move(posEmpty.x, posEmpty.y) + await comfyMouse.move(posEmpty) // Should be back to dragging link mode when space is released. await expect(comfyPage.canvas).toHaveScreenshot('dragging-link2.png') - await comfyPage.page.mouse.up() + await comfyMouse.drop() }) test('Can pan very far and back', async ({ comfyPage }) => {