From eb2c4e29a395c93d5972d425531b1cbfed14cc10 Mon Sep 17 00:00:00 2001 From: DrJKL Date: Mon, 12 Jan 2026 10:17:53 -0800 Subject: [PATCH] fix(types): add null guards to browser_tests fixtures --- browser_tests/fixtures/ComfyPage.ts | 155 +++++++++++++----- .../fixtures/components/SidebarTab.ts | 17 +- browser_tests/fixtures/components/Topbar.ts | 9 +- .../fixtures/utils/litegraphUtils.ts | 142 +++++++++------- browser_tests/fixtures/utils/taskHistory.ts | 26 ++- 5 files changed, 237 insertions(+), 112 deletions(-) diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 08cdd5cce..aa812cd7b 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -81,11 +81,14 @@ class ComfyMenu { await this.themeToggleButton.click() await this.page.evaluate(() => { return new Promise((resolve) => { - window['app'].ui.settings.addEventListener( - 'Comfy.ColorPalette.change', - resolve, - { once: true } - ) + const app = window.app + if (!app) { + resolve(undefined) + return + } + app.ui.settings.addEventListener('Comfy.ColorPalette.change', resolve, { + once: true + }) setTimeout(resolve, 5000) }) @@ -94,9 +97,9 @@ class ComfyMenu { async getThemeId() { return await this.page.evaluate(async () => { - return await window['app'].ui.settings.getSettingValue( - 'Comfy.ColorPalette' - ) + const app = window.app + if (!app) return undefined + return await app.ui.settings.getSettingValue('Comfy.ColorPalette') }) } } @@ -138,7 +141,14 @@ class ConfirmDialog { // Wait for workflow service to finish if it's busy await this.page.waitForFunction( - () => window['app']?.extensionManager?.workflow?.isBusy === false, + () => { + const app = window.app + if (!app) return true + const extMgr = app.extensionManager as { + workflow?: { isBusy?: boolean } + } + return extMgr.workflow?.isBusy === false + }, undefined, { timeout: 3000 } ) @@ -256,7 +266,12 @@ export class ComfyPage { } await this.page.evaluate(async () => { - await window['app'].extensionManager.workflow.syncWorkflows() + const app = window.app + if (!app) return + const extMgr = app.extensionManager as { + workflow?: { syncWorkflows: () => Promise } + } + if (extMgr.workflow) await extMgr.workflow.syncWorkflows() }) // Wait for Vue to re-render the workflow list @@ -360,7 +375,9 @@ export class ComfyPage { async executeCommand(commandId: string) { await this.page.evaluate((id: string) => { - return window['app'].extensionManager.command.execute(id) + const app = window.app + if (!app) return + return app.extensionManager.command.execute(id) }, commandId) } @@ -370,7 +387,8 @@ export class ComfyPage { ) { await this.page.evaluate( ({ commandId, commandStr }) => { - const app = window['app'] + const app = window.app + if (!app) return const randomSuffix = Math.random().toString(36).substring(2, 8) const extensionName = `TestExtension_${randomSuffix}` @@ -391,7 +409,8 @@ export class ComfyPage { async registerKeybinding(keyCombo: KeyCombo, command: () => void) { await this.page.evaluate( ({ keyCombo, commandStr }) => { - const app = window['app'] + const app = window.app + if (!app) return const randomSuffix = Math.random().toString(36).substring(2, 8) const extensionName = `TestExtension_${randomSuffix}` const commandId = `TestCommand_${randomSuffix}` @@ -419,7 +438,9 @@ export class ComfyPage { async setSetting(settingId: string, settingValue: any) { return await this.page.evaluate( async ({ id, value }) => { - await window['app'].extensionManager.setting.set(id, value) + const app = window.app + if (!app) return + await app.extensionManager.setting.set(id, value) }, { id: settingId, value: settingValue } ) @@ -427,7 +448,9 @@ export class ComfyPage { async getSetting(settingId: string) { return await this.page.evaluate(async (id) => { - return await window['app'].extensionManager.setting.get(id) + const app = window.app + if (!app) return undefined + return await app.extensionManager.setting.get(id) }, settingId) } @@ -873,8 +896,10 @@ export class ComfyPage { const foundSlot = await this.page.evaluate( async (params) => { const { slotType, action, targetSlotName } = params - const app = window['app'] + const app = window.app + if (!app) throw new Error('App not initialized') const currentGraph = app.canvas.graph + if (!currentGraph) throw new Error('No graph available') // Check if we're in a subgraph if (currentGraph.constructor.name !== 'Subgraph') { @@ -883,13 +908,24 @@ export class ComfyPage { ) } - // Get the appropriate node and slots + // Get the appropriate node and slots (these are Subgraph-specific properties) + const subgraph = currentGraph as { + inputNode?: { onPointerDown?: (...args: unknown[]) => void } + outputNode?: { onPointerDown?: (...args: unknown[]) => void } + inputs?: Array<{ + name: string + pos?: number[] + boundingRect?: number[] + }> + outputs?: Array<{ + name: string + pos?: number[] + boundingRect?: number[] + }> + } const node = - slotType === 'input' - ? currentGraph.inputNode - : currentGraph.outputNode - const slots = - slotType === 'input' ? currentGraph.inputs : currentGraph.outputs + slotType === 'input' ? subgraph.inputNode : subgraph.outputNode + const slots = slotType === 'input' ? subgraph.inputs : subgraph.outputs if (!node) { throw new Error(`No ${slotType} node found in subgraph`) @@ -970,6 +1006,7 @@ export class ComfyPage { } if (node.onPointerDown) { + // Call onPointerDown for test simulation node.onPointerDown( event, app.canvas.pointer, @@ -977,8 +1014,11 @@ export class ComfyPage { ) // Trigger double-click - if (app.canvas.pointer.onDoubleClick) { - app.canvas.pointer.onDoubleClick(event) + const onDoubleClick = app.canvas.pointer.onDoubleClick as + | ((e: unknown) => void) + | undefined + if (onDoubleClick) { + onDoubleClick(event) } } @@ -1574,7 +1614,9 @@ export class ComfyPage { async convertOffsetToCanvas(pos: [number, number]) { return this.page.evaluate((pos) => { - return window['app'].canvas.ds.convertOffsetToCanvas(pos) + const app = window.app + if (!app) return pos + return app.canvas.ds.convertOffsetToCanvas(pos) }, pos) } @@ -1588,14 +1630,18 @@ export class ComfyPage { } async getNodes(): Promise { return await this.page.evaluate(() => { - return window['app'].graph.nodes + const app = window.app + if (!app?.graph?.nodes) return [] + return app.graph.nodes }) } async getNodeRefsByType(type: string): Promise { return Promise.all( ( await this.page.evaluate((type) => { - return window['app'].graph.nodes + const app = window.app + if (!app?.graph?.nodes) return [] + return app.graph.nodes .filter((n: LGraphNode) => n.type === type) .map((n: LGraphNode) => n.id) }, type) @@ -1606,7 +1652,9 @@ export class ComfyPage { return Promise.all( ( await this.page.evaluate((title) => { - return window['app'].graph.nodes + const app = window.app + if (!app?.graph?.nodes) return [] + return app.graph.nodes .filter((n: LGraphNode) => n.title === title) .map((n: LGraphNode) => n.id) }, title) @@ -1616,7 +1664,9 @@ export class ComfyPage { async getFirstNodeRef(): Promise { const id = await this.page.evaluate(() => { - return window['app'].graph.nodes[0]?.id + const app = window.app + if (!app?.graph?.nodes) return undefined + return app.graph.nodes[0]?.id }) if (!id) return null return this.getNodeRefById(id) @@ -1626,32 +1676,41 @@ export class ComfyPage { } async getUndoQueueSize() { return this.page.evaluate(() => { - const workflow = (window['app'].extensionManager as WorkspaceStore) - .workflow.activeWorkflow - return workflow?.changeTracker.undoQueue.length + const app = window.app + if (!app) return 0 + const extMgr = app.extensionManager as WorkspaceStore + return extMgr.workflow.activeWorkflow?.changeTracker.undoQueue.length ?? 0 }) } async getRedoQueueSize() { return this.page.evaluate(() => { - const workflow = (window['app'].extensionManager as WorkspaceStore) - .workflow.activeWorkflow - return workflow?.changeTracker.redoQueue.length + const app = window.app + if (!app) return 0 + const extMgr = app.extensionManager as WorkspaceStore + return extMgr.workflow.activeWorkflow?.changeTracker.redoQueue.length ?? 0 }) } async isCurrentWorkflowModified() { return this.page.evaluate(() => { - return (window['app'].extensionManager as WorkspaceStore).workflow - .activeWorkflow?.isModified + const app = window.app + if (!app) return false + const extMgr = app.extensionManager as WorkspaceStore + return extMgr.workflow.activeWorkflow?.isModified ?? false }) } async getExportedWorkflow({ api = false }: { api?: boolean } = {}) { return this.page.evaluate(async (api) => { - return (await window['app'].graphToPrompt())[api ? 'output' : 'workflow'] + const app = window.app + if (!app) return undefined + return (await app.graphToPrompt())[api ? 'output' : 'workflow'] }, api) } async setFocusMode(focusMode: boolean) { await this.page.evaluate((focusMode) => { - window['app'].extensionManager.focusMode = focusMode + const app = window.app + if (!app) return + const extMgr = app.extensionManager as { focusMode?: boolean } + extMgr.focusMode = focusMode }, focusMode) await this.nextFrame() } @@ -1664,7 +1723,9 @@ export class ComfyPage { */ async getGroupPosition(title: string): Promise { const pos = await this.page.evaluate((title) => { - const groups = window['app'].graph.groups + const app = window.app + if (!app?.graph?.groups) return null + const groups = 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] } @@ -1686,7 +1747,8 @@ export class ComfyPage { }): Promise { const { name, deltaX, deltaY } = options const screenPos = await this.page.evaluate((title) => { - const app = window['app'] + const app = window.app + if (!app?.graph?.groups) return null const groups = app.graph.groups const group = groups.find((g: { title: string }) => g.title === title) if (!group) return null @@ -1754,11 +1816,16 @@ export const comfyPageFixture = base.extend<{ } }) +interface MatcherContext { + isNot: boolean +} + const makeMatcher = function ( getValue: (node: NodeReference) => Promise | T, type: string ) { return async function ( + this: MatcherContext, node: NodeReference, options?: { timeout?: number; intervals?: number[] } ) { @@ -1784,7 +1851,11 @@ export const comfyExpect = expect.extend({ toBePinned: makeMatcher((n) => n.isPinned(), 'pinned'), toBeBypassed: makeMatcher((n) => n.isBypassed(), 'bypassed'), toBeCollapsed: makeMatcher((n) => n.isCollapsed(), 'collapsed'), - async toHaveFocus(locator: Locator, options = { timeout: 256 }) { + async toHaveFocus( + this: MatcherContext, + locator: Locator, + options = { timeout: 256 } + ) { const isFocused = await locator.evaluate( (el) => el === document.activeElement ) diff --git a/browser_tests/fixtures/components/SidebarTab.ts b/browser_tests/fixtures/components/SidebarTab.ts index 3254e27c8..182315911 100644 --- a/browser_tests/fixtures/components/SidebarTab.ts +++ b/browser_tests/fixtures/components/SidebarTab.ts @@ -31,7 +31,7 @@ class SidebarTab { } export class NodeLibrarySidebarTab extends SidebarTab { - constructor(public readonly page: Page) { + constructor(public override readonly page: Page) { super(page, 'node-library') } @@ -55,12 +55,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 } @@ -87,7 +87,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') } @@ -140,7 +140,14 @@ export class WorkflowsSidebarTab extends SidebarTab { // Wait for workflow service to finish renaming await this.page.waitForFunction( - () => !window['app']?.extensionManager?.workflow?.isBusy, + () => { + const app = window.app + if (!app) return true + const extMgr = app.extensionManager as { + workflow?: { isBusy?: boolean } + } + return !extMgr.workflow?.isBusy + }, undefined, { timeout: 3000 } ) diff --git a/browser_tests/fixtures/components/Topbar.ts b/browser_tests/fixtures/components/Topbar.ts index c5e7c8155..d809c4292 100644 --- a/browser_tests/fixtures/components/Topbar.ts +++ b/browser_tests/fixtures/components/Topbar.ts @@ -86,7 +86,14 @@ export class Topbar { // Wait for workflow service to finish saving await this.page.waitForFunction( - () => !window['app'].extensionManager.workflow.isBusy, + () => { + const app = window.app + if (!app) return true + const extMgr = app.extensionManager as { + workflow?: { isBusy?: boolean } + } + return !extMgr.workflow?.isBusy + }, undefined, { timeout: 3000 } ) diff --git a/browser_tests/fixtures/utils/litegraphUtils.ts b/browser_tests/fixtures/utils/litegraphUtils.ts index 832db6324..72f4cc165 100644 --- a/browser_tests/fixtures/utils/litegraphUtils.ts +++ b/browser_tests/fixtures/utils/litegraphUtils.ts @@ -22,7 +22,10 @@ export class SubgraphSlotReference { async getPosition(): Promise { const pos: [number, number] = await this.comfyPage.page.evaluate( ([type, slotName]) => { - const currentGraph = window['app'].canvas.graph + const app = window.app + if (!app) throw new Error('App not initialized') + const currentGraph = app.canvas.graph + if (!currentGraph) throw new Error('No graph available') // Check if we're in a subgraph if (currentGraph.constructor.name !== 'Subgraph') { @@ -31,15 +34,18 @@ export class SubgraphSlotReference { ) } - const slots = - type === 'input' ? currentGraph.inputs : currentGraph.outputs + const subgraph = currentGraph as { + inputs?: Array<{ name: string; pos?: number[] }> + outputs?: Array<{ name: string; pos?: number[] }> + } + const slots = type === 'input' ? subgraph.inputs : subgraph.outputs if (!slots || slots.length === 0) { throw new Error(`No ${type} slots found in subgraph`) } // Find the specific slot or use the first one if no name specified const slot = slotName - ? slots.find((s) => s.name === slotName) + ? slots.find((s: { name: string }) => s.name === slotName) : slots[0] if (!slot) { @@ -51,7 +57,7 @@ export class SubgraphSlotReference { } // Convert from offset to canvas coordinates - const canvasPos = window['app'].canvas.ds.convertOffsetToCanvas([ + const canvasPos = app.canvas.ds.convertOffsetToCanvas([ slot.pos[0], slot.pos[1] ]) @@ -69,7 +75,10 @@ export class SubgraphSlotReference { async getOpenSlotPosition(): Promise { const pos: [number, number] = await this.comfyPage.page.evaluate( ([type]) => { - const currentGraph = window['app'].canvas.graph + const app = window.app + if (!app) throw new Error('App not initialized') + const currentGraph = app.canvas.graph + if (!currentGraph) throw new Error('No graph available') if (currentGraph.constructor.name !== 'Subgraph') { throw new Error( @@ -77,35 +86,35 @@ export class SubgraphSlotReference { ) } - const node = - type === 'input' ? currentGraph.inputNode : currentGraph.outputNode - const slots = - type === 'input' ? currentGraph.inputs : currentGraph.outputs + const subgraph = currentGraph as { + inputNode?: { pos: number[]; size: number[] } + outputNode?: { pos: number[]; size: number[] } + inputs?: Array<{ pos?: number[] }> + outputs?: Array<{ pos?: number[] }> + slotAnchorX?: number + } + const node = type === 'input' ? subgraph.inputNode : subgraph.outputNode + const slots = type === 'input' ? subgraph.inputs : subgraph.outputs if (!node) { throw new Error(`No ${type} node found in subgraph`) } - // Calculate position for next available slot - // const nextSlotIndex = slots?.length || 0 - // const slotHeight = 20 - // const slotY = node.pos[1] + 30 + nextSlotIndex * slotHeight - // Find last slot position - const lastSlot = slots.at(-1) + const lastSlot = slots?.at(-1) let slotX: number let slotY: number - if (lastSlot) { + if (lastSlot?.pos) { // If there are existing slots, position the new one below the last one const gapHeight = 20 slotX = lastSlot.pos[0] slotY = lastSlot.pos[1] + gapHeight } else { // No existing slots - use slotAnchorX if available, otherwise calculate from node position - if (currentGraph.slotAnchorX !== undefined) { + if (subgraph.slotAnchorX !== undefined) { // The actual slot X position seems to be slotAnchorX - 10 - slotX = currentGraph.slotAnchorX - 10 + slotX = subgraph.slotAnchorX - 10 } else { // Fallback: calculate from node edge slotX = @@ -118,10 +127,7 @@ export class SubgraphSlotReference { } // Convert from offset to canvas coordinates - const canvasPos = window['app'].canvas.ds.convertOffsetToCanvas([ - slotX, - slotY - ]) + const canvasPos = app.canvas.ds.convertOffsetToCanvas([slotX, slotY]) return canvasPos }, [this.type] as const @@ -143,16 +149,18 @@ class NodeSlotReference { async getPosition() { const pos: [number, number] = await this.node.comfyPage.page.evaluate( ([type, id, index]) => { + const app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const graph = app.canvas.graph // 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 = 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 = app.canvas.ds.convertOffsetToCanvas(rawPos) // Debug logging - convert Float64Arrays to regular arrays for visibility - // eslint-disable-next-line no-console + console.log( `NodeSlotReference debug for ${type} slot ${index} on node ${id}:`, { @@ -160,7 +168,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: graph.constructor.name } ) @@ -176,7 +184,9 @@ class NodeSlotReference { async getLinkCount() { return await this.node.comfyPage.page.evaluate( ([type, id, index]) => { - const node = window['app'].canvas.graph.getNodeById(id) + const app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const node = 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 @@ -189,7 +199,9 @@ class NodeSlotReference { async removeLinks() { await this.node.comfyPage.page.evaluate( ([type, id, index]) => { - const node = window['app'].canvas.graph.getNodeById(id) + const app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const node = app.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) if (type === 'input') { node.disconnectInput(index) @@ -214,15 +226,19 @@ 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 app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const node = app.canvas.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) + if (!node.widgets) throw new Error(`Node ${id} has no widgets.`) 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] = node.getBounding() + const titleHeight = window.LiteGraph?.NODE_TITLE_HEIGHT ?? 20 + return app.canvasPosToClientPos([ x + w / 2, - y + window['LiteGraph']['NODE_TITLE_HEIGHT'] + widget.last_y + 1 + y + titleHeight + (widget.last_y ?? 0) + 1 ]) }, [this.node.id, this.index] as const @@ -239,8 +255,11 @@ 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 app = window.app + if (!app?.graph) throw new Error('App not initialized') + const node = app.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) + if (!node.widgets) throw new Error(`Node ${id} has no widgets.`) const widget = node.widgets[index] if (!widget) throw new Error(`Widget ${index} not found.`) @@ -248,11 +267,13 @@ class NodeWidgetReference { (slot) => slot.widget?.name === widget.name ) if (!slot) throw new Error(`Socket ${widget.name} not found.`) + if (!slot.pos) throw new Error(`Socket ${widget.name} has no position.`) const [x, y] = node.getBounding() - return window['app'].canvasPosToClientPos([ + const titleHeight = window.LiteGraph?.NODE_TITLE_HEIGHT ?? 20 + return app.canvasPosToClientPos([ x + slot.pos[0], - y + slot.pos[1] + window['LiteGraph']['NODE_TITLE_HEIGHT'] + y + slot.pos[1] + titleHeight ]) }, [this.node.id, this.index] as const @@ -288,8 +309,11 @@ class NodeWidgetReference { async getValue() { return await this.node.comfyPage.page.evaluate( ([id, index]) => { - const node = window['app'].graph.getNodeById(id) + const app = window.app + if (!app?.graph) throw new Error('App not initialized') + const node = app.graph.getNodeById(id) if (!node) throw new Error(`Node ${id} not found.`) + if (!node.widgets) throw new Error(`Node ${id} has no widgets.`) const widget = node.widgets[index] if (!widget) throw new Error(`Widget ${index} not found.`) return widget.value @@ -305,7 +329,9 @@ export class NodeReference { ) {} async exists(): Promise { return await this.comfyPage.page.evaluate((id) => { - const node = window['app'].canvas.graph.getNodeById(id) + const app = window.app + if (!app?.canvas?.graph) return false + const node = app.canvas.graph.getNodeById(id) return !!node }, this.id) } @@ -322,17 +348,19 @@ 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) - if (!node) throw new Error('Node not found') - return node.getBounding() - }, this.id) + const bounding = await this.comfyPage.page.evaluate((id) => { + const app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const node = app.canvas.graph.getNodeById(id) + if (!node) throw new Error('Node not found') + const b = node.getBounding() + return [b[0], b[1], b[2], b[3]] as [number, number, number, number] + }, this.id) return { - x, - y, - width, - height + x: bounding[0], + y: bounding[1], + width: bounding[2], + height: bounding[3] } } async getSize(): Promise { @@ -355,14 +383,16 @@ export class NodeReference { return (await this.getProperty('mode')) === 4 } async getProperty(prop: string): Promise { - return await this.comfyPage.page.evaluate( + return (await this.comfyPage.page.evaluate( ([id, prop]) => { - const node = window['app'].canvas.graph.getNodeById(id) + const app = window.app + if (!app?.canvas?.graph) throw new Error('App not initialized') + const node = app.canvas.graph.getNodeById(id) if (!node) throw new Error('Node not found') - return node[prop] + return (node as unknown as Record)[prop] }, [this.id, prop] as const - ) + )) as T } async getOutput(index: number) { return new NodeSlotReference('output', index, this) @@ -480,7 +510,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 ?? 20 }) const nodePos = await this.getPosition() const nodeSize = await this.getSize() @@ -513,7 +543,9 @@ export class NodeReference { // Check if we successfully entered the subgraph isInSubgraph = await this.comfyPage.page.evaluate(() => { - const graph = window['app'].canvas.graph + const app = window.app + if (!app) return false + const graph = app.canvas.graph return graph?.constructor?.name === 'Subgraph' }) diff --git a/browser_tests/fixtures/utils/taskHistory.ts b/browser_tests/fixtures/utils/taskHistory.ts index 01dfb1a4a..8476d9fc3 100644 --- a/browser_tests/fixtures/utils/taskHistory.ts +++ b/browser_tests/fixtures/utils/taskHistory.ts @@ -120,15 +120,23 @@ export default class TaskHistory { filenames: string[], filetype: OutputFileType ): TaskOutput { - return filenames.reduce((outputs, filename, i) => { - const nodeId = `${i + 1}` - outputs[nodeId] = { - [filetype]: [{ filename, subfolder: '', type: 'output' }] - } - const contentType = getContentType(filename, filetype) - this.outputContentTypes.set(filename, contentType) - return outputs - }, {}) + return filenames.reduce( + (outputs, filename, i) => { + const nodeId = `${i + 1}` + outputs[nodeId] = { + [filetype]: [{ filename, subfolder: '', type: 'output' }] + } + const contentType = getContentType(filename, filetype) + this.outputContentTypes.set(filename, contentType) + return outputs + }, + {} as Record< + string, + { + [key: string]: { filename: string; subfolder: string; type: string }[] + } + > + ) } private addTask(task: HistoryTaskItem) {