From 4e00e8428ff59e49b6ad916aed74cfe8918fb5aa Mon Sep 17 00:00:00 2001 From: Alexander Brown <448862+DrJKL@users.noreply.github.com> Date: Sat, 31 Jan 2026 15:38:03 -0800 Subject: [PATCH] refactor: wire helpers into ComfyPage and update test usages Phase 2 of ComfyPage refactor: - Add ToastHelper, DragDropHelper, CommandHelper instances to ComfyPage - Remove migrated methods from ComfyPage (command, toast, dragDrop, workflow, canvasOps, nodeOps methods) - Update all test files to use new helper paths - Keep visibleToasts as passthrough getter for backward compatibility Amp-Thread-ID: https://ampcode.com/threads/T-019c1666-ed27-773c-976a-07cc805d7a6c Co-authored-by: Amp --- browser_tests/fixtures/ComfyPage.ts | 386 +----------------- .../fixtures/components/SettingDialog.ts | 2 +- .../fixtures/helpers/NodeOperationsHelper.ts | 2 +- .../fixtures/helpers/WorkflowHelper.ts | 2 +- .../fixtures/utils/litegraphUtils.ts | 2 +- browser_tests/tests/changeTracker.spec.ts | 44 +- browser_tests/tests/colorPalette.spec.ts | 2 +- browser_tests/tests/commands.spec.ts | 20 +- browser_tests/tests/domWidget.spec.ts | 2 +- browser_tests/tests/execution.spec.ts | 6 +- browser_tests/tests/extensionAPI.spec.ts | 4 +- browser_tests/tests/graph.spec.ts | 2 +- browser_tests/tests/groupNode.spec.ts | 10 +- browser_tests/tests/interaction.spec.ts | 22 +- browser_tests/tests/keybindings.spec.ts | 6 +- browser_tests/tests/litegraphEvent.spec.ts | 2 +- .../tests/loadWorkflowInMedia.spec.ts | 4 +- browser_tests/tests/menu.spec.ts | 2 +- browser_tests/tests/mobileBaseline.spec.ts | 2 +- browser_tests/tests/nodeSearchBox.spec.ts | 16 +- browser_tests/tests/rightClickMenu.spec.ts | 4 +- browser_tests/tests/sidebar/workflows.spec.ts | 26 +- browser_tests/tests/templates.spec.ts | 12 +- .../tests/vueNodes/groups/groups.spec.ts | 16 +- .../links/linkInteraction.spec.ts | 6 +- browser_tests/tests/widget.spec.ts | 10 +- 26 files changed, 130 insertions(+), 482 deletions(-) diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 24d61bfc7..166023113 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -1,11 +1,8 @@ import type { APIRequestContext, Locator, Page } from '@playwright/test' import { test as base, expect } from '@playwright/test' import dotenv from 'dotenv' -import { readFileSync } from 'fs' -import type { KeyCombo } from '../../src/platform/keybindings' import { TestIds } from './selectors' -import type { useWorkspaceStore } from '../../src/stores/workspaceStore' import { NodeBadgeMode } from '../../src/types/nodeSource' import { ComfyActionbar } from '../helpers/actionbar' import { ComfyTemplates } from '../helpers/templates' @@ -19,22 +16,21 @@ import { WorkflowsSidebarTab } from './components/SidebarTab' import { Topbar } from './components/Topbar' -import { DefaultGraphPositions } from './constants/defaultGraphPositions' import { CanvasHelper } from './helpers/CanvasHelper' import { ClipboardHelper } from './helpers/ClipboardHelper' +import { CommandHelper } from './helpers/CommandHelper' import { DebugHelper } from './helpers/DebugHelper' +import { DragDropHelper } from './helpers/DragDropHelper' import { KeyboardHelper } from './helpers/KeyboardHelper' import { NodeOperationsHelper } from './helpers/NodeOperationsHelper' import { SettingsHelper } from './helpers/SettingsHelper' import { SubgraphHelper } from './helpers/SubgraphHelper' +import { ToastHelper } from './helpers/ToastHelper' import { WorkflowHelper } from './helpers/WorkflowHelper' -import type { Position } from './types' import type { NodeReference } from './utils/litegraphUtils' dotenv.config() -type WorkspaceStore = ReturnType - class ComfyPropertiesPanel { readonly root: Locator readonly panelTitle: Locator @@ -161,9 +157,6 @@ export class ComfyPage { // Inputs public readonly workflowUploadInput: Locator - // Toasts - public readonly visibleToasts: Locator - // Components public readonly searchBox: ComfyNodeSearchBox public readonly menu: ComfyMenu @@ -181,6 +174,9 @@ export class ComfyPage { public readonly clipboard: ClipboardHelper public readonly workflow: WorkflowHelper public readonly contextMenu: ContextMenu + public readonly toast: ToastHelper + public readonly dragDrop: DragDropHelper + public readonly command: CommandHelper /** Worker index to test user ID */ public readonly userIds: string[] = [] @@ -207,7 +203,6 @@ export class ComfyPage { .getByTestId('queue-button') .getByRole('button', { name: 'Run' }) this.workflowUploadInput = page.locator('#comfy-file-input') - this.visibleToasts = page.locator('.p-toast-message:visible') this.searchBox = new ComfyNodeSearchBox(page) this.menu = new ComfyMenu(page) @@ -225,6 +220,13 @@ export class ComfyPage { this.clipboard = new ClipboardHelper(this.keyboard, this.canvas) this.workflow = new WorkflowHelper(this) this.contextMenu = new ContextMenu(page) + this.toast = new ToastHelper(page) + this.dragDrop = new DragDropHelper(page, this.assetPath.bind(this)) + this.command = new CommandHelper(page) + } + + get visibleToasts() { + return this.toast.visibleToasts } async setupUser(username: string) { @@ -317,64 +319,6 @@ export class ComfyPage { return `./browser_tests/assets/${fileName}` } - async executeCommand(commandId: string) { - await this.page.evaluate((id: string) => { - return window['app'].extensionManager.command.execute(id) - }, commandId) - } - - async registerCommand( - commandId: string, - command: (() => void) | (() => Promise) - ) { - await this.page.evaluate( - ({ commandId, commandStr }) => { - const app = window['app'] - const randomSuffix = Math.random().toString(36).substring(2, 8) - const extensionName = `TestExtension_${randomSuffix}` - - app.registerExtension({ - name: extensionName, - commands: [ - { - id: commandId, - function: eval(commandStr) - } - ] - }) - }, - { commandId, commandStr: command.toString() } - ) - } - - async registerKeybinding(keyCombo: KeyCombo, command: () => void) { - await this.page.evaluate( - ({ keyCombo, commandStr }) => { - const app = window['app'] - const randomSuffix = Math.random().toString(36).substring(2, 8) - const extensionName = `TestExtension_${randomSuffix}` - const commandId = `TestCommand_${randomSuffix}` - - app.registerExtension({ - name: extensionName, - keybindings: [ - { - combo: keyCombo, - commandId: commandId - } - ], - commands: [ - { - id: commandId, - function: eval(commandStr) - } - ] - }) - }, - { keyCombo, commandStr: command.toString() } - ) - } - async goto() { await this.page.goto(this.url) } @@ -415,236 +359,6 @@ export class ComfyPage { }) } - async getToastErrorCount() { - return await this.page - .locator('.p-toast-message.p-toast-message-error') - .count() - } - - async getVisibleToastCount() { - return await this.visibleToasts.count() - } - - async closeToasts(requireCount = 0) { - if (requireCount) { - await this.visibleToasts - .nth(requireCount - 1) - .waitFor({ state: 'visible' }) - } - - // Clear all toasts - const toastCloseButtons = await this.page - .locator('.p-toast-close-button') - .all() - for (const button of toastCloseButtons) { - await button.click() - } - - // Wait for toasts to disappear - await this.visibleToasts - .first() - .waitFor({ state: 'hidden', timeout: 1000 }) - .catch(() => {}) - } - - async dragAndDropExternalResource( - options: { - fileName?: string - url?: string - dropPosition?: Position - waitForUpload?: boolean - } = {} - ) { - const { - dropPosition = { x: 100, y: 100 }, - fileName, - url, - waitForUpload = false - } = options - - if (!fileName && !url) - throw new Error('Must provide either fileName or url') - - const evaluateParams: { - dropPosition: Position - fileName?: string - fileType?: string - buffer?: Uint8Array | number[] - url?: string - } = { dropPosition } - - // Dropping a file from the filesystem - if (fileName) { - const filePath = this.assetPath(fileName) - const buffer = readFileSync(filePath) - - const getFileType = (fileName: string) => { - if (fileName.endsWith('.png')) return 'image/png' - if (fileName.endsWith('.svg')) return 'image/svg+xml' - if (fileName.endsWith('.webp')) return 'image/webp' - if (fileName.endsWith('.webm')) return 'video/webm' - if (fileName.endsWith('.json')) return 'application/json' - if (fileName.endsWith('.glb')) return 'model/gltf-binary' - if (fileName.endsWith('.avif')) return 'image/avif' - return 'application/octet-stream' - } - - evaluateParams.fileName = fileName - evaluateParams.fileType = getFileType(fileName) - evaluateParams.buffer = [...new Uint8Array(buffer)] - } - - // Dropping a URL (e.g., dropping image across browser tabs in Firefox) - if (url) evaluateParams.url = url - - // Set up response waiter for file uploads before triggering the drop - const uploadResponsePromise = waitForUpload - ? this.page.waitForResponse( - (resp) => resp.url().includes('/upload/') && resp.status() === 200, - { timeout: 10000 } - ) - : null - - // Execute the drag and drop in the browser - await this.page.evaluate(async (params) => { - const dataTransfer = new DataTransfer() - - // Add file if provided - if (params.buffer && params.fileName && params.fileType) { - const file = new File( - [new Uint8Array(params.buffer)], - params.fileName, - { - type: params.fileType - } - ) - dataTransfer.items.add(file) - } - - // Add URL data if provided - if (params.url) { - dataTransfer.setData('text/uri-list', params.url) - dataTransfer.setData('text/x-moz-url', params.url) - } - - const targetElement = document.elementFromPoint( - params.dropPosition.x, - params.dropPosition.y - ) - - if (!targetElement) { - console.error('No element found at drop position:', params.dropPosition) - return { success: false, error: 'No element at position' } - } - - const eventOptions = { - bubbles: true, - cancelable: true, - dataTransfer, - clientX: params.dropPosition.x, - clientY: params.dropPosition.y - } - - const dragOverEvent = new DragEvent('dragover', eventOptions) - const dropEvent = new DragEvent('drop', eventOptions) - - Object.defineProperty(dropEvent, 'preventDefault', { - value: () => {}, - writable: false - }) - - Object.defineProperty(dropEvent, 'stopPropagation', { - value: () => {}, - writable: false - }) - - targetElement.dispatchEvent(dragOverEvent) - targetElement.dispatchEvent(dropEvent) - - return { - success: true, - targetInfo: { - tagName: targetElement.tagName, - id: targetElement.id, - classList: Array.from(targetElement.classList) - } - } - }, evaluateParams) - - // Wait for file upload to complete - if (uploadResponsePromise) { - await uploadResponsePromise - } - - await this.nextFrame() - } - - async dragAndDropFile( - fileName: string, - options: { dropPosition?: Position; waitForUpload?: boolean } = {} - ) { - return this.dragAndDropExternalResource({ fileName, ...options }) - } - - async dragAndDropURL(url: string, options: { dropPosition?: Position } = {}) { - return this.dragAndDropExternalResource({ url, ...options }) - } - - async dragNode2() { - await this.canvasOps.dragAndDrop(DefaultGraphPositions.textEncodeNode2, { - x: DefaultGraphPositions.textEncodeNode2.x, - y: 300 - }) - await this.nextFrame() - } - - get promptDialogInput() { - return this.page.locator('.p-dialog-content input[type="text"]') - } - - async fillPromptDialog(value: string) { - await this.promptDialogInput.fill(value) - await this.page.keyboard.press('Enter') - await this.promptDialogInput.waitFor({ state: 'hidden' }) - await this.nextFrame() - } - - async disconnectEdge() { - await this.canvasOps.dragAndDrop( - DefaultGraphPositions.clipTextEncodeNode1InputSlot, - DefaultGraphPositions.emptySpace - ) - } - - async connectEdge( - options: { - reverse?: boolean - } = {} - ) { - const { reverse = false } = options - const start = reverse - ? DefaultGraphPositions.clipTextEncodeNode1InputSlot - : DefaultGraphPositions.loadCheckpointNodeClipOutputSlot - const end = reverse - ? DefaultGraphPositions.loadCheckpointNodeClipOutputSlot - : DefaultGraphPositions.clipTextEncodeNode1InputSlot - - await this.canvasOps.dragAndDrop(start, end) - } - - async adjustWidgetValue() { - // Adjust Empty Latent Image's width input. - const page = this.page - await page.locator('#graph-canvas').click({ - position: DefaultGraphPositions.emptyLatentWidgetClick - }) - const dialogInput = page.locator('.graphdialog input[type="text"]') - await dialogInput.click() - await dialogInput.fill('128') - await dialogInput.press('Enter') - await this.nextFrame() - } - async closeMenu() { await this.page.click('button.comfy-close-menu-btn') await this.nextFrame() @@ -668,86 +382,12 @@ export class ComfyPage { return await this.page.locator('.dom-widget').count() } - async getUndoQueueSize() { - return this.page.evaluate(() => { - const workflow = (window['app'].extensionManager as WorkspaceStore) - .workflow.activeWorkflow - return workflow?.changeTracker.undoQueue.length - }) - } - async getRedoQueueSize() { - return this.page.evaluate(() => { - const workflow = (window['app'].extensionManager as WorkspaceStore) - .workflow.activeWorkflow - return workflow?.changeTracker.redoQueue.length - }) - } - async isCurrentWorkflowModified() { - return this.page.evaluate(() => { - return (window['app'].extensionManager as WorkspaceStore).workflow - .activeWorkflow?.isModified - }) - } - async getExportedWorkflow({ api = false }: { api?: boolean } = {}) { - return this.page.evaluate(async (api) => { - return (await window['app'].graphToPrompt())[api ? 'output' : 'workflow'] - }, api) - } async setFocusMode(focusMode: boolean) { await this.page.evaluate((focusMode) => { window['app'].extensionManager.focusMode = focusMode }, focusMode) await this.nextFrame() } - - /** - * Get the position of a group by title. - * @param title The title of the group to find - * @returns The group's canvas position - * @throws Error if group not found - */ - async getGroupPosition(title: string): Promise { - const pos = await this.page.evaluate((title) => { - const groups = window['app'].graph.groups - const group = groups.find((g: { title: string }) => g.title === title) - if (!group) return null - return { x: group.pos[0], y: group.pos[1] } - }, title) - if (!pos) throw new Error(`Group "${title}" not found`) - return pos - } - - /** - * Drag a group by its title. - * @param options.name The title of the group to drag - * @param options.deltaX Horizontal drag distance in screen pixels - * @param options.deltaY Vertical drag distance in screen pixels - */ - async dragGroup(options: { - name: string - deltaX: number - deltaY: number - }): Promise { - const { name, deltaX, deltaY } = options - const screenPos = await this.page.evaluate((title) => { - const app = window['app'] - const groups = app.graph.groups - const group = groups.find((g: { title: string }) => g.title === title) - if (!group) return null - // Position in the title area of the group - const clientPos = app.canvasPosToClientPos([ - group.pos[0] + 50, - group.pos[1] + 15 - ]) - return { x: clientPos[0], y: clientPos[1] } - }, name) - if (!screenPos) throw new Error(`Group "${name}" not found`) - - await this.canvasOps.dragAndDrop(screenPos, { - x: screenPos.x + deltaX, - y: screenPos.y + deltaY - }) - } } export const testComfySnapToGridGridSize = 50 diff --git a/browser_tests/fixtures/components/SettingDialog.ts b/browser_tests/fixtures/components/SettingDialog.ts index 61c83e91e..651e8a95a 100644 --- a/browser_tests/fixtures/components/SettingDialog.ts +++ b/browser_tests/fixtures/components/SettingDialog.ts @@ -13,7 +13,7 @@ export class SettingDialog extends BaseDialog { } async open() { - await this.comfyPage.executeCommand('Comfy.ShowSettingsDialog') + await this.comfyPage.command.executeCommand('Comfy.ShowSettingsDialog') await this.waitForVisible() } diff --git a/browser_tests/fixtures/helpers/NodeOperationsHelper.ts b/browser_tests/fixtures/helpers/NodeOperationsHelper.ts index d7984ddb6..de0c6ac66 100644 --- a/browser_tests/fixtures/helpers/NodeOperationsHelper.ts +++ b/browser_tests/fixtures/helpers/NodeOperationsHelper.ts @@ -137,7 +137,7 @@ export class NodeOperationsHelper { await this.comfyPage.canvas.press('Control+a') const node = await this.getFirstNodeRef() await node!.clickContextMenuOption('Convert to Group Node') - await this.comfyPage.fillPromptDialog(groupNodeName) + await this.fillPromptDialog(groupNodeName) await this.comfyPage.nextFrame() } diff --git a/browser_tests/fixtures/helpers/WorkflowHelper.ts b/browser_tests/fixtures/helpers/WorkflowHelper.ts index 796447753..065e231bb 100644 --- a/browser_tests/fixtures/helpers/WorkflowHelper.ts +++ b/browser_tests/fixtures/helpers/WorkflowHelper.ts @@ -80,7 +80,7 @@ export class WorkflowHelper { await this.comfyPage.confirmDialog.delete.click() // Clear toast & close tab - await this.comfyPage.closeToasts(1) + await this.comfyPage.toast.closeToasts(1) await workflowsTab.close() } diff --git a/browser_tests/fixtures/utils/litegraphUtils.ts b/browser_tests/fixtures/utils/litegraphUtils.ts index 42c547629..35f7818d0 100644 --- a/browser_tests/fixtures/utils/litegraphUtils.ts +++ b/browser_tests/fixtures/utils/litegraphUtils.ts @@ -421,7 +421,7 @@ export class NodeReference { } async convertToGroupNode(groupNodeName: string = 'GroupNode') { await this.clickContextMenuOption('Convert to Group Node') - await this.comfyPage.fillPromptDialog(groupNodeName) + await this.comfyPage.nodeOps.fillPromptDialog(groupNodeName) await this.comfyPage.nextFrame() const nodes = await this.comfyPage.nodeOps.getNodeRefsByType( `workflow>${groupNodeName}` diff --git a/browser_tests/tests/changeTracker.spec.ts b/browser_tests/tests/changeTracker.spec.ts index 40cedc558..73430031b 100644 --- a/browser_tests/tests/changeTracker.spec.ts +++ b/browser_tests/tests/changeTracker.spec.ts @@ -28,41 +28,41 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => { }) test('Can undo multiple operations', async ({ comfyPage }) => { - expect(await comfyPage.getUndoQueueSize()).toBe(0) - expect(await comfyPage.getRedoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0) // Save, confirm no errors & workflow modified flag removed await comfyPage.menu.topbar.saveWorkflow('undo-redo-test') - expect(await comfyPage.getToastErrorCount()).toBe(0) - expect(await comfyPage.isCurrentWorkflowModified()).toBe(false) - expect(await comfyPage.getUndoQueueSize()).toBe(0) - expect(await comfyPage.getRedoQueueSize()).toBe(0) + expect(await comfyPage.toast.getToastErrorCount()).toBe(0) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0) const node = (await comfyPage.nodeOps.getFirstNodeRef())! await node.click('title') await node.click('collapse') await expect(node).toBeCollapsed() - expect(await comfyPage.isCurrentWorkflowModified()).toBe(true) - expect(await comfyPage.getUndoQueueSize()).toBe(1) - expect(await comfyPage.getRedoQueueSize()).toBe(0) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(1) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0) await comfyPage.keyboard.bypass() await expect(node).toBeBypassed() - expect(await comfyPage.isCurrentWorkflowModified()).toBe(true) - expect(await comfyPage.getUndoQueueSize()).toBe(2) - expect(await comfyPage.getRedoQueueSize()).toBe(0) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(2) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(0) await comfyPage.keyboard.undo() await expect(node).not.toBeBypassed() - expect(await comfyPage.isCurrentWorkflowModified()).toBe(true) - expect(await comfyPage.getUndoQueueSize()).toBe(1) - expect(await comfyPage.getRedoQueueSize()).toBe(1) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(true) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(1) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(1) await comfyPage.keyboard.undo() await expect(node).not.toBeCollapsed() - expect(await comfyPage.isCurrentWorkflowModified()).toBe(false) - expect(await comfyPage.getUndoQueueSize()).toBe(0) - expect(await comfyPage.getRedoQueueSize()).toBe(2) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getRedoQueueSize()).toBe(2) }) }) @@ -157,7 +157,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => { }) test('Can detect changes in workflow.extra', async ({ comfyPage }) => { - expect(await comfyPage.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) await comfyPage.page.evaluate(() => { window['app'].graph.extra.foo = 'bar' }) @@ -165,12 +165,12 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => { await comfyPage.canvasOps.clickEmptySpace( DefaultGraphPositions.emptySpaceClick ) - expect(await comfyPage.getUndoQueueSize()).toBe(1) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(1) }) test('Ignores changes in workflow.ds', async ({ comfyPage }) => { - expect(await comfyPage.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) await comfyPage.canvasOps.pan({ x: 10, y: 10 }) - expect(await comfyPage.getUndoQueueSize()).toBe(0) + expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) }) }) diff --git a/browser_tests/tests/colorPalette.spec.ts b/browser_tests/tests/colorPalette.spec.ts index 66dcf981e..672ef5dee 100644 --- a/browser_tests/tests/colorPalette.spec.ts +++ b/browser_tests/tests/colorPalette.spec.ts @@ -181,7 +181,7 @@ test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => { await comfyPage.page.evaluate((p) => { window['app'].extensionManager.colorPalette.addCustomColorPalette(p) }, customColorPalettes.obsidian_dark) - expect(await comfyPage.getToastErrorCount()).toBe(0) + expect(await comfyPage.toast.getToastErrorCount()).toBe(0) await comfyPage.settings.setSetting('Comfy.ColorPalette', 'obsidian_dark') await comfyPage.nextFrame() diff --git a/browser_tests/tests/commands.spec.ts b/browser_tests/tests/commands.spec.ts index 66776387a..74dda361e 100644 --- a/browser_tests/tests/commands.spec.ts +++ b/browser_tests/tests/commands.spec.ts @@ -8,16 +8,16 @@ test.beforeEach(async ({ comfyPage }) => { test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should execute command', async ({ comfyPage }) => { - await comfyPage.registerCommand('TestCommand', () => { + await comfyPage.command.registerCommand('TestCommand', () => { window['foo'] = true }) - await comfyPage.executeCommand('TestCommand') + await comfyPage.command.executeCommand('TestCommand') expect(await comfyPage.page.evaluate(() => window['foo'])).toBe(true) }) test('Should execute async command', async ({ comfyPage }) => { - await comfyPage.registerCommand('TestCommand', async () => { + await comfyPage.command.registerCommand('TestCommand', async () => { await new Promise((resolve) => setTimeout(() => { window['foo'] = true @@ -26,21 +26,21 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { ) }) - await comfyPage.executeCommand('TestCommand') + await comfyPage.command.executeCommand('TestCommand') expect(await comfyPage.page.evaluate(() => window['foo'])).toBe(true) }) test('Should handle command errors', async ({ comfyPage }) => { - await comfyPage.registerCommand('TestCommand', () => { + await comfyPage.command.registerCommand('TestCommand', () => { throw new Error('Test error') }) - await comfyPage.executeCommand('TestCommand') - expect(await comfyPage.getToastErrorCount()).toBe(1) + await comfyPage.command.executeCommand('TestCommand') + expect(await comfyPage.toast.getToastErrorCount()).toBe(1) }) test('Should handle async command errors', async ({ comfyPage }) => { - await comfyPage.registerCommand('TestCommand', async () => { + await comfyPage.command.registerCommand('TestCommand', async () => { await new Promise((resolve, reject) => setTimeout(() => { reject(new Error('Test error')) @@ -48,7 +48,7 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { ) }) - await comfyPage.executeCommand('TestCommand') - expect(await comfyPage.getToastErrorCount()).toBe(1) + await comfyPage.command.executeCommand('TestCommand') + expect(await comfyPage.toast.getToastErrorCount()).toBe(1) }) }) diff --git a/browser_tests/tests/domWidget.spec.ts b/browser_tests/tests/domWidget.spec.ts index c47823fa0..d8e2dab9b 100644 --- a/browser_tests/tests/domWidget.spec.ts +++ b/browser_tests/tests/domWidget.spec.ts @@ -34,7 +34,7 @@ test.describe('DOM Widget', { tag: '@widget' }, () => { { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Top') - await comfyPage.executeCommand('Workspace.ToggleFocusMode') + await comfyPage.command.executeCommand('Workspace.ToggleFocusMode') await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot('focus-mode-on.png') } diff --git a/browser_tests/tests/execution.spec.ts b/browser_tests/tests/execution.spec.ts index b5c8ee07f..4a1d2a5f9 100644 --- a/browser_tests/tests/execution.spec.ts +++ b/browser_tests/tests/execution.spec.ts @@ -12,12 +12,12 @@ test.describe('Execution', { tag: ['@smoke', '@workflow'] }, () => { 'Report error on unconnected slot', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await comfyPage.canvasOps.clickEmptySpace( DefaultGraphPositions.emptySpaceClick ) - await comfyPage.executeCommand('Comfy.QueuePrompt') + await comfyPage.command.executeCommand('Comfy.QueuePrompt') await expect(comfyPage.page.locator('.comfy-error-report')).toBeVisible() await comfyPage.page .locator('.p-dialog') @@ -48,7 +48,7 @@ test.describe( await output1.click('title') - await comfyPage.executeCommand('Comfy.QueueSelectedOutputNodes') + await comfyPage.command.executeCommand('Comfy.QueueSelectedOutputNodes') await expect(async () => { expect(await (await input.getWidget(0)).getValue()).toBe('foo') expect(await (await output1.getWidget(0)).getValue()).toBe('foo') diff --git a/browser_tests/tests/extensionAPI.spec.ts b/browser_tests/tests/extensionAPI.spec.ts index 932fb0ef3..9b3d3a8e0 100644 --- a/browser_tests/tests/extensionAPI.spec.ts +++ b/browser_tests/tests/extensionAPI.spec.ts @@ -37,7 +37,7 @@ test.describe('Topbar commands', () => { test('Should not allow register command defined in other extension', async ({ comfyPage }) => { - await comfyPage.registerCommand('foo', () => alert(1)) + await comfyPage.command.registerCommand('foo', () => alert(1)) await comfyPage.page.evaluate(() => { window['app'].registerExtension({ name: 'TestExtension1', @@ -265,7 +265,7 @@ test.describe('Topbar commands', () => { }) }) - await comfyPage.fillPromptDialog('Hello, world!') + await comfyPage.nodeOps.fillPromptDialog('Hello, world!') expect(await comfyPage.page.evaluate(() => window['value'])).toBe( 'Hello, world!' ) diff --git a/browser_tests/tests/graph.spec.ts b/browser_tests/tests/graph.spec.ts index 949e216d5..4e1fdd1c6 100644 --- a/browser_tests/tests/graph.spec.ts +++ b/browser_tests/tests/graph.spec.ts @@ -21,6 +21,6 @@ test.describe('Graph', { tag: ['@smoke', '@canvas'] }, () => { test('Validate workflow links', async ({ comfyPage }) => { await comfyPage.settings.setSetting('Comfy.Validation.Workflows', true) await comfyPage.workflow.loadWorkflow('links/bad_link') - await expect(comfyPage.getVisibleToastCount()).resolves.toBe(2) + await expect(comfyPage.toast.getVisibleToastCount()).resolves.toBe(2) }) }) diff --git a/browser_tests/tests/groupNode.spec.ts b/browser_tests/tests/groupNode.spec.ts index 96248ec14..7d3abad34 100644 --- a/browser_tests/tests/groupNode.spec.ts +++ b/browser_tests/tests/groupNode.spec.ts @@ -279,7 +279,7 @@ test.describe('Group Node', { tag: '@node' }, () => { await comfyPage.settings.setSetting('Comfy.ConfirmClear', false) // Clear workflow - await comfyPage.executeCommand('Comfy.ClearWorkflow') + await comfyPage.command.executeCommand('Comfy.ClearWorkflow') await comfyPage.clipboard.paste() await verifyNodeLoaded(comfyPage, 1) @@ -323,18 +323,18 @@ test.describe('Group Node', { tag: '@node' }, () => { test.describe('Keybindings', () => { test('Convert to group node, no selection', async ({ comfyPage }) => { - expect(await comfyPage.getVisibleToastCount()).toBe(0) + expect(await comfyPage.toast.getVisibleToastCount()).toBe(0) await comfyPage.page.keyboard.press('Alt+g') - expect(await comfyPage.getVisibleToastCount()).toBe(1) + expect(await comfyPage.toast.getVisibleToastCount()).toBe(1) }) test('Convert to group node, selected 1 node', async ({ comfyPage }) => { - expect(await comfyPage.getVisibleToastCount()).toBe(0) + expect(await comfyPage.toast.getVisibleToastCount()).toBe(0) await comfyPage.canvas.click({ position: DefaultGraphPositions.textEncodeNode1 }) await comfyPage.nextFrame() await comfyPage.page.keyboard.press('Alt+g') - expect(await comfyPage.getVisibleToastCount()).toBe(1) + expect(await comfyPage.toast.getVisibleToastCount()).toBe(1) }) }) }) diff --git a/browser_tests/tests/interaction.spec.ts b/browser_tests/tests/interaction.spec.ts index ea3662a1d..e1e565a69 100644 --- a/browser_tests/tests/interaction.spec.ts +++ b/browser_tests/tests/interaction.spec.ts @@ -127,7 +127,7 @@ test.describe('Node Interaction', () => { }) => { const originalPositions = await getPositions() await dragSelectNodes(comfyPage, clipNodes) - await comfyPage.executeCommand( + await comfyPage.command.executeCommand( `Comfy.Canvas.MoveSelectedNodes.${direction}` ) await comfyPage.canvas.press(`Control+Arrow${direction}`) @@ -166,7 +166,7 @@ test.describe('Node Interaction', () => { }) test('Can drag node', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.dragNode2() + await comfyPage.nodeOps.dragTextEncodeNode2() await expect(comfyPage.canvas).toHaveScreenshot('dragged-node1.png') }) @@ -187,9 +187,9 @@ test.describe('Node Interaction', () => { test(`Can disconnect/connect edge ${reverse ? 'reverse' : 'normal'}`, async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await expect(comfyPage.canvas).toHaveScreenshot('disconnected-edge.png') - await comfyPage.connectEdge({ reverse }) + await comfyPage.canvasOps.connectEdge({ reverse }) // Move mouse to empty area to avoid slot highlight. await comfyPage.canvasOps.moveMouseToEmptyArea() // Litegraph renders edge with a slight offset. @@ -247,7 +247,7 @@ test.describe('Node Interaction', () => { 'Can adjust widget value', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.adjustWidgetValue() + await comfyPage.nodeOps.adjustEmptyLatentWidth() await expect(comfyPage.canvas).toHaveScreenshot( 'adjusted-widget-value.png' ) @@ -445,7 +445,7 @@ test.describe('Node Interaction', () => { await comfyPage.workflow.loadWorkflow('groups/oversized_group') await comfyPage.keyboard.selectAll() await comfyPage.nextFrame() - await comfyPage.executeCommand('Comfy.Graph.FitGroupToContents') + await comfyPage.command.executeCommand('Comfy.Graph.FitGroupToContents') await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot( 'group-fit-to-contents.png' @@ -455,10 +455,14 @@ test.describe('Node Interaction', () => { test('Can pin/unpin nodes', { tag: '@screenshot' }, async ({ comfyPage }) => { await comfyPage.nodeOps.selectNodes(['CLIP Text Encode (Prompt)']) - await comfyPage.executeCommand('Comfy.Canvas.ToggleSelectedNodes.Pin') + await comfyPage.command.executeCommand( + 'Comfy.Canvas.ToggleSelectedNodes.Pin' + ) await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot('nodes-pinned.png') - await comfyPage.executeCommand('Comfy.Canvas.ToggleSelectedNodes.Pin') + await comfyPage.command.executeCommand( + 'Comfy.Canvas.ToggleSelectedNodes.Pin' + ) await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot('nodes-unpinned.png') }) @@ -817,7 +821,7 @@ test.describe('Load duplicate workflow', () => { }) => { await comfyPage.workflow.loadWorkflow('nodes/single_ksampler') await comfyPage.menu.workflowsTab.open() - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') await comfyPage.workflow.loadWorkflow('nodes/single_ksampler') expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(1) }) diff --git a/browser_tests/tests/keybindings.spec.ts b/browser_tests/tests/keybindings.spec.ts index a40da0eef..f05e840dc 100644 --- a/browser_tests/tests/keybindings.spec.ts +++ b/browser_tests/tests/keybindings.spec.ts @@ -10,7 +10,7 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should not trigger non-modifier keybinding when typing in input fields', async ({ comfyPage }) => { - await comfyPage.registerKeybinding({ key: 'k' }, () => { + await comfyPage.command.registerKeybinding({ key: 'k' }, () => { window['TestCommand'] = true }) @@ -26,7 +26,7 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should not trigger modifier keybinding when typing in input fields', async ({ comfyPage }) => { - await comfyPage.registerKeybinding({ key: 'k', ctrl: true }, () => { + await comfyPage.command.registerKeybinding({ key: 'k', ctrl: true }, () => { window['TestCommand'] = true }) @@ -43,7 +43,7 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should not trigger keybinding reserved by text input when typing in input fields', async ({ comfyPage }) => { - await comfyPage.registerKeybinding({ key: 'Ctrl+v' }, () => { + await comfyPage.command.registerKeybinding({ key: 'Ctrl+v' }, () => { window['TestCommand'] = true }) diff --git a/browser_tests/tests/litegraphEvent.spec.ts b/browser_tests/tests/litegraphEvent.spec.ts index 1499acf09..a412200b5 100644 --- a/browser_tests/tests/litegraphEvent.spec.ts +++ b/browser_tests/tests/litegraphEvent.spec.ts @@ -17,7 +17,7 @@ function listenForEvent(): Promise { test.describe('Canvas Event', { tag: '@canvas' }, () => { test('Emit litegraph:canvas empty-release', async ({ comfyPage }) => { const eventPromise = comfyPage.page.evaluate(listenForEvent) - const disconnectPromise = comfyPage.disconnectEdge() + const disconnectPromise = comfyPage.canvasOps.disconnectEdge() const event = await eventPromise await disconnectPromise diff --git a/browser_tests/tests/loadWorkflowInMedia.spec.ts b/browser_tests/tests/loadWorkflowInMedia.spec.ts index 7254183a7..e5bbf2174 100644 --- a/browser_tests/tests/loadWorkflowInMedia.spec.ts +++ b/browser_tests/tests/loadWorkflowInMedia.spec.ts @@ -32,7 +32,7 @@ test.describe( test(`Load workflow in ${fileName} (drop from filesystem)`, async ({ comfyPage }) => { - await comfyPage.dragAndDropFile(`workflowInMedia/${fileName}`) + await comfyPage.dragDrop.dragAndDropFile(`workflowInMedia/${fileName}`) await expect(comfyPage.canvas).toHaveScreenshot(`${fileName}.png`) }) }) @@ -44,7 +44,7 @@ test.describe( test(`Load workflow from URL ${url} (drop from different browser tabs)`, async ({ comfyPage }) => { - await comfyPage.dragAndDropURL(url) + await comfyPage.dragDrop.dragAndDropURL(url) const readableName = url.split('/').pop() await expect(comfyPage.canvas).toHaveScreenshot( `dropped_workflow_url_${readableName}.png` diff --git a/browser_tests/tests/menu.spec.ts b/browser_tests/tests/menu.spec.ts index 203ad65f4..ae74784aa 100644 --- a/browser_tests/tests/menu.spec.ts +++ b/browser_tests/tests/menu.spec.ts @@ -175,7 +175,7 @@ test.describe('Menu', { tag: '@ui' }, () => { }) }) await comfyPage.menu.topbar.triggerTopbarCommand(['ext', 'foo-command']) - expect(await comfyPage.getVisibleToastCount()).toBe(1) + expect(await comfyPage.toast.getVisibleToastCount()).toBe(1) }) test('Can navigate Theme menu and switch between Dark and Light themes', async ({ diff --git a/browser_tests/tests/mobileBaseline.spec.ts b/browser_tests/tests/mobileBaseline.spec.ts index 521ccf537..da2b12c37 100644 --- a/browser_tests/tests/mobileBaseline.spec.ts +++ b/browser_tests/tests/mobileBaseline.spec.ts @@ -7,7 +7,7 @@ test.describe( () => { test('@mobile empty canvas', async ({ comfyPage }) => { await comfyPage.settings.setSetting('Comfy.ConfirmClear', false) - await comfyPage.executeCommand('Comfy.ClearWorkflow') + await comfyPage.command.executeCommand('Comfy.ClearWorkflow') await expect(async () => { expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(0) }).toPass({ timeout: 5000 }) diff --git a/browser_tests/tests/nodeSearchBox.spec.ts b/browser_tests/tests/nodeSearchBox.spec.ts index f30fb29aa..5085c210d 100644 --- a/browser_tests/tests/nodeSearchBox.spec.ts +++ b/browser_tests/tests/nodeSearchBox.spec.ts @@ -33,7 +33,7 @@ test.describe('Node search box', { tag: '@node' }, () => { }) test('Can trigger on link release', async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await expect(comfyPage.searchBox.input).toHaveCount(1) }) @@ -47,7 +47,7 @@ test.describe('Node search box', { tag: '@node' }, () => { await comfyPage.settings.setSetting('Comfy.NodeSearchBoxImpl', 'default') // Don't set LinkRelease settings explicitly to test versioned defaults - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await expect(comfyPage.searchBox.input).toHaveCount(1) await expect(comfyPage.searchBox.input).toBeVisible() }) @@ -60,7 +60,7 @@ test.describe('Node search box', { tag: '@node' }, () => { }) test('Can auto link node', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() // Select the second item as the first item is always reroute await comfyPage.searchBox.fillAndSelectFirstNode('CLIPTextEncode', { suggestionIndex: 0 @@ -100,7 +100,7 @@ test.describe('Node search box', { tag: '@node' }, () => { 'Link release connecting to node with no slots', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await expect(comfyPage.searchBox.input).toHaveCount(1) await comfyPage.page.locator('.p-chip-remove-icon').click() await comfyPage.searchBox.fillAndSelectFirstNode('KSampler') @@ -280,7 +280,7 @@ test.describe('Release context menu', { tag: '@node' }, () => { 'Can trigger on link release', { tag: '@screenshot' }, async ({ comfyPage }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() const contextMenu = comfyPage.page.locator('.litecontextmenu') // Wait for context menu with correct title (slot name | slot type) // The title shows the output slot name and type from the disconnected link @@ -299,7 +299,7 @@ test.describe('Release context menu', { tag: '@node' }, () => { 'Can search and add node from context menu', { tag: '@screenshot' }, async ({ comfyPage, comfyMouse }) => { - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() await comfyMouse.move({ x: 10, y: 10 }) await comfyPage.contextMenu.clickMenuItem('Search') await comfyPage.nextFrame() @@ -320,7 +320,7 @@ test.describe('Release context menu', { tag: '@node' }, () => { await comfyPage.settings.setSetting('Comfy.NodeSearchBoxImpl', 'default') // Don't set LinkRelease settings explicitly to test versioned defaults - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() // Context menu should appear, search box should not await expect(comfyPage.searchBox.input).toHaveCount(0) const contextMenu = comfyPage.page.locator('.litecontextmenu') @@ -340,7 +340,7 @@ test.describe('Release context menu', { tag: '@node' }, () => { ) await comfyPage.settings.setSetting('Comfy.NodeSearchBoxImpl', 'default') - await comfyPage.disconnectEdge() + await comfyPage.canvasOps.disconnectEdge() // Context menu should appear due to explicit setting, not search box await expect(comfyPage.searchBox.input).toHaveCount(0) const contextMenu = comfyPage.page.locator('.litecontextmenu') diff --git a/browser_tests/tests/rightClickMenu.spec.ts b/browser_tests/tests/rightClickMenu.spec.ts index a07ac261e..6ddc9942e 100644 --- a/browser_tests/tests/rightClickMenu.spec.ts +++ b/browser_tests/tests/rightClickMenu.spec.ts @@ -42,9 +42,9 @@ test.describe( 'Convert to Group Node (Deprecated)' ) await comfyPage.nextFrame() - await comfyPage.promptDialogInput.fill('GroupNode2CLIP') + await comfyPage.nodeOps.promptDialogInput.fill('GroupNode2CLIP') await comfyPage.page.keyboard.press('Enter') - await comfyPage.promptDialogInput.waitFor({ state: 'hidden' }) + await comfyPage.nodeOps.promptDialogInput.waitFor({ state: 'hidden' }) await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot( 'right-click-node-group-node.png' diff --git a/browser_tests/tests/sidebar/workflows.spec.ts b/browser_tests/tests/sidebar/workflows.spec.ts index a706fc80a..bd56a1b50 100644 --- a/browser_tests/tests/sidebar/workflows.spec.ts +++ b/browser_tests/tests/sidebar/workflows.spec.ts @@ -25,7 +25,7 @@ test.describe('Workflows sidebar', () => { '*Unsaved Workflow.json' ]) - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') expect(await tab.getOpenedWorkflowNames()).toEqual([ '*Unsaved Workflow.json', '*Unsaved Workflow (2).json' @@ -53,20 +53,20 @@ test.describe('Workflows sidebar', () => { expect.arrayContaining(['workflow1.json']) ) - await comfyPage.executeCommand('Comfy.DuplicateWorkflow') + await comfyPage.command.executeCommand('Comfy.DuplicateWorkflow') expect(await tab.getOpenedWorkflowNames()).toEqual([ 'workflow1.json', '*workflow1 (Copy).json' ]) - await comfyPage.executeCommand('Comfy.DuplicateWorkflow') + await comfyPage.command.executeCommand('Comfy.DuplicateWorkflow') expect(await tab.getOpenedWorkflowNames()).toEqual([ 'workflow1.json', '*workflow1 (Copy).json', '*workflow1 (Copy) (2).json' ]) - await comfyPage.executeCommand('Comfy.DuplicateWorkflow') + await comfyPage.command.executeCommand('Comfy.DuplicateWorkflow') expect(await tab.getOpenedWorkflowNames()).toEqual([ 'workflow1.json', '*workflow1 (Copy).json', @@ -82,7 +82,7 @@ test.describe('Workflows sidebar', () => { const tab = comfyPage.menu.workflowsTab await tab.open() - await comfyPage.executeCommand('Comfy.LoadDefaultWorkflow') + await comfyPage.command.executeCommand('Comfy.LoadDefaultWorkflow') const originalNodeCount = (await comfyPage.nodeOps.getNodes()).length await tab.insertWorkflow(tab.getPersistedItem('workflow1.json')) @@ -121,7 +121,7 @@ test.describe('Workflows sidebar', () => { }) test('Can save workflow as', async ({ comfyPage }) => { - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') await comfyPage.menu.topbar.saveWorkflowAs('workflow3.json') expect(await comfyPage.menu.workflowsTab.getOpenedWorkflowNames()).toEqual([ '*Unsaved Workflow.json', @@ -140,7 +140,7 @@ test.describe('Workflows sidebar', () => { comfyPage }) => { await comfyPage.workflow.loadWorkflow('default') - const exportedWorkflow = await comfyPage.getExportedWorkflow({ + const exportedWorkflow = await comfyPage.workflow.getExportedWorkflow({ api: false }) expect(exportedWorkflow).toBeDefined() @@ -170,14 +170,14 @@ test.describe('Workflows sidebar', () => { expect(download.suggestedFilename()).toBe('exported_default.json') // Get the exported workflow content - const downloadedContent = await comfyPage.getExportedWorkflow({ + const downloadedContent = await comfyPage.workflow.getExportedWorkflow({ api: false }) await comfyPage.settings.setSetting('Comfy.Locale', 'zh') await comfyPage.setup() - const downloadedContentZh = await comfyPage.getExportedWorkflow({ + const downloadedContentZh = await comfyPage.workflow.getExportedWorkflow({ api: false }) @@ -204,7 +204,7 @@ test.describe('Workflows sidebar', () => { test('Can save temporary workflow with unmodified name', async ({ comfyPage }) => { - expect(await comfyPage.isCurrentWorkflowModified()).toBe(false) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false) await comfyPage.menu.topbar.saveWorkflow('Unsaved Workflow') // Should not trigger the overwrite dialog @@ -212,7 +212,7 @@ test.describe('Workflows sidebar', () => { await comfyPage.page.locator('.comfy-modal-content:visible').count() ).toBe(0) - expect(await comfyPage.isCurrentWorkflowModified()).toBe(false) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false) }) test('Can overwrite other workflows with save as', async ({ comfyPage }) => { @@ -252,7 +252,7 @@ test.describe('Workflows sidebar', () => { // Load blank workflow await comfyPage.menu.workflowsTab.open() - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') // Switch back to the missing_nodes workflow await comfyPage.menu.workflowsTab.switchToWorkflow('missing_nodes') @@ -280,7 +280,7 @@ test.describe('Workflows sidebar', () => { test('Can close saved workflow with command', async ({ comfyPage }) => { const tab = comfyPage.menu.workflowsTab await comfyPage.menu.topbar.saveWorkflow('workflow1.json') - await comfyPage.executeCommand('Workspace.CloseWorkflow') + await comfyPage.command.executeCommand('Workspace.CloseWorkflow') expect(await tab.getOpenedWorkflowNames()).toEqual([ '*Unsaved Workflow.json' ]) diff --git a/browser_tests/tests/templates.spec.ts b/browser_tests/tests/templates.spec.ts index 63cfb0478..54f6360aa 100644 --- a/browser_tests/tests/templates.spec.ts +++ b/browser_tests/tests/templates.spec.ts @@ -75,13 +75,13 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { test('Can load template workflows', async ({ comfyPage }) => { // Clear the workflow await comfyPage.menu.workflowsTab.open() - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') await expect(async () => { expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(0) }).toPass({ timeout: 250 }) // Load a template - await comfyPage.executeCommand('Comfy.BrowseTemplates') + await comfyPage.command.executeCommand('Comfy.BrowseTemplates') await expect(comfyPage.templates.content).toBeVisible() await comfyPage.page @@ -112,7 +112,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { test('Uses proper locale files for templates', async ({ comfyPage }) => { await comfyPage.settings.setSetting('Comfy.Locale', 'fr') - await comfyPage.executeCommand('Comfy.BrowseTemplates') + await comfyPage.command.executeCommand('Comfy.BrowseTemplates') const dialog = comfyPage.page.getByRole('dialog').filter({ has: comfyPage.page.getByRole('heading', { name: 'Modèles', exact: true }) @@ -164,7 +164,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { ) // Load the templates dialog - await comfyPage.executeCommand('Comfy.BrowseTemplates') + await comfyPage.command.executeCommand('Comfy.BrowseTemplates') await expect(comfyPage.templates.content).toBeVisible() // Verify German was requested first, then English as fallback @@ -184,7 +184,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { comfyPage }) => { // Open templates dialog - await comfyPage.executeCommand('Comfy.BrowseTemplates') + await comfyPage.command.executeCommand('Comfy.BrowseTemplates') await comfyPage.templates.content.waitFor({ state: 'visible' }) const templateGrid = comfyPage.page.locator( @@ -275,7 +275,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => { }) // Open templates dialog - await comfyPage.executeCommand('Comfy.BrowseTemplates') + await comfyPage.command.executeCommand('Comfy.BrowseTemplates') await expect(comfyPage.templates.content).toBeVisible() // Wait for cards to load diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts b/browser_tests/tests/vueNodes/groups/groups.spec.ts index da17a0b25..5f691bbee 100644 --- a/browser_tests/tests/vueNodes/groups/groups.spec.ts +++ b/browser_tests/tests/vueNodes/groups/groups.spec.ts @@ -26,7 +26,7 @@ test.describe('Vue Node Groups', { tag: '@screenshot' }, () => { await comfyPage.setup() await comfyPage.workflow.loadWorkflow('groups/oversized_group') await comfyPage.keyboard.selectAll() - await comfyPage.executeCommand('Comfy.Graph.FitGroupToContents') + await comfyPage.command.executeCommand('Comfy.Graph.FitGroupToContents') await comfyPage.nextFrame() await expect(comfyPage.canvas).toHaveScreenshot( 'vue-groups-fit-to-contents.png' @@ -39,15 +39,17 @@ test.describe('Vue Node Groups', { tag: '@screenshot' }, () => { await comfyPage.workflow.loadWorkflow('groups/nested-groups-1-inner-node') // Get initial positions with null guards - const outerInitial = await comfyPage.getGroupPosition('Outer Group') - const innerInitial = await comfyPage.getGroupPosition('Inner Group') + const outerInitial = + await comfyPage.canvasOps.getGroupPosition('Outer Group') + const innerInitial = + await comfyPage.canvasOps.getGroupPosition('Inner Group') const initialOffsetX = innerInitial.x - outerInitial.x const initialOffsetY = innerInitial.y - outerInitial.y // Drag the outer group const dragDelta = { x: 100, y: 80 } - await comfyPage.dragGroup({ + await comfyPage.canvasOps.dragGroup({ name: 'Outer Group', deltaX: dragDelta.x, deltaY: dragDelta.y @@ -55,8 +57,10 @@ test.describe('Vue Node Groups', { tag: '@screenshot' }, () => { // Use retrying assertion to wait for positions to update await expect(async () => { - const outerFinal = await comfyPage.getGroupPosition('Outer Group') - const innerFinal = await comfyPage.getGroupPosition('Inner Group') + const outerFinal = + await comfyPage.canvasOps.getGroupPosition('Outer Group') + const innerFinal = + await comfyPage.canvasOps.getGroupPosition('Inner Group') const finalOffsetX = innerFinal.x - outerFinal.x const finalOffsetY = innerFinal.y - outerFinal.y diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts index 58c26d125..e6d8d0331 100644 --- a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts @@ -1049,9 +1049,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => { comfyMouse }) => { // Setup workflow with a KSampler node - await comfyPage.executeCommand('Comfy.NewBlankWorkflow') + await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow') await comfyPage.waitForGraphNodes(0) - await comfyPage.executeCommand('Workspace.SearchBox.Toggle') + await comfyPage.command.executeCommand('Workspace.SearchBox.Toggle') await comfyPage.nextFrame() await comfyPage.searchBox.fillAndSelectFirstNode('KSampler') await comfyPage.waitForGraphNodes(1) @@ -1061,7 +1061,7 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => { await comfyPage.nodeOps.getNodeRefsByType('KSampler') )?.[0] await comfyPage.vueNodes.selectNode(String(ksamplerNode.id)) - await comfyPage.executeCommand('Comfy.Graph.ConvertToSubgraph') + await comfyPage.command.executeCommand('Comfy.Graph.ConvertToSubgraph') // Enter the subgraph await comfyPage.vueNodes.enterSubgraph() diff --git a/browser_tests/tests/widget.spec.ts b/browser_tests/tests/widget.spec.ts index 51e7d26d5..92c5ff638 100644 --- a/browser_tests/tests/widget.spec.ts +++ b/browser_tests/tests/widget.spec.ts @@ -192,7 +192,7 @@ test.describe('Image widget', { tag: ['@screenshot', '@widget'] }, () => { const { x, y } = await loadImageNode.getPosition() // Drag and drop image file onto the load image node - await comfyPage.dragAndDropFile('image32x32.webp', { + await comfyPage.dragDrop.dragAndDropFile('image32x32.webp', { dropPosition: { x, y } }) @@ -282,7 +282,7 @@ test.describe( const { x, y } = await loadAnimatedWebpNode.getPosition() // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { + await comfyPage.dragDrop.dragAndDropFile('animated_webp.webp', { dropPosition: { x, y } }) @@ -311,7 +311,7 @@ test.describe( const { x, y } = await loadAnimatedWebpNode.getPosition() // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { + await comfyPage.dragDrop.dragAndDropFile('animated_webp.webp', { dropPosition: { x, y }, waitForUpload: true }) @@ -333,7 +333,7 @@ test.describe( const { x, y } = await loadAnimatedWebpNode.getPosition() // Drag and drop image file onto the load animated webp node - await comfyPage.dragAndDropFile('animated_webp.webp', { + await comfyPage.dragDrop.dragAndDropFile('animated_webp.webp', { dropPosition: { x, y } }) await comfyPage.nextFrame() @@ -383,6 +383,6 @@ test.describe('Unserialized widgets', { tag: '@widget' }, () => { await comfyPage.page.mouse.click(10, 10) // Expect the graph to not be modified - expect(await comfyPage.isCurrentWorkflowModified()).toBe(false) + expect(await comfyPage.workflow.isCurrentWorkflowModified()).toBe(false) }) })