From b56045c46240e37c2acc67a892f4c5b523a01d9c Mon Sep 17 00:00:00 2001 From: Alexander Brown <448862+DrJKL@users.noreply.github.com> Date: Sat, 31 Jan 2026 21:05:08 -0800 Subject: [PATCH] fix: browser_tests Phase 1 - mechanical fixes - Rename dragAndDrop to dragDrop (7 occurrences) - Add override modifiers in SidebarTab.ts (4 fixes) - Remove .ts import extensions in actionbar.spec.ts - Prefix unused variables with underscore (9 files) - Fix ESLint import() type annotation in globals.d.ts Reduces typecheck:browser errors from 229 to 215 Amp-Thread-ID: https://ampcode.com/threads/T-019c1787-c781-761d-b95a-4844e909e64c Co-authored-by: Amp --- browser_tests/fixtures/ComfyPage.ts | 4 +- .../fixtures/components/SidebarTab.ts | 8 +-- browser_tests/fixtures/components/Topbar.ts | 2 +- .../fixtures/helpers/CanvasHelper.ts | 12 ++--- .../fixtures/helpers/ClipboardHelper.ts | 2 +- .../fixtures/helpers/CommandHelper.ts | 6 +-- .../fixtures/helpers/NodeOperationsHelper.ts | 10 ++-- .../fixtures/helpers/SettingsHelper.ts | 4 +- .../fixtures/helpers/SubgraphHelper.ts | 10 ++-- .../fixtures/helpers/WorkflowHelper.ts | 10 ++-- .../fixtures/utils/litegraphUtils.ts | 50 +++++++++---------- browser_tests/globalSetup.ts | 2 +- browser_tests/globalTeardown.ts | 2 +- browser_tests/tests/actionbar.spec.ts | 8 +-- browser_tests/tests/browserTabTitle.spec.ts | 6 +-- browser_tests/tests/changeTracker.spec.ts | 6 +-- browser_tests/tests/colorPalette.spec.ts | 2 +- browser_tests/tests/commands.spec.ts | 2 +- browser_tests/tests/dialog.spec.ts | 6 +-- browser_tests/tests/extensionAPI.spec.ts | 28 +++++------ browser_tests/tests/graph.spec.ts | 2 +- browser_tests/tests/graphCanvasMenu.spec.ts | 2 +- browser_tests/tests/groupNode.spec.ts | 14 +++--- browser_tests/tests/lodThreshold.spec.ts | 24 ++++----- browser_tests/tests/menu.spec.ts | 4 +- browser_tests/tests/remoteWidgets.spec.ts | 10 ++-- .../tests/subgraph-rename-dialog.spec.ts | 9 ++-- browser_tests/tests/subgraph.spec.ts | 32 ++++++------ browser_tests/tests/useSettingSearch.spec.ts | 2 +- .../vueNodes/widgets/widgetReactivity.spec.ts | 12 ++--- browser_tests/tests/widget.spec.ts | 22 ++++---- browser_tests/tsconfig.json | 3 +- browser_tests/types/globals.d.ts | 6 ++- docs/guidance/playwright.md | 15 ++++++ 34 files changed, 181 insertions(+), 156 deletions(-) diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 7033325b5..f6c266cfb 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -96,7 +96,7 @@ class ComfyMenu { async getThemeId() { return await this.page.evaluate(async () => { - return await window.app.ui.settings.getSettingValue('Comfy.ColorPalette') + return await window.app!.ui.settings.getSettingValue('Comfy.ColorPalette') }) } } @@ -382,7 +382,7 @@ export class ComfyPage { async setFocusMode(focusMode: boolean) { await this.page.evaluate((focusMode) => { - window.app.extensionManager.focusMode = focusMode + window.app!.extensionManager.focusMode = focusMode }, focusMode) await this.nextFrame() } diff --git a/browser_tests/fixtures/components/SidebarTab.ts b/browser_tests/fixtures/components/SidebarTab.ts index 78145e9b6..0c64f0fe0 100644 --- a/browser_tests/fixtures/components/SidebarTab.ts +++ b/browser_tests/fixtures/components/SidebarTab.ts @@ -33,7 +33,7 @@ class SidebarTab { } export class NodeLibrarySidebarTab extends SidebarTab { - constructor(public readonly page: Page) { + constructor(public override readonly page: Page) { super(page, 'node-library') } @@ -59,12 +59,12 @@ export class NodeLibrarySidebarTab extends SidebarTab { return this.tabContainer.locator('.new-folder-button') } - async open() { + override async open() { await super.open() await this.nodeLibraryTree.waitFor({ state: 'visible' }) } - async close() { + override async close() { if (!this.tabButton.isVisible()) { return } @@ -101,7 +101,7 @@ export class NodeLibrarySidebarTab extends SidebarTab { } export class WorkflowsSidebarTab extends SidebarTab { - constructor(public readonly page: Page) { + constructor(public override readonly page: Page) { super(page, 'workflows') } diff --git a/browser_tests/fixtures/components/Topbar.ts b/browser_tests/fixtures/components/Topbar.ts index 24583ce22..e53bf4264 100644 --- a/browser_tests/fixtures/components/Topbar.ts +++ b/browser_tests/fixtures/components/Topbar.ts @@ -85,7 +85,7 @@ export class Topbar { // Wait for workflow service to finish saving await this.page.waitForFunction( - () => !window.app.extensionManager.workflow.isBusy, + () => !window.app!.extensionManager.workflow.isBusy, undefined, { timeout: 3000 } ) diff --git a/browser_tests/fixtures/helpers/CanvasHelper.ts b/browser_tests/fixtures/helpers/CanvasHelper.ts index 3aaf68902..41c1c2f6f 100644 --- a/browser_tests/fixtures/helpers/CanvasHelper.ts +++ b/browser_tests/fixtures/helpers/CanvasHelper.ts @@ -93,13 +93,13 @@ export class CanvasHelper { async getScale(): Promise { return this.page.evaluate(() => { - return window.app.canvas.ds.scale + return window.app!.canvas.ds.scale }) } async setScale(scale: number): Promise { await this.page.evaluate((s) => { - window.app.canvas.ds.scale = s + window.app!.canvas.ds.scale = s }, scale) await this.nextFrame() } @@ -108,13 +108,13 @@ export class CanvasHelper { pos: [number, number] ): Promise<[number, number]> { return this.page.evaluate((pos) => { - return window.app.canvas.ds.convertOffsetToCanvas(pos) + return window.app!.canvas.ds.convertOffsetToCanvas(pos) }, pos) } async getNodeCenterByTitle(title: string): Promise { return this.page.evaluate((title) => { - const app = window.app + const app = window.app! const node = app.graph.nodes.find( (n: { title: string }) => n.title === title ) @@ -129,7 +129,7 @@ export class CanvasHelper { async getGroupPosition(title: string): Promise { const pos = await this.page.evaluate((title) => { - const groups = window.app.graph.groups + 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] } @@ -145,7 +145,7 @@ export class CanvasHelper { }): Promise { const { name, deltaX, deltaY } = options const screenPos = await this.page.evaluate((title) => { - const app = window.app + const app = window.app! const groups = app.graph.groups const group = groups.find((g: { title: string }) => g.title === title) if (!group) return null diff --git a/browser_tests/fixtures/helpers/ClipboardHelper.ts b/browser_tests/fixtures/helpers/ClipboardHelper.ts index 4c9f1a2b5..cd900ead4 100644 --- a/browser_tests/fixtures/helpers/ClipboardHelper.ts +++ b/browser_tests/fixtures/helpers/ClipboardHelper.ts @@ -5,7 +5,7 @@ import type { KeyboardHelper } from './KeyboardHelper' export class ClipboardHelper { constructor( private readonly keyboard: KeyboardHelper, - private readonly canvas: Locator + private readonly _canvas: Locator ) {} async copy(locator?: Locator | null): Promise { diff --git a/browser_tests/fixtures/helpers/CommandHelper.ts b/browser_tests/fixtures/helpers/CommandHelper.ts index 8cf52dba3..58c2ef182 100644 --- a/browser_tests/fixtures/helpers/CommandHelper.ts +++ b/browser_tests/fixtures/helpers/CommandHelper.ts @@ -7,7 +7,7 @@ export class CommandHelper { async executeCommand(commandId: string): Promise { await this.page.evaluate((id: string) => { - return window.app.extensionManager.command.execute(id) + return window.app!.extensionManager.command.execute(id) }, commandId) } @@ -17,7 +17,7 @@ export class CommandHelper { ): Promise { await this.page.evaluate( ({ commandId, commandStr }) => { - const app = window.app + const app = window.app! const randomSuffix = Math.random().toString(36).substring(2, 8) const extensionName = `TestExtension_${randomSuffix}` @@ -41,7 +41,7 @@ export class CommandHelper { ): Promise { await this.page.evaluate( ({ keyCombo, commandStr }) => { - const app = window.app + const app = window.app! const randomSuffix = Math.random().toString(36).substring(2, 8) const extensionName = `TestExtension_${randomSuffix}` const commandId = `TestCommand_${randomSuffix}` diff --git a/browser_tests/fixtures/helpers/NodeOperationsHelper.ts b/browser_tests/fixtures/helpers/NodeOperationsHelper.ts index 843140099..f68ca4cda 100644 --- a/browser_tests/fixtures/helpers/NodeOperationsHelper.ts +++ b/browser_tests/fixtures/helpers/NodeOperationsHelper.ts @@ -35,7 +35,7 @@ export class NodeOperationsHelper { async getNodes(): Promise { return await this.page.evaluate(() => { - return window.app.graph.nodes + return window.app!.graph.nodes }) } @@ -47,7 +47,7 @@ export class NodeOperationsHelper { async getFirstNodeRef(): Promise { const id = await this.page.evaluate(() => { - return window.app.graph.nodes[0]?.id + return window.app!.graph.nodes[0]?.id }) if (!id) return null return this.getNodeRefById(id) @@ -66,7 +66,7 @@ export class NodeOperationsHelper { await this.page.evaluate( ({ type, includeSubgraph }) => { const graph = ( - includeSubgraph ? window.app.canvas.graph : window.app.graph + includeSubgraph ? window.app!.canvas.graph : window.app!.graph ) as LGraph const nodes = graph.nodes return nodes @@ -83,8 +83,8 @@ export class NodeOperationsHelper { return Promise.all( ( await this.page.evaluate((title) => { - return window.app.graph.nodes - .filter((n: LGraphNode) => n.title === title) + return window + .app!.graph.nodes.filter((n: LGraphNode) => n.title === title) .map((n: LGraphNode) => n.id) }, title) ).map((id: NodeId) => this.getNodeRefById(id)) diff --git a/browser_tests/fixtures/helpers/SettingsHelper.ts b/browser_tests/fixtures/helpers/SettingsHelper.ts index 5c48cb134..f9bde72a3 100644 --- a/browser_tests/fixtures/helpers/SettingsHelper.ts +++ b/browser_tests/fixtures/helpers/SettingsHelper.ts @@ -6,7 +6,7 @@ export class SettingsHelper { async setSetting(settingId: string, settingValue: unknown): Promise { await this.page.evaluate( async ({ id, value }) => { - await window.app.extensionManager.setting.set(id, value) + await window.app!.extensionManager.setting.set(id, value) }, { id: settingId, value: settingValue } ) @@ -14,7 +14,7 @@ export class SettingsHelper { async getSetting(settingId: string): Promise { return await this.page.evaluate(async (id) => { - return await window.app.extensionManager.setting.get(id) + return await window.app!.extensionManager.setting.get(id) }, settingId) } } diff --git a/browser_tests/fixtures/helpers/SubgraphHelper.ts b/browser_tests/fixtures/helpers/SubgraphHelper.ts index f8f54b1e1..96b8e18fe 100644 --- a/browser_tests/fixtures/helpers/SubgraphHelper.ts +++ b/browser_tests/fixtures/helpers/SubgraphHelper.ts @@ -27,7 +27,7 @@ export class SubgraphHelper { const foundSlot = await this.page.evaluate( async (params) => { const { slotType, action, targetSlotName } = params - const app = window.app + const app = window.app! const currentGraph = app.canvas.graph // Check if we're in a subgraph @@ -242,7 +242,7 @@ export class SubgraphHelper { ? await targetSlot.getPosition() // Connect to existing slot : await targetSlot.getOpenSlotPosition() // Create new slot - await this.comfyPage.dragAndDrop( + await this.comfyPage.dragDrop( await sourceSlot.getPosition(), targetPosition ) @@ -267,7 +267,7 @@ export class SubgraphHelper { const targetPosition = await targetSlot.getPosition() - await this.comfyPage.dragAndDrop(sourcePosition, targetPosition) + await this.comfyPage.dragDrop(sourcePosition, targetPosition) await this.comfyPage.nextFrame() } @@ -287,7 +287,7 @@ export class SubgraphHelper { ? await targetSlot.getPosition() // Connect to existing slot : await targetSlot.getOpenSlotPosition() // Create new slot - await this.comfyPage.dragAndDrop( + await this.comfyPage.dragDrop( await sourceSlot.getPosition(), targetPosition ) @@ -310,7 +310,7 @@ export class SubgraphHelper { ? await sourceSlot.getPosition() // Connect from existing slot : await sourceSlot.getOpenSlotPosition() // Create new slot - await this.comfyPage.dragAndDrop( + await this.comfyPage.dragDrop( sourcePosition, await targetSlot.getPosition() ) diff --git a/browser_tests/fixtures/helpers/WorkflowHelper.ts b/browser_tests/fixtures/helpers/WorkflowHelper.ts index bc1dde7de..61ea974e8 100644 --- a/browser_tests/fixtures/helpers/WorkflowHelper.ts +++ b/browser_tests/fixtures/helpers/WorkflowHelper.ts @@ -45,7 +45,7 @@ export class WorkflowHelper { } await this.comfyPage.page.evaluate(async () => { - await window.app.extensionManager.workflow.syncWorkflows() + await window.app!.extensionManager.workflow.syncWorkflows() }) // Wait for Vue to re-render the workflow list @@ -86,7 +86,7 @@ export class WorkflowHelper { async getUndoQueueSize(): Promise { return this.comfyPage.page.evaluate(() => { - const workflow = (window.app.extensionManager as WorkspaceStore).workflow + const workflow = (window.app!.extensionManager as WorkspaceStore).workflow .activeWorkflow return workflow?.changeTracker.undoQueue.length }) @@ -94,7 +94,7 @@ export class WorkflowHelper { async getRedoQueueSize(): Promise { return this.comfyPage.page.evaluate(() => { - const workflow = (window.app.extensionManager as WorkspaceStore).workflow + const workflow = (window.app!.extensionManager as WorkspaceStore).workflow .activeWorkflow return workflow?.changeTracker.redoQueue.length }) @@ -102,7 +102,7 @@ export class WorkflowHelper { async isCurrentWorkflowModified(): Promise { return this.comfyPage.page.evaluate(() => { - return (window.app.extensionManager as WorkspaceStore).workflow + return (window.app!.extensionManager as WorkspaceStore).workflow .activeWorkflow?.isModified }) } @@ -110,7 +110,7 @@ export class WorkflowHelper { async getExportedWorkflow(options?: { api?: boolean }): Promise { const api = options?.api ?? false return this.comfyPage.page.evaluate(async (api) => { - return (await window.app.graphToPrompt())[api ? 'output' : 'workflow'] + return (await window.app!.graphToPrompt())[api ? 'output' : 'workflow'] }, api) } } diff --git a/browser_tests/fixtures/utils/litegraphUtils.ts b/browser_tests/fixtures/utils/litegraphUtils.ts index 950a25169..abd30ca56 100644 --- a/browser_tests/fixtures/utils/litegraphUtils.ts +++ b/browser_tests/fixtures/utils/litegraphUtils.ts @@ -23,7 +23,7 @@ export class SubgraphSlotReference { async getPosition(): Promise { const pos: [number, number] = await this.comfyPage.page.evaluate( ([type, slotName]) => { - const currentGraph = window.app.canvas.graph + const currentGraph = window.app!.canvas.graph // Check if we're in a subgraph if (currentGraph.constructor.name !== 'Subgraph') { @@ -52,7 +52,7 @@ export class SubgraphSlotReference { } // Convert from offset to canvas coordinates - const canvasPos = window.app.canvas.ds.convertOffsetToCanvas([ + const canvasPos = window.app!.canvas.ds.convertOffsetToCanvas([ slot.pos[0], slot.pos[1] ]) @@ -70,7 +70,7 @@ export class SubgraphSlotReference { async getOpenSlotPosition(): Promise { const pos: [number, number] = await this.comfyPage.page.evaluate( ([type]) => { - const currentGraph = window.app.canvas.graph + const currentGraph = window.app!.canvas.graph if (currentGraph.constructor.name !== 'Subgraph') { throw new Error( @@ -86,7 +86,7 @@ export class SubgraphSlotReference { } // Convert from offset to canvas coordinates - const canvasPos = window.app.canvas.ds.convertOffsetToCanvas([ + const canvasPos = window.app!.canvas.ds.convertOffsetToCanvas([ node.emptySlot.pos[0], node.emptySlot.pos[1] ]) @@ -112,11 +112,11 @@ class NodeSlotReference { const pos: [number, number] = await this.node.comfyPage.page.evaluate( ([type, id, index]) => { // Use canvas.graph to get the current graph (works in both main graph and subgraphs) - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) const rawPos = node.getConnectionPos(type === 'input', index) - const convertedPos = window.app.canvas.ds.convertOffsetToCanvas(rawPos) + const convertedPos = window.app!.canvas.ds.convertOffsetToCanvas(rawPos) // Debug logging - convert Float64Arrays to regular arrays for visibility console.warn( @@ -126,7 +126,7 @@ class NodeSlotReference { nodeSize: [node.size[0], node.size[1]], rawConnectionPos: [rawPos[0], rawPos[1]], convertedPos: [convertedPos[0], convertedPos[1]], - currentGraphType: window.app.canvas.graph.constructor.name + currentGraphType: window.app!.canvas.graph.constructor.name } ) @@ -142,7 +142,7 @@ class NodeSlotReference { async getLinkCount() { return await this.node.comfyPage.page.evaluate( ([type, id, index]) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) if (type === 'input') { return node.inputs[index].link == null ? 0 : 1 @@ -155,7 +155,7 @@ class NodeSlotReference { async removeLinks() { await this.node.comfyPage.page.evaluate( ([type, id, index]) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) if (type === 'input') { node.disconnectInput(index) @@ -180,15 +180,15 @@ class NodeWidgetReference { async getPosition(): Promise { const pos: [number, number] = await this.node.comfyPage.page.evaluate( ([id, index]) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) const widget = node.widgets[index] if (!widget) throw new Error(`Widget ${index} not found.`) - const [x, y, w, h] = node.getBounding() - return window.app.canvasPosToClientPos([ + const [x, y, w, _h] = node.getBounding() + return window.app!.canvasPosToClientPos([ x + w / 2, - y + window.LiteGraph['NODE_TITLE_HEIGHT'] + widget.last_y + 1 + y + window.LiteGraph!['NODE_TITLE_HEIGHT'] + widget.last_y + 1 ]) }, [this.node.id, this.index] as const @@ -205,7 +205,7 @@ class NodeWidgetReference { async getSocketPosition(): Promise { const pos: [number, number] = await this.node.comfyPage.page.evaluate( ([id, index]) => { - const node = window.app.graph.getNodeById(id) + const node = window.app!.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) const widget = node.widgets[index] if (!widget) throw new Error(`Widget ${index} not found.`) @@ -216,9 +216,9 @@ class NodeWidgetReference { if (!slot) throw new Error(`Socket ${widget.name} not found.`) const [x, y] = node.getBounding() - return window.app.canvasPosToClientPos([ + return window.app!.canvasPosToClientPos([ x + slot.pos[0], - y + slot.pos[1] + window.LiteGraph['NODE_TITLE_HEIGHT'] + y + slot.pos[1] + window.LiteGraph!['NODE_TITLE_HEIGHT'] ]) }, [this.node.id, this.index] as const @@ -239,7 +239,7 @@ class NodeWidgetReference { const pos = await this.getPosition() const canvas = this.node.comfyPage.canvas const canvasPos = (await canvas.boundingBox())! - await this.node.comfyPage.dragAndDrop( + await this.node.comfyPage.dragDrop( { x: canvasPos.x + pos.x, y: canvasPos.y + pos.y @@ -254,7 +254,7 @@ class NodeWidgetReference { async getValue() { return await this.node.comfyPage.page.evaluate( ([id, index]) => { - const node = window.app.graph.getNodeById(id) + const node = window.app!.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) const widget = node.widgets[index] if (!widget) throw new Error(`Widget ${index} not found.`) @@ -271,7 +271,7 @@ export class NodeReference { ) {} async exists(): Promise { return await this.comfyPage.page.evaluate((id) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) return !!node }, this.id) } @@ -290,7 +290,7 @@ export class NodeReference { async getBounding(): Promise { const [x, y, width, height]: [number, number, number, number] = await this.comfyPage.page.evaluate((id) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error('Node not found') return node.getBounding() }, this.id) @@ -328,7 +328,7 @@ export class NodeReference { async getProperty(prop: string): Promise { return await this.comfyPage.page.evaluate( ([id, prop]) => { - const node = window.app.canvas.graph.getNodeById(id) + const node = window.app!.canvas.graph.getNodeById(id) if (!node) throw new Error('Node not found') return node[prop] }, @@ -389,7 +389,7 @@ export class NodeReference { ) { const originSlot = await this.getOutput(originSlotIndex) const targetWidget = await targetNode.getWidget(targetWidgetIndex) - await this.comfyPage.dragAndDrop( + await this.comfyPage.dragDrop( await originSlot.getPosition(), await targetWidget.getSocketPosition() ) @@ -402,7 +402,7 @@ export class NodeReference { ) { const originSlot = await this.getOutput(originSlotIndex) const targetSlot = await targetNode.getInput(targetSlotIndex) - await this.comfyPage.dragAndDrop( + await this.comfyPage.dragDrop( await originSlot.getPosition(), await targetSlot.getPosition() ) @@ -452,7 +452,7 @@ export class NodeReference { } async navigateIntoSubgraph() { const titleHeight = await this.comfyPage.page.evaluate(() => { - return window.LiteGraph['NODE_TITLE_HEIGHT'] + return window.LiteGraph!['NODE_TITLE_HEIGHT'] }) const nodePos = await this.getPosition() const nodeSize = await this.getSize() @@ -466,7 +466,7 @@ export class NodeReference { const checkIsInSubgraph = async () => { return this.comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph?.constructor?.name === 'Subgraph' }) } diff --git a/browser_tests/globalSetup.ts b/browser_tests/globalSetup.ts index 881ef11c4..b43b77c6a 100644 --- a/browser_tests/globalSetup.ts +++ b/browser_tests/globalSetup.ts @@ -5,7 +5,7 @@ import { backupPath } from './utils/backupUtils' dotenv.config() -export default function globalSetup(config: FullConfig) { +export default function globalSetup(_config: FullConfig) { if (!process.env.CI) { if (process.env.TEST_COMFYUI_DIR) { backupPath([process.env.TEST_COMFYUI_DIR, 'user']) diff --git a/browser_tests/globalTeardown.ts b/browser_tests/globalTeardown.ts index aeed77294..c69f563df 100644 --- a/browser_tests/globalTeardown.ts +++ b/browser_tests/globalTeardown.ts @@ -5,7 +5,7 @@ import { restorePath } from './utils/backupUtils' dotenv.config() -export default function globalTeardown(config: FullConfig) { +export default function globalTeardown(_config: FullConfig) { if (!process.env.CI && process.env.TEST_COMFYUI_DIR) { restorePath([process.env.TEST_COMFYUI_DIR, 'user']) restorePath([process.env.TEST_COMFYUI_DIR, 'models']) diff --git a/browser_tests/tests/actionbar.spec.ts b/browser_tests/tests/actionbar.spec.ts index ada32f215..e1576f723 100644 --- a/browser_tests/tests/actionbar.spec.ts +++ b/browser_tests/tests/actionbar.spec.ts @@ -1,9 +1,9 @@ import type { Response } from '@playwright/test' import { expect, mergeTests } from '@playwright/test' -import type { StatusWsMessage } from '../../src/schemas/apiSchema.ts' -import { comfyPageFixture } from '../fixtures/ComfyPage.ts' -import { webSocketFixture } from '../fixtures/ws.ts' +import type { StatusWsMessage } from '../../src/schemas/apiSchema' +import { comfyPageFixture } from '../fixtures/ComfyPage' +import { webSocketFixture } from '../fixtures/ws' const test = mergeTests(comfyPageFixture, webSocketFixture) @@ -49,7 +49,7 @@ test.describe('Actionbar', { tag: '@ui' }, () => { // Find and set the width on the latent node const triggerChange = async (value: number) => { return await comfyPage.page.evaluate((value) => { - const node = window.app.graph._nodes.find( + const node = window.app!.graph!._nodes.find( (n) => n.type === 'EmptyLatentImage' ) node.widgets[0].value = value diff --git a/browser_tests/tests/browserTabTitle.spec.ts b/browser_tests/tests/browserTabTitle.spec.ts index 73fcd67f1..8abe15877 100644 --- a/browser_tests/tests/browserTabTitle.spec.ts +++ b/browser_tests/tests/browserTabTitle.spec.ts @@ -11,7 +11,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { test('Can display workflow name', async ({ comfyPage }) => { const workflowName = await comfyPage.page.evaluate(async () => { - return window.app.extensionManager.workflow.activeWorkflow.filename + return window.app!.extensionManager.workflow.activeWorkflow.filename }) expect(await comfyPage.page.title()).toBe(`*${workflowName} - ComfyUI`) }) @@ -22,7 +22,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { comfyPage }) => { const workflowName = await comfyPage.page.evaluate(async () => { - return window.app.extensionManager.workflow.activeWorkflow.filename + return window.app!.extensionManager.workflow.activeWorkflow.filename }) expect(await comfyPage.page.title()).toBe(`${workflowName} - ComfyUI`) @@ -38,7 +38,7 @@ test.describe('Browser tab title', { tag: '@smoke' }, () => { // Delete the saved workflow for cleanup. await comfyPage.page.evaluate(async () => { - return window.app.extensionManager.workflow.activeWorkflow.delete() + return window.app!.extensionManager.workflow.activeWorkflow.delete() }) }) }) diff --git a/browser_tests/tests/changeTracker.spec.ts b/browser_tests/tests/changeTracker.spec.ts index 3d80d280c..2415561ec 100644 --- a/browser_tests/tests/changeTracker.spec.ts +++ b/browser_tests/tests/changeTracker.spec.ts @@ -7,12 +7,12 @@ import { DefaultGraphPositions } from '../fixtures/constants/defaultGraphPositio async function beforeChange(comfyPage: ComfyPage) { await comfyPage.page.evaluate(() => { - window.app.canvas.emitBeforeChange() + window.app!.canvas!.emitBeforeChange() }) } async function afterChange(comfyPage: ComfyPage) { await comfyPage.page.evaluate(() => { - window.app.canvas.emitAfterChange() + window.app!.canvas!.emitAfterChange() }) } @@ -159,7 +159,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => { test('Can detect changes in workflow.extra', async ({ comfyPage }) => { expect(await comfyPage.workflow.getUndoQueueSize()).toBe(0) await comfyPage.page.evaluate(() => { - window.app.graph.extra.foo = 'bar' + window.app!.graph!.extra.foo = 'bar' }) // Click empty space to trigger a change detection. await comfyPage.canvasOps.clickEmptySpace( diff --git a/browser_tests/tests/colorPalette.spec.ts b/browser_tests/tests/colorPalette.spec.ts index 883d32a95..f26332c7b 100644 --- a/browser_tests/tests/colorPalette.spec.ts +++ b/browser_tests/tests/colorPalette.spec.ts @@ -179,7 +179,7 @@ test.describe('Color Palette', { tag: ['@screenshot', '@settings'] }, () => { test('Can add custom color palette', async ({ comfyPage }) => { await comfyPage.page.evaluate((p) => { - window.app.extensionManager.colorPalette.addCustomColorPalette(p) + window.app!.extensionManager.colorPalette.addCustomColorPalette(p) }, customColorPalettes.obsidian_dark) expect(await comfyPage.toast.getToastErrorCount()).toBe(0) diff --git a/browser_tests/tests/commands.spec.ts b/browser_tests/tests/commands.spec.ts index 5c371c5db..d4e4f7fbf 100644 --- a/browser_tests/tests/commands.spec.ts +++ b/browser_tests/tests/commands.spec.ts @@ -41,7 +41,7 @@ test.describe('Keybindings', { tag: '@keyboard' }, () => { test('Should handle async command errors', async ({ comfyPage }) => { await comfyPage.command.registerCommand('TestCommand', async () => { - await new Promise((resolve, reject) => + await new Promise((_resolve, reject) => setTimeout(() => { reject(new Error('Test error')) }, 5) diff --git a/browser_tests/tests/dialog.spec.ts b/browser_tests/tests/dialog.spec.ts index b629adf0c..470862cba 100644 --- a/browser_tests/tests/dialog.spec.ts +++ b/browser_tests/tests/dialog.spec.ts @@ -345,7 +345,7 @@ test.describe('Error dialog', () => { comfyPage }) => { await comfyPage.page.evaluate(() => { - const graph = window.graph + const graph = window.graph! graph.configure = () => { throw new Error('Error on configure!') } @@ -361,7 +361,7 @@ test.describe('Error dialog', () => { comfyPage }) => { await comfyPage.page.evaluate(async () => { - const app = window.app + const app = window.app! app.api.queuePrompt = () => { throw new Error('Error on queuePrompt!') } @@ -391,7 +391,7 @@ test.describe('Signin dialog', () => { await textBox.press('Control+c') await comfyPage.page.evaluate(() => { - void window.app.extensionManager.dialog.showSignInDialog() + void window.app!.extensionManager.dialog.showSignInDialog() }) const input = comfyPage.page.locator('#comfy-org-sign-in-password') diff --git a/browser_tests/tests/extensionAPI.spec.ts b/browser_tests/tests/extensionAPI.spec.ts index 660821152..19eaa2142 100644 --- a/browser_tests/tests/extensionAPI.spec.ts +++ b/browser_tests/tests/extensionAPI.spec.ts @@ -10,7 +10,7 @@ test.describe('Topbar commands', () => { test('Should allow registering topbar commands', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', commands: [ { @@ -39,7 +39,7 @@ test.describe('Topbar commands', () => { }) => { await comfyPage.command.registerCommand('foo', () => alert(1)) await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', menuCommands: [ { @@ -56,7 +56,7 @@ test.describe('Topbar commands', () => { test('Should allow registering keybindings', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - const app = window.app + const app = window.app! app.registerExtension({ name: 'TestExtension1', commands: [ @@ -83,7 +83,7 @@ test.describe('Topbar commands', () => { test.describe('Settings', () => { test('Should allow adding settings', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', settings: [ { @@ -113,7 +113,7 @@ test.describe('Topbar commands', () => { test('Should allow setting boolean settings', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', settings: [ { @@ -197,7 +197,7 @@ test.describe('Topbar commands', () => { comfyPage }) => { await comfyPage.page.evaluate((config) => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', settings: [ { @@ -230,7 +230,7 @@ test.describe('Topbar commands', () => { test.describe('About panel', () => { test('Should allow adding badges', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', aboutPageBadges: [ { @@ -253,8 +253,8 @@ test.describe('Topbar commands', () => { test.describe('Dialog', () => { test('Should allow showing a prompt dialog', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - void window.app.extensionManager.dialog - .prompt({ + void window + .app!.extensionManager.dialog.prompt({ title: 'Test Prompt', message: 'Test Prompt Message' }) @@ -273,8 +273,8 @@ test.describe('Topbar commands', () => { comfyPage }) => { await comfyPage.page.evaluate(() => { - void window.app.extensionManager.dialog - .confirm({ + void window + .app!.extensionManager.dialog.confirm({ title: 'Test Confirm', message: 'Test Confirm Message' }) @@ -290,8 +290,8 @@ test.describe('Topbar commands', () => { test('Should allow dismissing a dialog', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { window['value'] = 'foo' - void window.app.extensionManager.dialog - .confirm({ + void window + .app!.extensionManager.dialog.confirm({ title: 'Test Confirm', message: 'Test Confirm Message' }) @@ -315,7 +315,7 @@ test.describe('Topbar commands', () => { }) => { // Register an extension with a selection toolbox command await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', commands: [ { diff --git a/browser_tests/tests/graph.spec.ts b/browser_tests/tests/graph.spec.ts index c91d91d31..5ec85259a 100644 --- a/browser_tests/tests/graph.spec.ts +++ b/browser_tests/tests/graph.spec.ts @@ -13,7 +13,7 @@ test.describe('Graph', { tag: ['@smoke', '@canvas'] }, () => { await comfyPage.workflow.loadWorkflow('inputs/input_order_swap') expect( await comfyPage.page.evaluate(() => { - return window.app.graph.links.get(1)?.target_slot + return window.app!.graph!.links.get(1)?.target_slot }) ).toBe(1) }) diff --git a/browser_tests/tests/graphCanvasMenu.spec.ts b/browser_tests/tests/graphCanvasMenu.spec.ts index 754cd6ef0..5dc35217e 100644 --- a/browser_tests/tests/graphCanvasMenu.spec.ts +++ b/browser_tests/tests/graphCanvasMenu.spec.ts @@ -26,7 +26,7 @@ test.describe('Graph Canvas Menu', { tag: ['@screenshot', '@canvas'] }, () => { 'canvas-with-hidden-links.png' ) const hiddenLinkRenderMode = await comfyPage.page.evaluate(() => { - return window.LiteGraph.HIDDEN_LINK + return window.LiteGraph!.HIDDEN_LINK }) expect(await comfyPage.settings.getSetting('Comfy.LinkRenderMode')).toBe( hiddenLinkRenderMode diff --git a/browser_tests/tests/groupNode.spec.ts b/browser_tests/tests/groupNode.spec.ts index 0590b728e..48d8f0eba 100644 --- a/browser_tests/tests/groupNode.spec.ts +++ b/browser_tests/tests/groupNode.spec.ts @@ -23,7 +23,9 @@ test.describe('Group Node', { tag: '@node' }, () => { await libraryTab.open() }) - test('Is added to node library sidebar', async ({ comfyPage }) => { + test('Is added to node library sidebar', async ({ + comfyPage: _comfyPage + }) => { expect(await libraryTab.getFolder('group nodes').count()).toBe(1) }) @@ -158,7 +160,7 @@ test.describe('Group Node', { tag: '@node' }, () => { const totalInputCount = await comfyPage.page.evaluate((nodeName) => { const { extra: { groupNodes } - } = window.app.graph + } = window.app!.graph! const { nodes } = groupNodes[nodeName] return nodes.reduce((acc: number, node) => { return acc + node.inputs.length @@ -166,7 +168,7 @@ test.describe('Group Node', { tag: '@node' }, () => { }, groupNodeName) const visibleInputCount = await comfyPage.page.evaluate((id) => { - const node = window.app.graph.getNodeById(id) + const node = window.app!.graph!.getNodeById(id) return node.inputs.length }, groupNodeId) @@ -233,7 +235,7 @@ test.describe('Group Node', { tag: '@node' }, () => { const isRegisteredLitegraph = async (comfyPage: ComfyPage) => { return await comfyPage.page.evaluate((nodeType: string) => { - return !!window.LiteGraph.registered_node_types[nodeType] + return !!window.LiteGraph!.registered_node_types[nodeType] }, GROUP_NODE_TYPE) } @@ -307,12 +309,12 @@ test.describe('Group Node', { tag: '@node' }, () => { await comfyPage.menu.topbar.triggerTopbarCommand(['New']) await comfyPage.clipboard.paste() const currentGraphState = await comfyPage.page.evaluate(() => - window.app.graph.serialize() + window.app!.graph!.serialize() ) await test.step('Load workflow containing a group node pasted from a different workflow', async () => { await comfyPage.page.evaluate( - (workflow) => window.app.loadGraphData(workflow), + (workflow) => window.app!.loadGraphData(workflow), currentGraphState ) await comfyPage.nextFrame() diff --git a/browser_tests/tests/lodThreshold.spec.ts b/browser_tests/tests/lodThreshold.spec.ts index 45f37a146..e1bf11dae 100644 --- a/browser_tests/tests/lodThreshold.spec.ts +++ b/browser_tests/tests/lodThreshold.spec.ts @@ -15,7 +15,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // Get initial LOD state and settings const initialState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale, @@ -36,7 +36,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { await comfyPage.nextFrame() const aboveThresholdState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale @@ -54,7 +54,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // Check that LOD is now active const zoomedOutState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale @@ -70,7 +70,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // Check that LOD is now inactive const zoomedInState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale @@ -94,7 +94,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // Check that font size updated const newState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { minFontSize: canvas.min_font_size_for_lod } @@ -105,7 +105,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // At default zoom, LOD should still be inactive (scale is exactly 1.0, not less than) const lodState = await comfyPage.page.evaluate(() => { - return window.app.canvas.low_quality + return window.app!.canvas.low_quality }) expect(lodState).toBe(false) @@ -114,7 +114,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { await comfyPage.nextFrame() const afterZoom = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale @@ -139,7 +139,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // LOD should remain disabled even at very low zoom const state = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale, @@ -164,8 +164,8 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { // Zoom to target level await comfyPage.page.evaluate((zoom) => { - window.app.canvas.ds.scale = zoom - window.app.canvas.setDirty(true, true) + window.app!.canvas.ds.scale = zoom + window.app!.canvas.setDirty(true, true) }, targetZoom) await comfyPage.nextFrame() @@ -175,7 +175,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { ) const lowQualityState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale @@ -196,7 +196,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => { ) const highQualityState = await comfyPage.page.evaluate(() => { - const canvas = window.app.canvas + const canvas = window.app!.canvas return { lowQuality: canvas.low_quality, scale: canvas.ds.scale diff --git a/browser_tests/tests/menu.spec.ts b/browser_tests/tests/menu.spec.ts index 83b7b8550..eb5b93825 100644 --- a/browser_tests/tests/menu.spec.ts +++ b/browser_tests/tests/menu.spec.ts @@ -11,7 +11,7 @@ test.describe('Menu', { tag: '@ui' }, () => { const initialChildrenCount = await comfyPage.menu.buttons.count() await comfyPage.page.evaluate(async () => { - window.app.extensionManager.registerSidebarTab({ + window.app!.extensionManager.registerSidebarTab({ id: 'search', icon: 'pi pi-search', title: 'search', @@ -155,7 +155,7 @@ test.describe('Menu', { tag: '@ui' }, () => { test('Can catch error when executing command', async ({ comfyPage }) => { await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestExtension1', commands: [ { diff --git a/browser_tests/tests/remoteWidgets.spec.ts b/browser_tests/tests/remoteWidgets.spec.ts index 0ad27670b..23147ed21 100644 --- a/browser_tests/tests/remoteWidgets.spec.ts +++ b/browser_tests/tests/remoteWidgets.spec.ts @@ -26,21 +26,21 @@ test.describe('Remote COMBO Widget', { tag: '@widget' }, () => { nodeName: string ): Promise => { return await comfyPage.page.evaluate((name) => { - const node = window.app.graph.nodes.find((node) => node.title === name) + const node = window.app!.graph!.nodes.find((node) => node.title === name) return node.widgets[0].options.values }, nodeName) } const getWidgetValue = async (comfyPage: ComfyPage, nodeName: string) => { return await comfyPage.page.evaluate((name) => { - const node = window.app.graph.nodes.find((node) => node.title === name) + const node = window.app!.graph!.nodes.find((node) => node.title === name) return node.widgets[0].value }, nodeName) } const clickRefreshButton = (comfyPage: ComfyPage, nodeName: string) => { return comfyPage.page.evaluate((name) => { - const node = window.app.graph.nodes.find((node) => node.title === name) + const node = window.app!.graph!.nodes.find((node) => node.title === name) const buttonWidget = node.widgets.find((w) => w.name === 'refresh') return buttonWidget?.callback() }, nodeName) @@ -92,7 +92,7 @@ test.describe('Remote COMBO Widget', { tag: '@widget' }, () => { await comfyPage.workflow.loadWorkflow('inputs/remote_widget') const node = await comfyPage.page.evaluate((name) => { - return window.app.graph.nodes.find((node) => node.title === name) + return window.app!.graph!.nodes.find((node) => node.title === name) }, nodeName) expect(node).toBeDefined() @@ -196,7 +196,7 @@ test.describe('Remote COMBO Widget', { tag: '@widget' }, () => { // Fulfill each request with a unique timestamp await comfyPage.page.route( '**/api/models/checkpoints**', - async (route, request) => { + async (route, _request) => { await route.fulfill({ body: JSON.stringify([Date.now()]), status: 200 diff --git a/browser_tests/tests/subgraph-rename-dialog.spec.ts b/browser_tests/tests/subgraph-rename-dialog.spec.ts index b5aa3970f..4afc05b93 100644 --- a/browser_tests/tests/subgraph-rename-dialog.spec.ts +++ b/browser_tests/tests/subgraph-rename-dialog.spec.ts @@ -3,7 +3,6 @@ import { expect } from '@playwright/test' import { comfyPageFixture as test } from '../fixtures/ComfyPage' // Constants -const INITIAL_NAME = 'initial_slot_name' const RENAMED_NAME = 'renamed_slot_name' const SECOND_RENAMED_NAME = 'second_renamed_name' @@ -27,7 +26,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Get initial slot label const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || graph.inputs?.[0]?.name || null }) @@ -56,7 +55,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Verify the rename worked const afterFirstRename = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph const slot = graph.inputs?.[0] return { label: slot?.label || null, @@ -99,7 +98,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Verify the second rename worked const afterSecondRename = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) expect(afterSecondRename).toBe(SECOND_RENAMED_NAME) @@ -115,7 +114,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => { // Get initial output slot label const initialOutputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.outputs?.[0]?.label || graph.outputs?.[0]?.name || null }) diff --git a/browser_tests/tests/subgraph.spec.ts b/browser_tests/tests/subgraph.spec.ts index 74d606daa..b9ad45680 100644 --- a/browser_tests/tests/subgraph.spec.ts +++ b/browser_tests/tests/subgraph.spec.ts @@ -27,7 +27,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { type: 'inputs' | 'outputs' ): Promise { return await comfyPage.page.evaluate((slotType) => { - return window.app.canvas.graph[slotType]?.length || 0 + return window.app!.canvas.graph[slotType]?.length || 0 }, type) } @@ -36,7 +36,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { comfyPage: typeof test.prototype.comfyPage ): Promise { return await comfyPage.page.evaluate(() => { - return window.app.canvas.graph.nodes?.length || 0 + return window.app!.canvas.graph.nodes?.length || 0 }) } @@ -45,7 +45,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { comfyPage: typeof test.prototype.comfyPage ): Promise { return await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph?.constructor?.name === 'Subgraph' }) } @@ -132,7 +132,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -151,7 +151,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -166,7 +166,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -183,7 +183,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -198,7 +198,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialOutputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.outputs?.[0]?.label || null }) @@ -216,7 +216,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newOutputName = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.outputs?.[0]?.label || null }) @@ -233,7 +233,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -254,7 +254,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -271,7 +271,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await subgraphNode.navigateIntoSubgraph() const initialInputLabel = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -326,7 +326,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { await comfyPage.nextFrame() const newInputName = await comfyPage.page.evaluate(() => { - const graph = window.app.canvas.graph + const graph = window.app!.canvas.graph return graph.inputs?.[0]?.label || null }) @@ -350,7 +350,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { test('Can create subgraph from selected nodes', async ({ comfyPage }) => { await comfyPage.workflow.loadWorkflow('default') - const initialNodeCount = await getGraphNodeCount(comfyPage) + const _initialNodeCount = await getGraphNodeCount(comfyPage) await comfyPage.keyboard.selectAll() await comfyPage.nextFrame() @@ -459,7 +459,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { const initialNodeCount = await getGraphNodeCount(comfyPage) const nodesInSubgraph = await comfyPage.page.evaluate(() => { - const nodes = window.app.canvas.graph.nodes + const nodes = window.app!.canvas.graph.nodes return nodes?.[0]?.id || null }) @@ -689,7 +689,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { // Check that the subgraph node has no widgets after removing the text slot const widgetCount = await comfyPage.page.evaluate(() => { - return window.app.canvas.graph.nodes[0].widgets?.length || 0 + return window.app!.canvas.graph.nodes[0].widgets?.length || 0 }) expect(widgetCount).toBe(0) diff --git a/browser_tests/tests/useSettingSearch.spec.ts b/browser_tests/tests/useSettingSearch.spec.ts index 2b989ab8b..bd8373fc1 100644 --- a/browser_tests/tests/useSettingSearch.spec.ts +++ b/browser_tests/tests/useSettingSearch.spec.ts @@ -10,7 +10,7 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { test.beforeEach(async ({ comfyPage }) => { // Register test settings to verify hidden/deprecated filtering await comfyPage.page.evaluate(() => { - window.app.registerExtension({ + window.app!.registerExtension({ name: 'TestSettingsExtension', settings: [ { diff --git a/browser_tests/tests/vueNodes/widgets/widgetReactivity.spec.ts b/browser_tests/tests/vueNodes/widgets/widgetReactivity.spec.ts index 7560a72b5..b60223df2 100644 --- a/browser_tests/tests/vueNodes/widgets/widgetReactivity.spec.ts +++ b/browser_tests/tests/vueNodes/widgets/widgetReactivity.spec.ts @@ -13,17 +13,17 @@ test.describe('Vue Widget Reactivity', () => { 'css=[data-testid="node-body-4"] > .lg-node-widgets > div' ) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['4'] + const node = window.graph!._nodes_by_id['4'] node.widgets.push(node.widgets[0]) }) await expect(loadCheckpointNode).toHaveCount(2) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['4'] + const node = window.graph!._nodes_by_id['4'] node.widgets[2] = node.widgets[0] }) await expect(loadCheckpointNode).toHaveCount(3) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['4'] + const node = window.graph!._nodes_by_id['4'] node.widgets.splice(0, 0, node.widgets[0]) }) await expect(loadCheckpointNode).toHaveCount(4) @@ -33,17 +33,17 @@ test.describe('Vue Widget Reactivity', () => { 'css=[data-testid="node-body-3"] > .lg-node-widgets > div' ) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['3'] + const node = window.graph!._nodes_by_id['3'] node.widgets.pop() }) await expect(loadCheckpointNode).toHaveCount(5) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['3'] + const node = window.graph!._nodes_by_id['3'] node.widgets.length-- }) await expect(loadCheckpointNode).toHaveCount(4) await comfyPage.page.evaluate(() => { - const node = window.graph._nodes_by_id['3'] + const node = window.graph!._nodes_by_id['3'] node.widgets.splice(0, 1) }) await expect(loadCheckpointNode).toHaveCount(3) diff --git a/browser_tests/tests/widget.spec.ts b/browser_tests/tests/widget.spec.ts index bef249734..27787dd4b 100644 --- a/browser_tests/tests/widget.spec.ts +++ b/browser_tests/tests/widget.spec.ts @@ -58,8 +58,10 @@ test.describe('Combo text widget', { tag: ['@screenshot', '@widget'] }, () => { }) => { const getComboValues = async () => comfyPage.page.evaluate(() => { - return window.app.graph.nodes - .find((node) => node.title === 'Node With Optional Combo Input') + return window + .app!.graph!.nodes.find( + (node) => node.title === 'Node With Optional Combo Input' + ) .widgets.find((widget) => widget.name === 'optional_combo_input') .options.values }) @@ -93,8 +95,10 @@ test.describe('Combo text widget', { tag: ['@screenshot', '@widget'] }, () => { await comfyPage.nextFrame() // get the combo widget's values const comboValues = await comfyPage.page.evaluate(() => { - return window.app.graph.nodes - .find((node) => node.title === 'Node With V2 Combo Input') + return window + .app!.graph!.nodes.find( + (node) => node.title === 'Node With V2 Combo Input' + ) .widgets.find((widget) => widget.name === 'combo_input').options.values }) expect(comboValues).toEqual(['A', 'B']) @@ -121,7 +125,7 @@ test.describe('Slider widget', { tag: ['@screenshot', '@widget'] }, () => { const widget = await node.getWidget(0) await comfyPage.page.evaluate(() => { - const widget = window.app.graph.nodes[0].widgets[0] + const widget = window.app!.graph!.nodes[0].widgets[0] widget.callback = (value: number) => { window.widgetValue = value } @@ -142,7 +146,7 @@ test.describe('Number widget', { tag: ['@screenshot', '@widget'] }, () => { const node = (await comfyPage.nodeOps.getFirstNodeRef())! const widget = await node.getWidget(0) await comfyPage.page.evaluate(() => { - const widget = window.app.graph.nodes[0].widgets[0] + const widget = window.app!.graph!.nodes[0].widgets[0] widget.callback = (value: number) => { window.widgetValue = value } @@ -166,8 +170,8 @@ test.describe( await comfyPage.workflow.loadWorkflow('nodes/single_ksampler') await comfyPage.page.evaluate(() => { - window.graph.nodes[0].addWidget('number', 'new_widget', 10) - window.graph.setDirtyCanvas(true, true) + window.graph!.nodes[0].addWidget('number', 'new_widget', 10) + window.graph!.setDirtyCanvas(true, true) }) await expect(comfyPage.canvas).toHaveScreenshot( @@ -349,7 +353,7 @@ test.describe( await comfyPage.page.evaluate( ([loadId, saveId]) => { // Set the output of the SaveAnimatedWEBP node to equal the loader node's image - window.app.nodeOutputs[saveId] = window.app.nodeOutputs[loadId] + window.app!.nodeOutputs[saveId] = window.app!.nodeOutputs[loadId] app.canvas.setDirty(true) }, [loadAnimatedWebpNode.id, saveAnimatedWebpNode.id] diff --git a/browser_tests/tsconfig.json b/browser_tests/tsconfig.json index 34e549c39..8e943db4b 100644 --- a/browser_tests/tsconfig.json +++ b/browser_tests/tsconfig.json @@ -5,7 +5,8 @@ "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "types": ["vite/client"] }, "include": [ "**/*.ts", diff --git a/browser_tests/types/globals.d.ts b/browser_tests/types/globals.d.ts index dbd7f4f9f..03f770cef 100644 --- a/browser_tests/types/globals.d.ts +++ b/browser_tests/types/globals.d.ts @@ -1,7 +1,6 @@ import type { ComfyApp } from '@/scripts/app' import type { LGraph } from '@/lib/litegraph' import type { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal' -import type { LGraphBadge } from '@/lib/litegraph/src/LGraphBadge' interface AppReadiness { featureFlagsReceived: boolean @@ -31,6 +30,11 @@ declare global { __capturedMessages?: CapturedMessages __appReadiness?: AppReadiness } + + const app: ComfyApp | undefined + const graph: LGraph | undefined + const LiteGraph: LiteGraphGlobal | undefined + const LGraphBadge: typeof LGraphBadge | undefined } export {} diff --git a/docs/guidance/playwright.md b/docs/guidance/playwright.md index 49f47f864..75eef9aa9 100644 --- a/docs/guidance/playwright.md +++ b/docs/guidance/playwright.md @@ -14,6 +14,21 @@ See `docs/testing/*.md` for detailed patterns. - Prefer specific selectors (role, label, test-id) - Test across viewports +## Window Globals + +Browser tests access `window.app`, `window.graph`, and `window.LiteGraph` which are +optional in the main app types. In E2E tests, use non-null assertions (`!`): + +```typescript +window.app!.graph!.nodes +window.LiteGraph!.registered_node_types +``` + +This is the **only context** where non-null assertions are acceptable. + +**TODO:** Consolidate these references into a central utility (e.g., `getApp()`) that +performs proper runtime type checking, removing the need for scattered `!` assertions. + ## Test Tags Tags are respected by config: