refactor(browser_tests): remove deprecated proxy methods from ComfyPage

Migrate all test callers to use helper classes directly:

- nodeOps: getGraphNodesCount, getNodeRefById, selectNodes, etc.

- canvasOps: dragAndDrop, zoom, pan, resetView, etc.

- subgraph: rightClickInputSlot, connectToOutput, etc.

Reduces ComfyPage.ts from 1335 to 1085 lines (-250 lines).

Amp-Thread-ID: https://ampcode.com/threads/T-019c1318-58b7-757f-801c-5b676f0d3421
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-01-31 00:52:33 -08:00
parent 2c7dad3088
commit 681709f8e7
40 changed files with 404 additions and 533 deletions

View File

@@ -3,8 +3,6 @@ import { test as base, expect } from '@playwright/test'
import dotenv from 'dotenv'
import * as fs from 'fs'
import type { LGraphNode } from '../../src/lib/litegraph/src/litegraph'
import type { NodeId } from '../../src/platform/workflow/validation/schemas/workflowSchema'
import type { KeyCombo } from '../../src/platform/keybindings'
import type { useWorkspaceStore } from '../../src/stores/workspaceStore'
import { NodeBadgeMode } from '../../src/types/nodeSource'
@@ -24,9 +22,10 @@ import { CanvasHelper } from './helpers/CanvasHelper'
import { DebugHelper } from './helpers/DebugHelper'
import { NodeOperationsHelper } from './helpers/NodeOperationsHelper'
import { SubgraphHelper } from './helpers/SubgraphHelper'
import type { Position, Size } from './types'
import type { SubgraphSlotReference } from './utils/litegraphUtils'
import type { NodeReference } from './utils/litegraphUtils'
import type { Position } from './types'
import type {
NodeReference
} from './utils/litegraphUtils'
dotenv.config()
@@ -233,16 +232,6 @@ export class ComfyPage {
return result
}
/** @deprecated Use this.nodeOps.getGraphNodesCount() instead */
async getGraphNodesCount(): Promise<number> {
return this.nodeOps.getGraphNodesCount()
}
/** @deprecated Use this.nodeOps.getSelectedGraphNodesCount() instead */
async getSelectedGraphNodesCount(): Promise<number> {
return this.nodeOps.getSelectedGraphNodesCount()
}
async setupWorkflowsDirectory(structure: FolderStructure) {
const resp = await this.request.post(
`${this.url}/api/devtools/setup_folder_structure`,
@@ -502,11 +491,6 @@ export class ComfyPage {
})
}
/** @deprecated Use this.canvasOps.resetView() instead */
async resetView() {
return this.canvasOps.resetView()
}
async getToastErrorCount() {
return await this.page
.locator('.p-toast-message.p-toast-message-error')
@@ -564,11 +548,6 @@ export class ComfyPage {
return this.canvasOps.clickEmptySpace(DefaultGraphPositions.emptySpaceClick)
}
/** @deprecated Use this.canvasOps.dragAndDrop() instead */
async dragAndDrop(source: Position, target: Position) {
return this.canvasOps.dragAndDrop(source, target)
}
async dragAndDropExternalResource(
options: {
fileName?: string
@@ -713,7 +692,7 @@ export class ComfyPage {
}
async dragNode2() {
await this.dragAndDrop({ x: 622, y: 400 }, { x: 622, y: 300 })
await this.canvasOps.dragAndDrop({ x: 622, y: 400 }, { x: 622, y: 300 })
await this.nextFrame()
}
@@ -751,7 +730,10 @@ export class ComfyPage {
}
async disconnectEdge() {
await this.dragAndDrop(this.clipTextEncodeNode1InputSlot, this.emptySpace)
await this.canvasOps.dragAndDrop(
this.clipTextEncodeNode1InputSlot,
this.emptySpace
)
}
async connectEdge(
@@ -767,7 +749,7 @@ export class ComfyPage {
? this.loadCheckpointNodeClipOutputSlot
: this.clipTextEncodeNode1InputSlot
await this.dragAndDrop(start, end)
await this.canvasOps.dragAndDrop(start, end)
}
async adjustWidgetValue() {
@@ -783,26 +765,6 @@ export class ComfyPage {
await this.nextFrame()
}
/** @deprecated Use this.canvasOps.zoom() instead */
async zoom(deltaY: number, steps: number = 1) {
return this.canvasOps.zoom(deltaY, steps)
}
/** @deprecated Use this.canvasOps.pan() instead */
async pan(offset: Position, safeSpot?: Position) {
return this.canvasOps.pan(offset, safeSpot)
}
/** @deprecated Use this.canvasOps.panWithTouch() instead */
async panWithTouch(offset: Position, safeSpot?: Position) {
return this.canvasOps.panWithTouch(offset, safeSpot)
}
/** @deprecated Use this.canvasOps.rightClick() instead */
async rightClickCanvas(x: number = 10, y: number = 10) {
return this.canvasOps.rightClick(x, y)
}
async clickContextMenuItem(name: string): Promise<void> {
await this.page.getByRole('menuitem', { name }).click()
await this.nextFrame()
@@ -817,143 +779,6 @@ export class ComfyPage {
await this.nextFrame()
}
/** @deprecated Use this.subgraph.rightClickInputSlot() instead */
async rightClickSubgraphInputSlot(inputName?: string): Promise<void> {
return this.subgraph.rightClickInputSlot(inputName)
}
/** @deprecated Use this.subgraph.rightClickOutputSlot() instead */
async rightClickSubgraphOutputSlot(outputName?: string): Promise<void> {
return this.subgraph.rightClickOutputSlot(outputName)
}
/** @deprecated Use this.subgraph.doubleClickInputSlot() instead */
async doubleClickSubgraphInputSlot(inputName?: string): Promise<void> {
return this.subgraph.doubleClickInputSlot(inputName)
}
/** @deprecated Use this.subgraph.doubleClickOutputSlot() instead */
async doubleClickSubgraphOutputSlot(outputName?: string): Promise<void> {
return this.subgraph.doubleClickOutputSlot(outputName)
}
/** @deprecated Use this.subgraph.getInputSlot() instead */
async getSubgraphInputSlot(
slotName?: string
): Promise<SubgraphSlotReference> {
return this.subgraph.getInputSlot(slotName)
}
/** @deprecated Use this.subgraph.getOutputSlot() instead */
async getSubgraphOutputSlot(
slotName?: string
): Promise<SubgraphSlotReference> {
return this.subgraph.getOutputSlot(slotName)
}
/** @deprecated Use this.subgraph.connectToInput() instead */
async connectToSubgraphInput(
sourceNode: NodeReference,
sourceSlotIndex: number,
targetInputName?: string
): Promise<void> {
return this.subgraph.connectToInput(
sourceNode,
sourceSlotIndex,
targetInputName
)
}
/** @deprecated Use this.subgraph.connectFromInput() instead */
async connectFromSubgraphInput(
targetNode: NodeReference,
targetSlotIndex: number,
sourceInputName?: string
): Promise<void> {
return this.subgraph.connectFromInput(
targetNode,
targetSlotIndex,
sourceInputName
)
}
/** @deprecated Use this.subgraph.connectToOutput() instead */
async connectToSubgraphOutput(
sourceNode: NodeReference,
sourceSlotIndex: number,
targetOutputName?: string
): Promise<void> {
return this.subgraph.connectToOutput(
sourceNode,
sourceSlotIndex,
targetOutputName
)
}
/** @deprecated Use this.subgraph.connectFromOutput() instead */
async connectFromSubgraphOutput(
targetNode: NodeReference,
targetSlotIndex: number,
sourceOutputName?: string
): Promise<void> {
return this.subgraph.connectFromOutput(
targetNode,
targetSlotIndex,
sourceOutputName
)
}
/** @deprecated Use this.debug.addMarker() instead */
async debugAddMarker(
position: Position,
id: string = 'debug-marker'
): Promise<void> {
return this.debug.addMarker(position, id)
}
/** @deprecated Use this.debug.removeMarkers() instead */
async debugRemoveMarkers(): Promise<void> {
return this.debug.removeMarkers()
}
/** @deprecated Use this.debug.attachScreenshot() instead */
async debugAttachScreenshot(
testInfo: any,
name: string,
options?: {
fullPage?: boolean
element?: 'canvas' | 'page'
markers?: Array<{ position: Position; id?: string }>
}
): Promise<void> {
return this.debug.attachScreenshot(testInfo, name, options)
}
/** @deprecated Use this.canvasOps.doubleClick() instead */
async doubleClickCanvas() {
return this.canvasOps.doubleClick()
}
/** @deprecated Use this.debug.saveCanvasScreenshot() instead */
async debugSaveCanvasScreenshot(filename: string): Promise<void> {
return this.debug.saveCanvasScreenshot(filename)
}
/** @deprecated Use this.debug.getCanvasDataURL() instead */
async debugGetCanvasDataURL(): Promise<string> {
return this.debug.getCanvasDataURL()
}
/** @deprecated Use this.debug.showCanvasOverlay() instead */
async debugShowCanvasOverlay(): Promise<void> {
return this.debug.showCanvasOverlay()
}
/** @deprecated Use this.debug.hideCanvasOverlay() instead */
async debugHideCanvasOverlay(): Promise<void> {
return this.debug.hideCanvasOverlay()
}
async clickEmptyLatentNode() {
await this.canvas.click({
position: {
@@ -977,16 +802,6 @@ export class ComfyPage {
await this.nextFrame()
}
/** @deprecated Use this.nodeOps.selectNodes() instead */
async selectNodes(nodeTitles: string[]) {
return this.nodeOps.selectNodes(nodeTitles)
}
/** @deprecated Use this.nodeOps.select2Nodes() instead */
async select2Nodes() {
return this.nodeOps.select2Nodes()
}
async ctrlSend(keyToPress: string, locator: Locator | null = this.canvas) {
const target = locator ?? this.page.keyboard
await target.press(`Control+${keyToPress}`)
@@ -1035,29 +850,12 @@ export class ComfyPage {
await this.page.locator('.p-dialog').waitFor({ state: 'hidden' })
}
/** @deprecated Use this.nodeOps.resizeNode() instead */
async resizeNode(
nodePos: Position,
nodeSize: Size,
ratioX: number,
ratioY: number,
revertAfter: boolean = false
) {
return this.nodeOps.resizeNode(
nodePos,
nodeSize,
ratioX,
ratioY,
revertAfter
)
}
async resizeKsamplerNode(
percentX: number,
percentY: number,
revertAfter: boolean = false
) {
return this.resizeNode(
return this.nodeOps.resizeNode(
DefaultGraphPositions.ksampler.pos,
DefaultGraphPositions.ksampler.size,
percentX,
@@ -1071,7 +869,7 @@ export class ComfyPage {
percentY: number,
revertAfter: boolean = false
) {
return this.resizeNode(
return this.nodeOps.resizeNode(
DefaultGraphPositions.loadCheckpoint.pos,
DefaultGraphPositions.loadCheckpoint.size,
percentX,
@@ -1085,7 +883,7 @@ export class ComfyPage {
percentY: number,
revertAfter: boolean = false
) {
return this.resizeNode(
return this.nodeOps.resizeNode(
DefaultGraphPositions.emptyLatent.pos,
DefaultGraphPositions.emptyLatent.size,
percentX,
@@ -1107,57 +905,11 @@ export class ComfyPage {
await modal.waitFor({ state: 'hidden' })
}
/** @deprecated Use this.nodeOps.convertAllNodesToGroupNode() instead */
async convertAllNodesToGroupNode(groupNodeName: string) {
return this.nodeOps.convertAllNodesToGroupNode(groupNodeName)
}
/** @deprecated Use this.canvasOps.convertOffsetToCanvas() instead */
async convertOffsetToCanvas(pos: [number, number]) {
return this.canvasOps.convertOffsetToCanvas(pos)
}
/** Get number of DOM widgets on the canvas. */
async getDOMWidgetCount() {
return await this.page.locator('.dom-widget').count()
}
/** @deprecated Use this.nodeOps.getNodeRefById() instead */
async getNodeRefById(id: NodeId) {
return this.nodeOps.getNodeRefById(id)
}
/** @deprecated Use this.nodeOps.getNodes() instead */
async getNodes(): Promise<LGraphNode[]> {
return this.nodeOps.getNodes()
}
/** @deprecated Use this.nodeOps.waitForGraphNodes() instead */
async waitForGraphNodes(count: number) {
return this.nodeOps.waitForGraphNodes(count)
}
/** @deprecated Use this.nodeOps.getNodeRefsByType() instead */
async getNodeRefsByType(
type: string,
includeSubgraph: boolean = false
): Promise<NodeReference[]> {
return this.nodeOps.getNodeRefsByType(type, includeSubgraph)
}
/** @deprecated Use this.nodeOps.getNodeRefsByTitle() instead */
async getNodeRefsByTitle(title: string): Promise<NodeReference[]> {
return this.nodeOps.getNodeRefsByTitle(title)
}
/** @deprecated Use this.nodeOps.getFirstNodeRef() instead */
async getFirstNodeRef(): Promise<NodeReference | null> {
return this.nodeOps.getFirstNodeRef()
}
/** @deprecated Use this.canvasOps.moveMouseToEmptyArea() instead */
async moveMouseToEmptyArea() {
return this.canvasOps.moveMouseToEmptyArea()
}
async getUndoQueueSize() {
return this.page.evaluate(() => {
const workflow = (window['app'].extensionManager as WorkspaceStore)
@@ -1233,7 +985,7 @@ export class ComfyPage {
}, name)
if (!screenPos) throw new Error(`Group "${name}" not found`)
await this.dragAndDrop(screenPos, {
await this.canvasOps.dragAndDrop(screenPos, {
x: screenPos.x + deltaX,
y: screenPos.y + deltaY
})

View File

@@ -280,7 +280,7 @@ export class NodeReference {
return this.getProperty('type')
}
async getPosition(): Promise<Position> {
const pos = await this.comfyPage.convertOffsetToCanvas(
const pos = await this.comfyPage.canvasOps.convertOffsetToCanvas(
await this.getProperty<[number, number]>('pos')
)
return {
@@ -370,7 +370,7 @@ export class NodeReference {
})
await this.comfyPage.nextFrame()
if (moveMouseToEmptyArea) {
await this.comfyPage.moveMouseToEmptyArea()
await this.comfyPage.canvasOps.moveMouseToEmptyArea()
}
}
async copy() {
@@ -418,7 +418,7 @@ export class NodeReference {
await this.clickContextMenuOption('Convert to Group Node')
await this.comfyPage.fillPromptDialog(groupNodeName)
await this.comfyPage.nextFrame()
const nodes = await this.comfyPage.getNodeRefsByType(
const nodes = await this.comfyPage.nodeOps.getNodeRefsByType(
`workflow>${groupNodeName}`
)
if (nodes.length !== 1) {
@@ -429,7 +429,8 @@ export class NodeReference {
async convertToSubgraph() {
await this.clickContextMenuOption('Convert to Subgraph')
await this.comfyPage.nextFrame()
const nodes = await this.comfyPage.getNodeRefsByTitle('New Subgraph')
const nodes =
await this.comfyPage.nodeOps.getNodeRefsByTitle('New Subgraph')
if (nodes.length !== 1) {
throw new Error(
`Did not find single subgraph node (found=${nodes.length})`

View File

@@ -37,7 +37,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => {
expect(await comfyPage.getUndoQueueSize()).toBe(0)
expect(await comfyPage.getRedoQueueSize()).toBe(0)
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
await node.click('title')
await node.click('collapse')
await expect(node).toBeCollapsed()
@@ -68,7 +68,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => {
test('Can group multiple change actions into a single transaction', async ({
comfyPage
}) => {
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
expect(node).toBeTruthy()
await expect(node).not.toBeCollapsed()
await expect(node).not.toBeBypassed()
@@ -113,7 +113,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => {
test('Can nest multiple change transactions without adding undo steps', async ({
comfyPage
}) => {
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
const bypassAndPin = async () => {
await beforeChange(comfyPage)
await comfyPage.ctrlB()
@@ -165,7 +165,7 @@ test.describe('Change Tracker', { tag: '@workflow' }, () => {
test('Ignores changes in workflow.ds', async ({ comfyPage }) => {
expect(await comfyPage.getUndoQueueSize()).toBe(0)
await comfyPage.pan({ x: 10, y: 10 })
await comfyPage.canvasOps.pan({ x: 10, y: 10 })
expect(await comfyPage.getUndoQueueSize()).toBe(0)
})
})

View File

@@ -273,7 +273,7 @@ test.describe(
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.ColorPalette', 'light')
await comfyPage.setSetting('Comfy.Node.Opacity', 0.3)
const node = await comfyPage.getFirstNodeRef()
const node = await comfyPage.nodeOps.getFirstNodeRef()
await node?.clickContextMenuOption('Colors')
})

View File

@@ -103,7 +103,7 @@ test.describe('Copy Paste', { tag: ['@screenshot', '@workflow'] }, () => {
test('Can undo paste multiple nodes as single action', async ({
comfyPage
}) => {
const initialCount = await comfyPage.getGraphNodesCount()
const initialCount = await comfyPage.nodeOps.getGraphNodesCount()
expect(initialCount).toBeGreaterThan(1)
await comfyPage.canvas.click()
await comfyPage.ctrlA()
@@ -111,11 +111,11 @@ test.describe('Copy Paste', { tag: ['@screenshot', '@workflow'] }, () => {
await comfyPage.ctrlC()
await comfyPage.ctrlV()
const pasteCount = await comfyPage.getGraphNodesCount()
const pasteCount = await comfyPage.nodeOps.getGraphNodesCount()
expect(pasteCount).toBe(initialCount * 2)
await comfyPage.ctrlZ()
const undoCount = await comfyPage.getGraphNodesCount()
const undoCount = await comfyPage.nodeOps.getGraphNodesCount()
expect(undoCount).toBe(initialCount)
})
})

View File

@@ -45,7 +45,7 @@ test('Does not report warning on undo/redo', async ({ comfyPage }) => {
await comfyPage.nextFrame()
// Make a change to the graph
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await comfyPage.searchBox.fillAndSelectFirstNode('KSampler')
// Undo and redo the change
@@ -362,7 +362,7 @@ test.describe('Signin dialog', () => {
test('Paste content to signin dialog should not paste node on canvas', async ({
comfyPage
}) => {
const nodeNum = (await comfyPage.getNodes()).length
const nodeNum = (await comfyPage.nodeOps.getNodes()).length
await comfyPage.clickEmptyLatentNode()
await comfyPage.ctrlC()
@@ -381,6 +381,6 @@ test.describe('Signin dialog', () => {
await input.press('Control+v')
await expect(input).toHaveValue('test_password')
expect(await comfyPage.getNodes()).toHaveLength(nodeNum)
expect(await comfyPage.nodeOps.getNodes()).toHaveLength(nodeNum)
})
})

View File

@@ -21,7 +21,7 @@ test.describe('DOM Widget', { tag: '@widget' }, () => {
await expect(firstMultiline).toBeVisible()
await expect(lastMultiline).toBeVisible()
const nodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const nodes = await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
for (const node of nodes) {
await node.click('collapse')
}

View File

@@ -33,9 +33,9 @@ test.describe(
() => {
test('Execute to selected output nodes', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('execution/partial_execution')
const input = await comfyPage.getNodeRefById(3)
const output1 = await comfyPage.getNodeRefById(1)
const output2 = await comfyPage.getNodeRefById(4)
const input = await comfyPage.nodeOps.getNodeRefById(3)
const output1 = await comfyPage.nodeOps.getNodeRefById(1)
const output2 = await comfyPage.nodeOps.getNodeRefById(4)
expect(await (await input.getWidget(0)).getValue()).toBe('foo')
expect(await (await output1.getWidget(0)).getValue()).toBe('')
expect(await (await output2.getWidget(0)).getValue()).toBe('')

View File

@@ -325,7 +325,7 @@ test.describe('Topbar commands', () => {
})
})
await comfyPage.selectNodes(['CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes(['CLIP Text Encode (Prompt)'])
// Click the command button in the selection toolbox
const toolboxButton = comfyPage.page.locator(

View File

@@ -18,7 +18,7 @@ test.describe('Group Node', { tag: '@node' }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
libraryTab = comfyPage.menu.nodeLibraryTab
await comfyPage.convertAllNodesToGroupNode(groupNodeName)
await comfyPage.nodeOps.convertAllNodesToGroupNode(groupNodeName)
await libraryTab.open()
})
@@ -29,14 +29,16 @@ test.describe('Group Node', { tag: '@node' }, () => {
test('Can be added to canvas using node library sidebar', async ({
comfyPage
}) => {
const initialNodeCount = await comfyPage.getGraphNodesCount()
const initialNodeCount = await comfyPage.nodeOps.getGraphNodesCount()
// Add group node from node library sidebar
await libraryTab.getFolder(groupNodeCategory).click()
await libraryTab.getNode(groupNodeName).click()
// Verify the node is added to the canvas
expect(await comfyPage.getGraphNodesCount()).toBe(initialNodeCount + 1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(
initialNodeCount + 1
)
})
test('Can be bookmarked and unbookmarked', async ({ comfyPage }) => {
@@ -94,8 +96,8 @@ test.describe('Group Node', { tag: '@node' }, () => {
{ tag: '@screenshot' },
async ({ comfyPage }) => {
const groupNodeName = 'DefautWorkflowGroupNode'
await comfyPage.convertAllNodesToGroupNode(groupNodeName)
await comfyPage.doubleClickCanvas()
await comfyPage.nodeOps.convertAllNodesToGroupNode(groupNodeName)
await comfyPage.canvasOps.doubleClick()
await comfyPage.nextFrame()
await comfyPage.searchBox.fillAndSelectFirstNode(groupNodeName)
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -106,7 +108,7 @@ test.describe('Group Node', { tag: '@node' }, () => {
test('Displays tooltip on title hover', async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.EnableTooltips', true)
await comfyPage.convertAllNodesToGroupNode('Group Node')
await comfyPage.nodeOps.convertAllNodesToGroupNode('Group Node')
await comfyPage.page.mouse.move(47, 173)
await expect(comfyPage.page.locator('.node-tooltip')).toBeVisible()
})
@@ -115,8 +117,8 @@ test.describe('Group Node', { tag: '@node' }, () => {
comfyPage
}) => {
const makeGroup = async (name, type1, type2) => {
const node1 = (await comfyPage.getNodeRefsByType(type1))[0]
const node2 = (await comfyPage.getNodeRefsByType(type2))[0]
const node1 = (await comfyPage.nodeOps.getNodeRefsByType(type1))[0]
const node2 = (await comfyPage.nodeOps.getNodeRefsByType(type2))[0]
await node1.click('title')
await node2.click('title', {
modifiers: ['Shift']
@@ -178,7 +180,7 @@ test.describe('Group Node', { tag: '@node' }, () => {
comfyPage
}) => {
const expectSingleNode = async (type: string) => {
const nodes = await comfyPage.getNodeRefsByType(type)
const nodes = await comfyPage.nodeOps.getNodeRefsByType(type)
expect(nodes).toHaveLength(1)
return nodes[0]
}
@@ -214,7 +216,7 @@ test.describe('Group Node', { tag: '@node' }, () => {
comfyPage
}) => {
await comfyPage.loadWorkflow('groupnodes/legacy_group_node')
expect(await comfyPage.getGraphNodesCount()).toBe(1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(1)
await expect(
comfyPage.page.locator('.comfy-missing-nodes')
).not.toBeVisible()
@@ -246,9 +248,9 @@ test.describe('Group Node', { tag: '@node' }, () => {
comfyPage: ComfyPage,
expectedCount: number
) => {
expect(await comfyPage.getNodeRefsByType(GROUP_NODE_TYPE)).toHaveLength(
expectedCount
)
expect(
await comfyPage.nodeOps.getNodeRefsByType(GROUP_NODE_TYPE)
).toHaveLength(expectedCount)
expect(await isRegisteredLitegraph(comfyPage)).toBe(true)
expect(await isRegisteredNodeDefStore(comfyPage)).toBe(true)
}
@@ -256,7 +258,7 @@ test.describe('Group Node', { tag: '@node' }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
await comfyPage.loadWorkflow(WORKFLOW_NAME)
groupNode = await comfyPage.getFirstNodeRef()
groupNode = await comfyPage.nodeOps.getFirstNodeRef()
if (!groupNode)
throw new Error(`Group node not found in workflow ${WORKFLOW_NAME}`)
await groupNode.copy()

View File

@@ -51,11 +51,13 @@ test.describe('Node Interaction', () => {
test(`Can add multiple nodes to selection using ${modifier}+Click`, async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNodes =
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
for (const node of clipNodes) {
await node.click('title', { modifiers: [modifier] })
}
const selectedNodeCount = await comfyPage.getSelectedGraphNodesCount()
const selectedNodeCount =
await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedNodeCount).toBe(clipNodes.length)
})
})
@@ -80,7 +82,7 @@ test.describe('Node Interaction', () => {
const clipNode2Pos = await clipNodes[1].getPosition()
const offset = 64
await comfyPage.page.keyboard.down('Meta')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{
x: Math.min(clipNode1Pos.x, clipNode2Pos.x) - offset,
y: Math.min(clipNode1Pos.y, clipNode2Pos.y) - offset
@@ -94,9 +96,10 @@ test.describe('Node Interaction', () => {
}
test('Can drag-select nodes with Meta (mac)', async ({ comfyPage }) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNodes =
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
await dragSelectNodes(comfyPage, clipNodes)
expect(await comfyPage.getSelectedGraphNodesCount()).toBe(
expect(await comfyPage.nodeOps.getSelectedGraphNodesCount()).toBe(
clipNodes.length
)
})
@@ -104,7 +107,8 @@ test.describe('Node Interaction', () => {
test('Can move selected nodes using the Comfy.Canvas.MoveSelectedNodes.{Up|Down|Left|Right} commands', async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNodes =
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
const getPositions = () =>
Promise.all(clipNodes.map((node) => node.getPosition()))
const testDirection = async ({
@@ -174,7 +178,7 @@ test.describe('Node Interaction', () => {
await expect(comfyPage.canvas).toHaveScreenshot('disconnected-edge.png')
await comfyPage.connectEdge({ reverse })
// Move mouse to empty area to avoid slot highlight.
await comfyPage.moveMouseToEmptyArea()
await comfyPage.canvasOps.moveMouseToEmptyArea()
// Litegraph renders edge with a slight offset.
await expect(comfyPage.canvas).toHaveScreenshot('default.png', {
maxDiffPixels: 50
@@ -183,12 +187,12 @@ test.describe('Node Interaction', () => {
})
test('Can move link', async ({ comfyPage }) => {
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
comfyPage.clipTextEncodeNode1InputSlot,
comfyPage.emptySpace
)
await expect(comfyPage.canvas).toHaveScreenshot('disconnected-edge.png')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
comfyPage.clipTextEncodeNode2InputSlot,
comfyPage.clipTextEncodeNode1InputSlot
)
@@ -199,13 +203,13 @@ test.describe('Node Interaction', () => {
test.skip('Can copy link by shift-drag existing link', async ({
comfyPage
}) => {
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
comfyPage.clipTextEncodeNode1InputSlot,
comfyPage.emptySpace
)
await expect(comfyPage.canvas).toHaveScreenshot('disconnected-edge.png')
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
comfyPage.clipTextEncodeNode2InputLinkPath,
comfyPage.clipTextEncodeNode1InputSlot
)
@@ -249,7 +253,7 @@ test.describe('Node Interaction', () => {
x: 748,
y: 77
}
await comfyPage.dragAndDrop(outputSlotPos, samplerNodeCenterPos)
await comfyPage.canvasOps.dragAndDrop(outputSlotPos, samplerNodeCenterPos)
await expect(comfyPage.canvas).toHaveScreenshot('snap_to_slot_linked.png')
})
@@ -271,7 +275,7 @@ test.describe('Node Interaction', () => {
}
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop(outputSlot1Pos, outputSlot2Pos)
await comfyPage.canvasOps.dragAndDrop(outputSlot1Pos, outputSlot2Pos)
await comfyPage.page.keyboard.up('Shift')
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -398,7 +402,7 @@ test.describe('Node Interaction', () => {
{ tag: '@screenshot' },
async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.GroupSelectedNodes.Padding', 10)
await comfyPage.select2Nodes()
await comfyPage.nodeOps.select2Nodes()
await comfyPage.page.keyboard.down('Control')
await comfyPage.page.keyboard.press('KeyG')
await comfyPage.page.keyboard.up('Control')
@@ -428,7 +432,7 @@ test.describe('Node Interaction', () => {
)
test('Can pin/unpin nodes', { tag: '@screenshot' }, async ({ comfyPage }) => {
await comfyPage.select2Nodes()
await comfyPage.nodeOps.select2Nodes()
await comfyPage.executeCommand('Comfy.Canvas.ToggleSelectedNodes.Pin')
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot('nodes-pinned.png')
@@ -441,7 +445,7 @@ test.describe('Node Interaction', () => {
'Can bypass/unbypass nodes with keyboard shortcut',
{ tag: '@screenshot' },
async ({ comfyPage }) => {
await comfyPage.select2Nodes()
await comfyPage.nodeOps.select2Nodes()
await comfyPage.canvas.press('Control+b')
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot('nodes-bypassed.png')
@@ -470,16 +474,16 @@ test.describe('Group Interaction', { tag: '@screenshot' }, () => {
test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
test('Can zoom in/out', async ({ comfyPage }) => {
await comfyPage.zoom(-100)
await comfyPage.canvasOps.zoom(-100)
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-in.png')
await comfyPage.zoom(200)
await comfyPage.canvasOps.zoom(200)
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-out.png')
})
test('Can zoom very far out', async ({ comfyPage }) => {
await comfyPage.zoom(100, 12)
await comfyPage.canvasOps.zoom(100, 12)
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-very-far-out.png')
await comfyPage.zoom(-100, 12)
await comfyPage.canvasOps.zoom(-100, 12)
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-back-in.png')
})
@@ -488,11 +492,11 @@ test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
}) => {
await comfyPage.page.keyboard.down('Control')
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop({ x: 10, y: 100 }, { x: 10, y: 40 })
await comfyPage.canvasOps.dragAndDrop({ x: 10, y: 100 }, { x: 10, y: 40 })
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-in-ctrl-shift.png')
await comfyPage.dragAndDrop({ x: 10, y: 40 }, { x: 10, y: 160 })
await comfyPage.canvasOps.dragAndDrop({ x: 10, y: 40 }, { x: 10, y: 160 })
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-out-ctrl-shift.png')
await comfyPage.dragAndDrop({ x: 10, y: 280 }, { x: 10, y: 220 })
await comfyPage.canvasOps.dragAndDrop({ x: 10, y: 280 }, { x: 10, y: 220 })
await expect(comfyPage.canvas).toHaveScreenshot(
'zoomed-default-ctrl-shift.png'
)
@@ -504,11 +508,11 @@ test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
comfyPage
}) => {
await comfyPage.setSetting('Comfy.Graph.ZoomSpeed', 1.05)
await comfyPage.zoom(-100, 4)
await comfyPage.canvasOps.zoom(-100, 4)
await expect(comfyPage.canvas).toHaveScreenshot(
'zoomed-in-low-zoom-speed.png'
)
await comfyPage.zoom(100, 8)
await comfyPage.canvasOps.zoom(100, 8)
await expect(comfyPage.canvas).toHaveScreenshot(
'zoomed-out-low-zoom-speed.png'
)
@@ -519,11 +523,11 @@ test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
comfyPage
}) => {
await comfyPage.setSetting('Comfy.Graph.ZoomSpeed', 1.5)
await comfyPage.zoom(-100, 4)
await comfyPage.canvasOps.zoom(-100, 4)
await expect(comfyPage.canvas).toHaveScreenshot(
'zoomed-in-high-zoom-speed.png'
)
await comfyPage.zoom(100, 8)
await comfyPage.canvasOps.zoom(100, 8)
await expect(comfyPage.canvas).toHaveScreenshot(
'zoomed-out-high-zoom-speed.png'
)
@@ -531,7 +535,7 @@ test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
})
test('Can pan', async ({ comfyPage }) => {
await comfyPage.pan({ x: 200, y: 200 })
await comfyPage.canvasOps.pan({ x: 200, y: 200 })
await expect(comfyPage.canvas).toHaveScreenshot('panned.png')
})
@@ -623,23 +627,23 @@ test.describe('Canvas Interaction', { tag: '@screenshot' }, () => {
test('Can pan very far and back', async ({ comfyPage }) => {
// intentionally slice the edge of where the clip text encode dom widgets are
await comfyPage.pan({ x: -800, y: -300 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: -800, y: -300 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-step-one.png')
await comfyPage.pan({ x: -200, y: 0 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: -200, y: 0 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-step-two.png')
await comfyPage.pan({ x: -2200, y: -2200 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: -2200, y: -2200 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-far-away.png')
await comfyPage.pan({ x: 2200, y: 2200 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: 2200, y: 2200 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-back-from-far.png')
await comfyPage.pan({ x: 200, y: 0 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: 200, y: 0 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-back-to-two.png')
await comfyPage.pan({ x: 800, y: 300 }, { x: 1000, y: 10 })
await comfyPage.canvasOps.pan({ x: 800, y: 300 }, { x: 1000, y: 10 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-back-to-one.png')
})
test('@mobile Can pan with touch', async ({ comfyPage }) => {
await comfyPage.closeMenu()
await comfyPage.panWithTouch({ x: 200, y: 200 })
await comfyPage.canvasOps.panWithTouch({ x: 200, y: 200 })
await expect(comfyPage.canvas).toHaveScreenshot('panned-touch.png')
})
})
@@ -696,7 +700,7 @@ test.describe('Load workflow', { tag: '@screenshot' }, () => {
comfyPage
}) => {
await comfyPage.loadWorkflow('nodes/single_ksampler')
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
await node.click('collapse')
await comfyPage.clickEmptySpace()
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -788,7 +792,7 @@ test.describe('Load duplicate workflow', () => {
await comfyPage.menu.workflowsTab.open()
await comfyPage.executeCommand('Comfy.NewBlankWorkflow')
await comfyPage.loadWorkflow('nodes/single_ksampler')
expect(await comfyPage.getGraphNodesCount()).toBe(1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(1)
})
})
@@ -871,7 +875,10 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
test('Left-click drag in empty area should pan canvas', async ({
comfyPage
}) => {
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await comfyPage.canvasOps.dragAndDrop(
{ x: 50, y: 50 },
{ x: 150, y: 150 }
)
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-left-drag-pan.png'
)
@@ -905,7 +912,7 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
test('Left-click on node should not pan canvas', async ({ comfyPage }) => {
await comfyPage.clickTextEncodeNode1()
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
const selectedCount = await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCount).toBe(1)
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-click-node-select.png'
@@ -921,12 +928,13 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
test('Left-click drag in empty area should select nodes', async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNodes =
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
const clipNode1Pos = await clipNodes[0].getPosition()
const clipNode2Pos = await clipNodes[1].getPosition()
const offset = 64
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{
x: Math.min(clipNode1Pos.x, clipNode2Pos.x) - offset,
y: Math.min(clipNode1Pos.y, clipNode2Pos.y) - offset
@@ -937,7 +945,7 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
}
)
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
const selectedCount = await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCount).toBe(clipNodes.length)
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-left-drag-select.png'
@@ -978,7 +986,7 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
comfyPage
}) => {
await comfyPage.clickTextEncodeNode1()
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
const selectedCount = await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCount).toBe(1)
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-click-node-select.png'
@@ -991,7 +999,10 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
await comfyPage.nextFrame()
await comfyPage.page.keyboard.down('Space')
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await comfyPage.canvasOps.dragAndDrop(
{ x: 50, y: 50 },
{ x: 150, y: 150 }
)
await comfyPage.page.keyboard.up('Space')
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-space-drag-pan.png'
@@ -1001,11 +1012,12 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
test('Space key overrides default left-click behavior', async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNodes =
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
const clipNode1Pos = await clipNodes[0].getPosition()
const offset = 64
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{
x: clipNode1Pos.x - offset,
y: clipNode1Pos.y - offset
@@ -1017,16 +1029,16 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
)
const selectedCountAfterDrag =
await comfyPage.getSelectedGraphNodesCount()
await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCountAfterDrag).toBeGreaterThan(0)
await comfyPage.clickEmptySpace()
const selectedCountAfterClear =
await comfyPage.getSelectedGraphNodesCount()
await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCountAfterClear).toBe(0)
await comfyPage.page.keyboard.down('Space')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{
x: clipNode1Pos.x - offset,
y: clipNode1Pos.y - offset
@@ -1039,7 +1051,7 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
await comfyPage.page.keyboard.up('Space')
const selectedCountAfterSpaceDrag =
await comfyPage.getSelectedGraphNodesCount()
await comfyPage.nodeOps.getSelectedGraphNodesCount()
expect(selectedCountAfterSpaceDrag).toBe(0)
})
})
@@ -1089,7 +1101,10 @@ test.describe('Canvas Navigation', { tag: '@screenshot' }, () => {
await comfyPage.page.keyboard.down('Alt')
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await comfyPage.canvasOps.dragAndDrop(
{ x: 50, y: 50 },
{ x: 150, y: 150 }
)
await comfyPage.page.keyboard.up('Shift')
await comfyPage.page.keyboard.up('Alt')

View File

@@ -29,7 +29,7 @@ test.describe('Canvas Event', { tag: '@canvas' }, () => {
test('Emit litegraph:canvas empty-double-click', async ({ comfyPage }) => {
const eventPromise = comfyPage.page.evaluate(listenForEvent)
const doubleClickPromise = comfyPage.doubleClickCanvas()
const doubleClickPromise = comfyPage.canvasOps.doubleClick()
const event = await eventPromise
await doubleClickPromise

View File

@@ -32,7 +32,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => {
// Can't access private _lowQualityZoomThreshold directly
// Zoom out just above threshold (should still be high quality)
await comfyPage.zoom(120, 5) // Zoom out 5 steps
await comfyPage.canvasOps.zoom(120, 5) // Zoom out 5 steps
await comfyPage.nextFrame()
const aboveThresholdState = await comfyPage.page.evaluate(() => {
@@ -49,7 +49,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => {
}
// Zoom out more to trigger LOD (below threshold)
await comfyPage.zoom(120, 5) // Zoom out 5 more steps
await comfyPage.canvasOps.zoom(120, 5) // Zoom out 5 more steps
await comfyPage.nextFrame()
// Check that LOD is now active
@@ -65,7 +65,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => {
expect(zoomedOutState.lowQuality).toBe(true)
// Zoom back in to disable LOD (above threshold)
await comfyPage.zoom(-120, 15) // Zoom in 15 steps
await comfyPage.canvasOps.zoom(-120, 15) // Zoom in 15 steps
await comfyPage.nextFrame()
// Check that LOD is now inactive
@@ -107,7 +107,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => {
expect(lodState).toBe(false)
// Zoom out slightly to trigger LOD
await comfyPage.zoom(120, 1) // Zoom out 1 step
await comfyPage.canvasOps.zoom(120, 1) // Zoom out 1 step
await comfyPage.nextFrame()
const afterZoom = await comfyPage.page.evaluate(() => {
@@ -131,7 +131,7 @@ test.describe('LOD Threshold', { tag: ['@screenshot', '@canvas'] }, () => {
await comfyPage.setSetting('LiteGraph.Canvas.MinFontSizeForLOD', 0)
// Zoom out significantly
await comfyPage.zoom(120, 20) // Zoom out 20 steps
await comfyPage.canvasOps.zoom(120, 20) // Zoom out 20 steps
await comfyPage.nextFrame()
// LOD should remain disabled even at very low zoom

View File

@@ -9,7 +9,7 @@ test.describe(
await comfyPage.setSetting('Comfy.ConfirmClear', false)
await comfyPage.executeCommand('Comfy.ClearWorkflow')
await expect(async () => {
expect(await comfyPage.getGraphNodesCount()).toBe(0)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(0)
}).toPass({ timeout: 256 })
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot('mobile-empty-canvas.png')

View File

@@ -77,7 +77,7 @@ test.describe(
await comfyPage.setSetting('Comfy.NodeBadge.NodeSourceBadgeMode', mode)
await comfyPage.setSetting('Comfy.NodeBadge.NodeIdBadgeMode', mode)
await comfyPage.nextFrame()
await comfyPage.resetView()
await comfyPage.canvasOps.resetView()
await expect(comfyPage.canvas).toHaveScreenshot(
`node-badge-${mode}.png`
)

View File

@@ -36,7 +36,7 @@ test.describe('Optional input', { tag: ['@screenshot', '@node'] }, () => {
test('Only optional inputs', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('inputs/only_optional_inputs')
expect(await comfyPage.getGraphNodesCount()).toBe(1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(1)
await expect(
comfyPage.page.locator('.comfy-missing-nodes')
).not.toBeVisible()
@@ -48,7 +48,7 @@ test.describe('Optional input', { tag: ['@screenshot', '@node'] }, () => {
})
test('Old workflow with converted input', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('inputs/old_workflow_converted_input')
const node = await comfyPage.getNodeRefById('1')
const node = await comfyPage.nodeOps.getNodeRefById('1')
const inputs = await node.getProperty('inputs')
const vaeInput = inputs.find((w) => w.name === 'vae')
const convertedInput = inputs.find((w) => w.name === 'strength')
@@ -60,7 +60,7 @@ test.describe('Optional input', { tag: ['@screenshot', '@node'] }, () => {
})
test('Renamed converted input', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('inputs/renamed_converted_widget')
const node = await comfyPage.getNodeRefById('3')
const node = await comfyPage.nodeOps.getNodeRefById('3')
const inputs = await node.getProperty('inputs')
const renamedInput = inputs.find((w) => w.name === 'breadth')
expect(renamedInput).toBeUndefined()

View File

@@ -36,7 +36,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
await comfyPage.loadWorkflow('default')
// Select a single node (KSampler) using node references
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
if (ksamplerNodes.length === 0) {
throw new Error('No KSampler nodes found in the workflow')
}
@@ -158,7 +159,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
// Load workflow and select a node
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
// Click help button
@@ -190,7 +192,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
// Load workflow and select a node
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
// Click help button
@@ -227,7 +230,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
})
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -277,7 +281,8 @@ test.describe('Node Help', { tag: ['@slow', '@ui'] }, () => {
})
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -350,7 +355,7 @@ This is documentation for a custom node.
return window['app']!.graph!.nodes.map((n) => n.id)
})
if (nodeRefs.length > 0) {
const firstNode = await comfyPage.getNodeRefById(nodeRefs[0])
const firstNode = await comfyPage.nodeOps.getNodeRefById(nodeRefs[0])
await selectNodeWithPan(comfyPage, firstNode)
}
@@ -394,7 +399,8 @@ This is documentation for a custom node.
})
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -463,7 +469,8 @@ This is English documentation.
await comfyPage.setSetting('Comfy.Locale', 'ja')
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -488,7 +495,8 @@ This is English documentation.
})
await comfyPage.loadWorkflow('default')
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -534,7 +542,8 @@ This is English documentation.
await fitToViewInstant(comfyPage)
// Select KSampler first
const ksamplerNodes = await comfyPage.getNodeRefsByType('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
await selectNodeWithPan(comfyPage, ksamplerNodes[0])
const helpButton = comfyPage.page.locator(
@@ -549,7 +558,7 @@ This is English documentation.
await expect(helpPage).toContainText('This is KSampler documentation')
// Now select Checkpoint Loader
const checkpointNodes = await comfyPage.getNodeRefsByType(
const checkpointNodes = await comfyPage.nodeOps.getNodeRefsByType(
'CheckpointLoaderSimple'
)
await selectNodeWithPan(comfyPage, checkpointNodes[0])

View File

@@ -15,7 +15,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
})
test(`Can trigger on empty canvas double click`, async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await expect(comfyPage.searchBox.input).toHaveCount(1)
})
@@ -47,7 +47,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
})
test('Can add node', { tag: '@screenshot' }, async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await expect(comfyPage.searchBox.input).toHaveCount(1)
await comfyPage.searchBox.fillAndSelectFirstNode('KSampler')
await expect(comfyPage.canvas).toHaveScreenshot('added-node.png')
@@ -77,7 +77,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
y: 5
}
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop(outputSlot1Pos, emptySpacePos)
await comfyPage.canvasOps.dragAndDrop(outputSlot1Pos, emptySpacePos)
await comfyPage.page.keyboard.up('Shift')
// Select the second item as the first item is always reroute
@@ -106,7 +106,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
test('Has correct aria-labels on search results', async ({ comfyPage }) => {
const node = 'Load Checkpoint'
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await comfyPage.searchBox.input.waitFor({ state: 'visible' })
await comfyPage.searchBox.input.fill(node)
await comfyPage.searchBox.dropdown.waitFor({ state: 'visible' })
@@ -149,7 +149,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
}
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
})
test('Can add filter', async ({ comfyPage }) => {
@@ -241,7 +241,7 @@ test.describe('Node search box', { tag: '@node' }, () => {
test.describe('Input focus behavior', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
})
test('focuses input after adding a filter', async ({ comfyPage }) => {

View File

@@ -17,8 +17,10 @@ test.describe('Primitive Node', { tag: ['@screenshot', '@node'] }, () => {
// to input.
test('Can connect to widget', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('primitive/primitive_node_unconnected')
const primitiveNode: NodeReference = await comfyPage.getNodeRefById(1)
const ksamplerNode: NodeReference = await comfyPage.getNodeRefById(2)
const primitiveNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(1)
const ksamplerNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(2)
// Connect the output of the primitive node to the input of first widget of the ksampler node
await primitiveNode.connectWidget(0, ksamplerNode, 0)
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -30,8 +32,10 @@ test.describe('Primitive Node', { tag: ['@screenshot', '@node'] }, () => {
await comfyPage.loadWorkflow(
'primitive/primitive_node_unconnected_dom_widget'
)
const primitiveNode: NodeReference = await comfyPage.getNodeRefById(1)
const clipEncoderNode: NodeReference = await comfyPage.getNodeRefById(2)
const primitiveNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(1)
const clipEncoderNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(2)
await primitiveNode.connectWidget(0, clipEncoderNode, 0)
await expect(comfyPage.canvas).toHaveScreenshot(
'primitive_node_connected_dom_widget.png'
@@ -40,8 +44,10 @@ test.describe('Primitive Node', { tag: ['@screenshot', '@node'] }, () => {
test('Can connect to static primitive node', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('primitive/static_primitive_unconnected')
const primitiveNode: NodeReference = await comfyPage.getNodeRefById(1)
const ksamplerNode: NodeReference = await comfyPage.getNodeRefById(2)
const primitiveNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(1)
const ksamplerNode: NodeReference =
await comfyPage.nodeOps.getNodeRefById(2)
await primitiveNode.connectWidget(0, ksamplerNode, 0)
await expect(comfyPage.canvas).toHaveScreenshot(
'static_primitive_connected.png'

View File

@@ -10,7 +10,10 @@ test.describe('Properties panel', () => {
await expect(propertiesPanel.panelTitle).toContainText('Workflow Overview')
await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes([
'KSampler',
'CLIP Text Encode (Prompt)'
])
await expect(propertiesPanel.panelTitle).toContainText('3 items selected')
await expect(propertiesPanel.root.getByText('KSampler')).toHaveCount(1)

View File

@@ -11,7 +11,7 @@ test.describe('Record Audio Node', { tag: '@screenshot' }, () => {
comfyPage
}) => {
// Open the search box by double clicking on the canvas
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await expect(comfyPage.searchBox.input).toHaveCount(1)
// Search for and add the RecordAudio node
@@ -19,7 +19,8 @@ test.describe('Record Audio Node', { tag: '@screenshot' }, () => {
await comfyPage.nextFrame()
// Verify the RecordAudio node was added
const recordAudioNodes = await comfyPage.getNodeRefsByType('RecordAudio')
const recordAudioNodes =
await comfyPage.nodeOps.getNodeRefsByType('RecordAudio')
expect(recordAudioNodes.length).toBe(1)
// Take a screenshot of the canvas with the RecordAudio node

View File

@@ -56,10 +56,10 @@ test.describe(
comfyPage
}) => {
const loadCheckpointNode = (
await comfyPage.getNodeRefsByTitle('Load Checkpoint')
await comfyPage.nodeOps.getNodeRefsByTitle('Load Checkpoint')
)[0]
const clipEncodeNode = (
await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)')
await comfyPage.nodeOps.getNodeRefsByTitle('CLIP Text Encode (Prompt)')
)[0]
const slot1 = await loadCheckpointNode.getOutput(1)
@@ -82,10 +82,10 @@ test.describe(
comfyPage
}) => {
const loadCheckpointNode = (
await comfyPage.getNodeRefsByTitle('Load Checkpoint')
await comfyPage.nodeOps.getNodeRefsByTitle('Load Checkpoint')
)[0]
const clipEncodeNode = (
await comfyPage.getNodeRefsByTitle('CLIP Text Encode (Prompt)')
await comfyPage.nodeOps.getNodeRefsByTitle('CLIP Text Encode (Prompt)')
)[0]
const slot1 = await loadCheckpointNode.getOutput(1)

View File

@@ -12,7 +12,7 @@ test.describe(
{ tag: ['@screenshot', '@ui'] },
() => {
test('Can add node', async ({ comfyPage }) => {
await comfyPage.rightClickCanvas()
await comfyPage.canvasOps.rightClick()
await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png')
await comfyPage.page.getByText('Add Node').click()
await comfyPage.nextFrame()
@@ -24,7 +24,7 @@ test.describe(
})
test('Can add group', async ({ comfyPage }) => {
await comfyPage.rightClickCanvas()
await comfyPage.canvasOps.rightClick()
await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png')
await comfyPage.page.getByText('Add Group', { exact: true }).click()
await comfyPage.nextFrame()
@@ -34,9 +34,9 @@ test.describe(
})
test('Can convert to group node', async ({ comfyPage }) => {
await comfyPage.select2Nodes()
await comfyPage.nodeOps.select2Nodes()
await expect(comfyPage.canvas).toHaveScreenshot('selected-2-nodes.png')
await comfyPage.rightClickCanvas()
await comfyPage.canvasOps.rightClick()
await comfyPage.clickContextMenuItem('Convert to Group Node (Deprecated)')
await comfyPage.promptDialogInput.fill('GroupNode2CLIP')
await comfyPage.page.keyboard.press('Enter')
@@ -103,7 +103,7 @@ test.describe('Node Right Click Menu', { tag: ['@screenshot', '@ui'] }, () => {
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png')
await comfyPage.page.click('.litemenu-entry:has-text("Pin")')
await comfyPage.nextFrame()
await comfyPage.dragAndDrop({ x: 621, y: 617 }, { x: 16, y: 16 })
await comfyPage.canvasOps.dragAndDrop({ x: 621, y: 617 }, { x: 16, y: 16 })
await expect(comfyPage.canvas).toHaveScreenshot('node-pinned.png')
await comfyPage.rightClickEmptyLatentNode()
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -124,14 +124,17 @@ test.describe('Node Right Click Menu', { tag: ['@screenshot', '@ui'] }, () => {
await comfyPage.rightClickEmptyLatentNode()
await comfyPage.page.click('.litemenu-entry:has-text("Unpin")')
await comfyPage.nextFrame()
await comfyPage.dragAndDrop({ x: 496, y: 618 }, { x: 200, y: 590 })
await comfyPage.canvasOps.dragAndDrop(
{ x: 496, y: 618 },
{ x: 200, y: 590 }
)
await expect(comfyPage.canvas).toHaveScreenshot(
'right-click-unpinned-node-moved.png'
)
})
test('Can pin/unpin selected nodes', async ({ comfyPage }) => {
await comfyPage.select2Nodes()
await comfyPage.nodeOps.select2Nodes()
await comfyPage.page.keyboard.down('Control')
await comfyPage.rightClickEmptyLatentNode()
await comfyPage.page.click('.litemenu-entry:has-text("Pin")')
@@ -147,8 +150,8 @@ test.describe('Node Right Click Menu', { tag: ['@screenshot', '@ui'] }, () => {
})
test('Can clone pinned nodes', async ({ comfyPage }) => {
const nodeCount = await comfyPage.getGraphNodesCount()
const node = (await comfyPage.getFirstNodeRef())!
const nodeCount = await comfyPage.nodeOps.getGraphNodesCount()
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
await node.clickContextMenuOption('Pin')
await comfyPage.nextFrame()
await node.click('title', { button: 'right' })
@@ -161,6 +164,6 @@ test.describe('Node Right Click Menu', { tag: ['@screenshot', '@ui'] }, () => {
await cloneItem.click()
await expect(cloneItem).toHaveCount(0)
await comfyPage.nextFrame()
expect(await comfyPage.getGraphNodesCount()).toBe(nodeCount + 1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(nodeCount + 1)
})
})

View File

@@ -20,7 +20,10 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
await expect(comfyPage.selectionToolbox).not.toBeVisible()
// Select multiple nodes
await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes([
'KSampler',
'CLIP Text Encode (Prompt)'
])
// Selection toolbox should be visible with multiple nodes selected
await expect(comfyPage.selectionToolbox).toBeVisible()
@@ -34,7 +37,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
await comfyPage.loadWorkflow('nodes/single_ksampler')
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await comfyPage.ctrlC()
await comfyPage.page.mouse.move(100, 100)
await comfyPage.ctrlV()
@@ -55,7 +58,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
await comfyPage.loadWorkflow('nodes/single_ksampler')
const node = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const node = (await comfyPage.nodeOps.getNodeRefsByTitle('KSampler'))[0]
const nodePos = await node.getPosition()
// Drag on the title of the node
@@ -68,7 +71,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
test('shows border only with multiple selections', async ({ comfyPage }) => {
// Select single node
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
// Selection toolbox should be visible but without border
await expect(comfyPage.selectionToolbox).toBeVisible()
@@ -78,7 +81,10 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
)
// Select multiple nodes
await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes([
'KSampler',
'CLIP Text Encode (Prompt)'
])
// Selection border should show with multiple selections (canvas-based)
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -86,7 +92,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
)
// Deselect to single node
await comfyPage.selectNodes(['CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes(['CLIP Text Encode (Prompt)'])
// Border should be hidden again (canvas-based)
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -110,7 +116,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
).toBeVisible()
// Deselect node (Only group is selected) should hide bypass button
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await expect(
comfyPage.page.locator(
'.selection-toolbox *[data-testid="bypass-button"]'
@@ -123,7 +129,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
// Select a node
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
// Color picker button should be visible
const colorPickerButton = comfyPage.page.locator(
@@ -151,7 +157,9 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
// Node should have the selected color class/style
// Note: Exact verification method depends on how color is applied to nodes
const selectedNode = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const selectedNode = (
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
)[0]
expect(await selectedNode.getProperty('color')).not.toBeNull()
})
@@ -159,7 +167,10 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
// Select multiple nodes
await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes([
'KSampler',
'CLIP Text Encode (Prompt)'
])
const colorPickerButton = comfyPage.page.locator(
'.selection-toolbox .pi-circle-fill'
@@ -183,22 +194,25 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
// Select first node and color it
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await comfyPage.page.locator('.selection-toolbox .pi-circle-fill').click()
await comfyPage.page
.locator('.color-picker-container i[data-testid="blue"]')
.click()
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
// Select second node and color it differently
await comfyPage.selectNodes(['CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes(['CLIP Text Encode (Prompt)'])
await comfyPage.page.locator('.selection-toolbox .pi-circle-fill').click()
await comfyPage.page
.locator('.color-picker-container i[data-testid="red"]')
.click()
// Select both nodes
await comfyPage.selectNodes(['KSampler', 'CLIP Text Encode (Prompt)'])
await comfyPage.nodeOps.selectNodes([
'KSampler',
'CLIP Text Encode (Prompt)'
])
// Color picker should show null/mixed state
const colorPickerButton = comfyPage.page.locator(
@@ -211,17 +225,17 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
// First color a node
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await comfyPage.page.locator('.selection-toolbox .pi-circle-fill').click()
await comfyPage.page
.locator('.color-picker-container i[data-testid="blue"]')
.click()
// Clear selection
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
// Re-select the node
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
// Color picker button should show the correct color
const colorPickerButton = comfyPage.page.locator(
@@ -234,7 +248,7 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
comfyPage
}) => {
// Select a node and color it
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await comfyPage.page.locator('.selection-toolbox .pi-circle-fill').click()
await comfyPage.page
.locator('.color-picker-container i[data-testid="blue"]')
@@ -245,7 +259,9 @@ test.describe('Selection Toolbox', { tag: ['@screenshot', '@ui'] }, () => {
await comfyPage.nextFrame()
// Node should be uncolored again
const selectedNode = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const selectedNode = (
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
)[0]
expect(await selectedNode.getProperty('color')).toBeUndefined()
})
})

View File

@@ -15,12 +15,13 @@ test.describe(
await comfyPage.setSetting('Comfy.Canvas.SelectionToolbox', true)
await comfyPage.loadWorkflow('nodes/single_ksampler')
await comfyPage.nextFrame()
await comfyPage.selectNodes(['KSampler'])
await comfyPage.nodeOps.selectNodes(['KSampler'])
await comfyPage.nextFrame()
})
const openMoreOptions = async (comfyPage: ComfyPage) => {
const ksamplerNodes = await comfyPage.getNodeRefsByTitle('KSampler')
const ksamplerNodes =
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
if (ksamplerNodes.length === 0) {
throw new Error('No KSampler nodes found')
}
@@ -30,7 +31,7 @@ test.describe(
const viewportSize = comfyPage.page.viewportSize()
const centerX = viewportSize.width / 3
const centerY = viewportSize.height / 2
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: nodePos.x, y: nodePos.y },
{ x: centerX, y: centerY }
)
@@ -85,7 +86,9 @@ test.describe(
})
test('changes node shape via Shape submenu', async ({ comfyPage }) => {
const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const nodeRef = (
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
)[0]
const initialShape = await nodeRef.getProperty<number>('shape')
await openMoreOptions(comfyPage)
@@ -106,7 +109,9 @@ test.describe(
test('changes node color via Color submenu swatch', async ({
comfyPage
}) => {
const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const nodeRef = (
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
)[0]
const initialColor = await nodeRef.getProperty<string | undefined>(
'color'
)
@@ -126,7 +131,9 @@ test.describe(
})
test('renames a node using Rename action', async ({ comfyPage }) => {
const nodeRef = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
const nodeRef = (
await comfyPage.nodeOps.getNodeRefsByTitle('KSampler')
)[0]
await openMoreOptions(comfyPage)
await comfyPage.page
.getByText('Rename', { exact: true })

View File

@@ -26,7 +26,7 @@ test.describe('Node library sidebar', () => {
)
expect(previewVisible).toBe(true)
const count = await comfyPage.getGraphNodesCount()
const count = await comfyPage.nodeOps.getGraphNodesCount()
// Drag the node onto the canvas
const canvasSelector = '#graph-canvas'
@@ -46,7 +46,7 @@ test.describe('Node library sidebar', () => {
})
// Verify the node is added to the canvas
expect(await comfyPage.getGraphNodesCount()).toBe(count + 1)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(count + 1)
})
test('Bookmark node', async ({ comfyPage }) => {

View File

@@ -80,15 +80,17 @@ test.describe('Workflows sidebar', () => {
const tab = comfyPage.menu.workflowsTab
await tab.open()
await comfyPage.executeCommand('Comfy.LoadDefaultWorkflow')
const originalNodeCount = (await comfyPage.getNodes()).length
const originalNodeCount = (await comfyPage.nodeOps.getNodes()).length
await tab.insertWorkflow(tab.getPersistedItem('workflow1.json'))
await comfyPage.nextFrame()
expect((await comfyPage.getNodes()).length).toEqual(originalNodeCount + 1)
expect((await comfyPage.nodeOps.getNodes()).length).toEqual(
originalNodeCount + 1
)
await tab.getPersistedItem('workflow1.json').click()
await comfyPage.nextFrame()
expect((await comfyPage.getNodes()).length).toEqual(1)
expect((await comfyPage.nodeOps.getNodes()).length).toEqual(1)
})
test('Can rename nested workflow from opened workflow item', async ({
@@ -345,7 +347,7 @@ test.describe('Workflows sidebar', () => {
comfyPage.menu.workflowsTab.getPersistedItem('workflow1.json')
await expect(workflowItem).toBeVisible({ timeout: 3000 })
const nodeCount = await comfyPage.getGraphNodesCount()
const nodeCount = await comfyPage.nodeOps.getGraphNodesCount()
// Get the bounding box of the canvas element
const canvasBoundingBox = (await comfyPage.page
@@ -366,7 +368,7 @@ test.describe('Workflows sidebar', () => {
// Wait for nodes to be inserted after drag-drop with retryable assertion
await expect
.poll(() => comfyPage.getGraphNodesCount(), { timeout: 3000 })
.poll(() => comfyPage.nodeOps.getGraphNodesCount(), { timeout: 3000 })
.toBe(nodeCount * 2)
})
})

View File

@@ -22,7 +22,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
// Get initial slot label
@@ -32,7 +32,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
})
// First rename
await comfyPage.rightClickSubgraphInputSlot(initialInputLabel)
await comfyPage.subgraph.rightClickInputSlot(initialInputLabel)
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
@@ -67,7 +67,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
// Now rename again - this is where the bug would show
// We need to use the index-based approach since the method looks for slot.name
await comfyPage.rightClickSubgraphInputSlot()
await comfyPage.subgraph.rightClickInputSlot()
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
@@ -108,7 +108,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
// Get initial output slot label
@@ -118,7 +118,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
})
// First rename
await comfyPage.rightClickSubgraphOutputSlot(initialOutputLabel)
await comfyPage.subgraph.rightClickOutputSlot(initialOutputLabel)
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
@@ -141,7 +141,7 @@ test.describe('Subgraph Slot Rename Dialog', { tag: '@subgraph' }, () => {
// Now rename again to check for stale content
// We need to use the index-based approach since the method looks for slot.name
await comfyPage.rightClickSubgraphOutputSlot()
await comfyPage.subgraph.rightClickOutputSlot()
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {

View File

@@ -54,13 +54,13 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can add input slots to subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialCount = await getSubgraphSlotCount(comfyPage, 'inputs')
const vaeEncodeNode = await comfyPage.getNodeRefById('2')
const vaeEncodeNode = await comfyPage.nodeOps.getNodeRefById('2')
await comfyPage.connectFromSubgraphInput(vaeEncodeNode, 0)
await comfyPage.subgraph.connectFromInput(vaeEncodeNode, 0)
await comfyPage.nextFrame()
const finalCount = await getSubgraphSlotCount(comfyPage, 'inputs')
@@ -70,13 +70,13 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can add output slots to subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialCount = await getSubgraphSlotCount(comfyPage, 'outputs')
const vaeEncodeNode = await comfyPage.getNodeRefById('2')
const vaeEncodeNode = await comfyPage.nodeOps.getNodeRefById('2')
await comfyPage.connectToSubgraphOutput(vaeEncodeNode, 0)
await comfyPage.subgraph.connectToOutput(vaeEncodeNode, 0)
await comfyPage.nextFrame()
const finalCount = await getSubgraphSlotCount(comfyPage, 'outputs')
@@ -86,13 +86,13 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can remove input slots from subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialCount = await getSubgraphSlotCount(comfyPage, 'inputs')
expect(initialCount).toBeGreaterThan(0)
await comfyPage.rightClickSubgraphInputSlot()
await comfyPage.subgraph.rightClickInputSlot()
await comfyPage.clickLitegraphContextMenuItem('Remove Slot')
// Force re-render
@@ -106,13 +106,13 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can remove output slots from subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialCount = await getSubgraphSlotCount(comfyPage, 'outputs')
expect(initialCount).toBeGreaterThan(0)
await comfyPage.rightClickSubgraphOutputSlot()
await comfyPage.subgraph.rightClickOutputSlot()
await comfyPage.clickLitegraphContextMenuItem('Remove Slot')
// Force re-render
@@ -126,7 +126,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can rename I/O slots', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialInputLabel = await comfyPage.page.evaluate(() => {
@@ -134,7 +134,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
return graph.inputs?.[0]?.label || null
})
await comfyPage.rightClickSubgraphInputSlot(initialInputLabel)
await comfyPage.subgraph.rightClickInputSlot(initialInputLabel)
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
@@ -159,7 +159,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can rename input slots via double-click', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialInputLabel = await comfyPage.page.evaluate(() => {
@@ -167,7 +167,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
return graph.inputs?.[0]?.label || null
})
await comfyPage.doubleClickSubgraphInputSlot(initialInputLabel)
await comfyPage.subgraph.doubleClickInputSlot(initialInputLabel)
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
state: 'visible'
@@ -191,7 +191,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can rename output slots via double-click', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialOutputLabel = await comfyPage.page.evaluate(() => {
@@ -199,7 +199,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
return graph.outputs?.[0]?.label || null
})
await comfyPage.doubleClickSubgraphOutputSlot(initialOutputLabel)
await comfyPage.subgraph.doubleClickOutputSlot(initialOutputLabel)
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
state: 'visible'
@@ -226,7 +226,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialInputLabel = await comfyPage.page.evaluate(() => {
@@ -235,7 +235,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
})
// Test that right-click still works for renaming
await comfyPage.rightClickSubgraphInputSlot(initialInputLabel)
await comfyPage.subgraph.rightClickInputSlot(initialInputLabel)
await comfyPage.clickLitegraphContextMenuItem('Rename Slot')
await comfyPage.page.waitForSelector(SELECTORS.promptDialog, {
@@ -263,7 +263,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialInputLabel = await comfyPage.page.evaluate(() => {
@@ -349,12 +349,12 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
await comfyPage.ctrlA()
await comfyPage.nextFrame()
const node = await comfyPage.getNodeRefById('5')
const node = await comfyPage.nodeOps.getNodeRefById('5')
await node.convertToSubgraph()
await comfyPage.nextFrame()
const subgraphNodes =
await comfyPage.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
await comfyPage.nodeOps.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
expect(subgraphNodes.length).toBe(1)
const finalNodeCount = await getGraphNodeCount(comfyPage)
@@ -364,7 +364,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can delete subgraph node', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
expect(await subgraphNode.exists()).toBe(true)
const initialNodeCount = await getGraphNodeCount(comfyPage)
@@ -376,7 +376,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
const finalNodeCount = await getGraphNodeCount(comfyPage)
expect(finalNodeCount).toBe(initialNodeCount - 1)
const deletedNode = await comfyPage.getNodeRefById('2')
const deletedNode = await comfyPage.nodeOps.getNodeRefById('2')
expect(await deletedNode.exists()).toBe(false)
})
@@ -386,7 +386,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
// Get position of subgraph node
const subgraphPos = await subgraphNode.getPosition()
@@ -404,7 +404,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
// Find all subgraph nodes
const subgraphNodes =
await comfyPage.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
await comfyPage.nodeOps.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
// Expect a second subgraph node to be created (2 total)
expect(subgraphNodes.length).toBe(2)
@@ -415,7 +415,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
}) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
// Get position of subgraph node
const subgraphPos = await subgraphNode.getPosition()
@@ -433,7 +433,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
// Find all subgraph nodes and expect all unique IDs
const subgraphNodes =
await comfyPage.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
await comfyPage.nodeOps.getNodeRefsByTitle(NEW_SUBGRAPH_TITLE)
// Expect the second subgraph node to have a unique type
const nodeType1 = await subgraphNodes[0].getType()
@@ -447,7 +447,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can copy and paste nodes in subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
const initialNodeCount = await getGraphNodeCount(comfyPage)
@@ -459,7 +459,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
expect(nodesInSubgraph).not.toBeNull()
const nodeToClone = await comfyPage.getNodeRefById(
const nodeToClone = await comfyPage.nodeOps.getNodeRefById(
String(nodesInSubgraph)
)
await nodeToClone.click('title')
@@ -478,11 +478,11 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
test('Can undo and redo operations in subgraph', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
// Add a node
await comfyPage.doubleClickCanvas()
await comfyPage.canvasOps.doubleClick()
await comfyPage.searchBox.fillAndSelectFirstNode('Note')
await comfyPage.nextFrame()
@@ -516,7 +516,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
await comfyPage.loadWorkflow('subgraphs/nested-subgraph')
await comfyPage.nextFrame()
const subgraphNode = await comfyPage.getNodeRefById('10')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('10')
const nodePos = await subgraphNode.getPosition()
const nodeSize = await subgraphNode.getSize()
@@ -575,7 +575,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
await expect(parentTextarea).toBeVisible()
await expect(parentTextarea).toHaveCount(1)
const subgraphNode = await comfyPage.getNodeRefById('11')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('11')
expect(await subgraphNode.exists()).toBe(true)
await subgraphNode.navigateIntoSubgraph()
@@ -605,7 +605,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
const textarea = comfyPage.page.locator(SELECTORS.domWidget)
await textarea.fill(TEST_WIDGET_CONTENT)
const subgraphNode = await comfyPage.getNodeRefById('11')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('11')
await subgraphNode.navigateIntoSubgraph()
const subgraphTextarea = comfyPage.page.locator(SELECTORS.domWidget)
@@ -630,7 +630,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
.count()
expect(initialCount).toBe(1)
const subgraphNode = await comfyPage.getNodeRefById('11')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('11')
await subgraphNode.click('title')
await comfyPage.page.keyboard.press('Delete')
@@ -656,12 +656,12 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
.count()
expect(textareaCount).toBe(1)
const subgraphNode = await comfyPage.getNodeRefById('11')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('11')
// Navigate into subgraph (method now handles retries internally)
await subgraphNode.navigateIntoSubgraph()
await comfyPage.rightClickSubgraphInputSlot('text')
await comfyPage.subgraph.rightClickInputSlot('text')
await comfyPage.clickLitegraphContextMenuItem('Remove Slot')
// Wait for breadcrumb to be visible
@@ -700,7 +700,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
.count()
expect(parentCount).toBeGreaterThan(1)
const subgraphNode = await comfyPage.getNodeRefById('11')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('11')
await subgraphNode.navigateIntoSubgraph()
const subgraphCount = await comfyPage.page
@@ -757,7 +757,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
await comfyPage.setup()
// Navigate into subgraph
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
await comfyPage.page.waitForSelector(SELECTORS.breadcrumb)
@@ -783,7 +783,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => {
await comfyPage.loadWorkflow('subgraphs/basic-subgraph')
await comfyPage.nextFrame()
const subgraphNode = await comfyPage.getNodeRefById('2')
const subgraphNode = await comfyPage.nodeOps.getNodeRefById('2')
await subgraphNode.navigateIntoSubgraph()
await comfyPage.page.waitForSelector(SELECTORS.breadcrumb)

View File

@@ -74,7 +74,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => {
await comfyPage.menu.workflowsTab.open()
await comfyPage.executeCommand('Comfy.NewBlankWorkflow')
await expect(async () => {
expect(await comfyPage.getGraphNodesCount()).toBe(0)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBe(0)
}).toPass({ timeout: 250 })
// Load a template
@@ -89,7 +89,7 @@ test.describe('Templates', { tag: ['@slow', '@workflow'] }, () => {
// Ensure we now have some nodes
await expect(async () => {
expect(await comfyPage.getGraphNodesCount()).toBeGreaterThan(0)
expect(await comfyPage.nodeOps.getGraphNodesCount()).toBeGreaterThan(0)
}).toPass({ timeout: 250 })
})

View File

@@ -13,7 +13,10 @@ test.describe('Vue Nodes Canvas Pan', () => {
'@mobile Can pan with touch',
{ tag: '@screenshot' },
async ({ comfyPage }) => {
await comfyPage.panWithTouch({ x: 64, y: 64 }, { x: 256, y: 256 })
await comfyPage.canvasOps.panWithTouch(
{ x: 64, y: 64 },
{ x: 256, y: 256 }
)
await expect(comfyPage.canvas).toHaveScreenshot(
'vue-nodes-paned-with-touch.png'
)

View File

@@ -26,7 +26,7 @@ test.describe('Vue Nodes Zoom', () => {
// the node. The node should not capture the drag while drag-zooming.
await comfyPage.page.keyboard.down('Control')
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: 200, y: 300 },
{ x: nodeMidpointX, y: nodeMidpointY }
)

View File

@@ -112,7 +112,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(samplerNode).toBeTruthy()
const slot = slotLocator(comfyPage.page, samplerNode.id, 0, false)
@@ -142,8 +144,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
test('should create a link when dropping on a compatible slot', async ({
comfyPage
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
expect(samplerNode && vaeNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -172,8 +176,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
test('should not create a link when slot types are incompatible', async ({
comfyPage
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
expect(samplerNode && clipNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -200,7 +208,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
test('should not create a link when dropping onto a slot on the same node', async ({
comfyPage
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(samplerNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -221,8 +231,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
expect(samplerNode && vaeNode).toBeTruthy()
const samplerOutputCenter = await getSlotCenter(
comfyPage.page,
@@ -258,8 +270,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
expect(samplerNode && vaeNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -315,8 +329,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
expect(samplerNode && vaeNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -398,8 +414,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
const samplerOutput = await samplerNode.getOutput(0)
const vaeInput = await vaeNode.getInput(0)
@@ -483,8 +501,10 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
const vaeNode = (await comfyPage.nodeOps.getNodeRefsByType('VAEDecode'))[0]
expect(samplerNode && vaeNode).toBeTruthy()
const samplerOutput = await samplerNode.getOutput(0)
@@ -572,8 +592,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(clipNode && samplerNode).toBeTruthy()
// Step 1: Connect CLIP's only output (index 0) to KSampler's second input (index 1)
@@ -642,8 +666,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(clipNode && samplerNode).toBeTruthy()
const clipOutput = await clipNode.getOutput(0)
@@ -697,8 +725,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(clipNode && samplerNode).toBeTruthy()
// Start drag from CLIP output[0]
@@ -746,8 +778,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
comfyPage,
comfyMouse
}) => {
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(clipNode && samplerNode).toBeTruthy()
// Drag from CLIP output[0] to KSampler input[2] (third slot) which is the
@@ -791,8 +827,12 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
test('should batch disconnect all links with ctrl+alt+click on slot', async ({
comfyPage
}) => {
const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0]
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const clipNode = (
await comfyPage.nodeOps.getNodeRefsByType('CLIPTextEncode')
)[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(clipNode && samplerNode).toBeTruthy()
await connectSlots(
@@ -837,7 +877,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
'context menu'
)
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(samplerNode).toBeTruthy()
const outputCenter = await getSlotCenter(
@@ -888,7 +930,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
)
await comfyPage.setSetting('Comfy.NodeSearchBoxImpl', 'default')
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(samplerNode).toBeTruthy()
const outputCenter = await getSlotCenter(
@@ -928,7 +972,7 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
expect(await samplerOutput.getLinkCount()).toBe(1)
// One of the VAEDecode nodes should have an incoming link on input[0]
const vaeNodes = await comfyPage.getNodeRefsByType('VAEDecode')
const vaeNodes = await comfyPage.nodeOps.getNodeRefsByType('VAEDecode')
let linked = false
for (const vae of vaeNodes) {
const details = await getInputLinkDetails(comfyPage.page, vae.id, 0)
@@ -947,7 +991,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
}) => {
await comfyPage.setSetting('Comfy.LinkRelease.ActionShift', 'search box')
const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0]
const samplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)[0]
expect(samplerNode).toBeTruthy()
const outputCenter = await getSlotCenter(
@@ -980,7 +1026,7 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
const samplerOutput = await samplerNode.getOutput(0)
expect(await samplerOutput.getLinkCount()).toBe(1)
const vaeNodes = await comfyPage.getNodeRefsByType('VAEDecode')
const vaeNodes = await comfyPage.nodeOps.getNodeRefsByType('VAEDecode')
let linked = false
for (const vae of vaeNodes) {
const details = await getInputLinkDetails(comfyPage.page, vae.id, 0)
@@ -1007,7 +1053,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
await comfyPage.waitForGraphNodes(1)
// Convert the KSampler node to a subgraph
let ksamplerNode = (await comfyPage.getNodeRefsByType('KSampler'))?.[0]
let ksamplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
)?.[0]
await comfyPage.vueNodes.selectNode(String(ksamplerNode.id))
await comfyPage.executeCommand('Comfy.Graph.ConvertToSubgraph')
@@ -1016,7 +1064,9 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
await fitToViewInstant(comfyPage)
// Get the KSampler node inside the subgraph
ksamplerNode = (await comfyPage.getNodeRefsByType('KSampler', true))?.[0]
ksamplerNode = (
await comfyPage.nodeOps.getNodeRefsByType('KSampler', true)
)?.[0]
const positiveInput = await ksamplerNode.getInput(1)
const negativeInput = await ksamplerNode.getInput(2)
@@ -1027,7 +1077,7 @@ test.describe('Vue Node Link Interaction', { tag: '@screenshot' }, () => {
true
)
const sourceSlot = await comfyPage.getSubgraphInputSlot()
const sourceSlot = await comfyPage.subgraph.getInputSlot()
const calculatedSourcePos = await sourceSlot.getOpenSlotPosition()
await comfyMouse.move(calculatedSourcePos)

View File

@@ -61,7 +61,7 @@ test.describe('Vue Node Bring to Front', { tag: '@screenshot' }, () => {
if (!ksamplerHeader) throw new Error('KSampler header not found')
// Drag KSampler on top of CLIP Text Encode
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: ksamplerHeader.x + 50, y: ksamplerHeader.y + 10 },
clipCenter
)
@@ -108,7 +108,7 @@ test.describe('Vue Node Bring to Front', { tag: '@screenshot' }, () => {
const vaeHeader = await comfyPage.page.getByText('VAE Decode').boundingBox()
if (!vaeHeader) throw new Error('VAE Decode header not found')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: vaeHeader.x + 50, y: vaeHeader.y + 10 },
{ x: clipCenter.x - 50, y: clipCenter.y }
)

View File

@@ -35,7 +35,7 @@ test.describe('Vue Node Moving', () => {
async ({ comfyPage }) => {
const loadCheckpointHeaderPos =
await getLoadCheckpointHeaderPos(comfyPage)
await comfyPage.dragAndDrop(loadCheckpointHeaderPos, {
await comfyPage.canvasOps.dragAndDrop(loadCheckpointHeaderPos, {
x: 256,
y: 256
})
@@ -56,7 +56,7 @@ test.describe('Vue Node Moving', () => {
const loadCheckpointHeaderPos =
await getLoadCheckpointHeaderPos(comfyPage)
await comfyPage.panWithTouch(
await comfyPage.canvasOps.panWithTouch(
{
x: 64,
y: 64

View File

@@ -83,7 +83,7 @@ test.describe('Vue Nodes - Delete Key Interaction', () => {
test('Delete key does not delete node when typing in Vue node widgets', async ({
comfyPage
}) => {
const initialNodeCount = await comfyPage.getGraphNodesCount()
const initialNodeCount = await comfyPage.nodeOps.getGraphNodesCount()
// Find a text input widget in a Vue node
const textWidget = comfyPage.page
@@ -98,7 +98,7 @@ test.describe('Vue Nodes - Delete Key Interaction', () => {
await textWidget.press('Delete')
// Node count should remain the same
const finalNodeCount = await comfyPage.getGraphNodesCount()
const finalNodeCount = await comfyPage.nodeOps.getGraphNodesCount()
expect(finalNodeCount).toBe(initialNodeCount)
})

View File

@@ -78,7 +78,7 @@ test.describe('Vue Node Selection', () => {
const initialPos = await checkpointNodeHeader.boundingBox()
if (!initialPos) throw new Error('Failed to get header position')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: initialPos.x + 10, y: initialPos.y + 10 },
{ x: initialPos.x + 100, y: initialPos.y + 100 }
)

View File

@@ -55,7 +55,7 @@ test.describe('Vue Node Pin', () => {
// Try to drag the node
const headerPos = await checkpointNodeHeader.boundingBox()
if (!headerPos) throw new Error('Failed to get header position')
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: headerPos.x, y: headerPos.y },
{ x: headerPos.x + 256, y: headerPos.y + 256 }
)
@@ -71,7 +71,7 @@ test.describe('Vue Node Pin', () => {
await comfyPage.page.keyboard.press(PIN_HOTKEY)
// Try to drag the node again
await comfyPage.dragAndDrop(
await comfyPage.canvasOps.dragAndDrop(
{ x: headerPos.x, y: headerPos.y },
{ x: headerPos.x + 256, y: headerPos.y + 256 }
)

View File

@@ -83,7 +83,7 @@ test.describe('Boolean widget', { tag: ['@screenshot', '@widget'] }, () => {
test('Can toggle', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('widgets/boolean_widget')
await expect(comfyPage.canvas).toHaveScreenshot('boolean_widget.png')
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
const widget = await node.getWidget(0)
await widget.click()
await expect(comfyPage.canvas).toHaveScreenshot(
@@ -95,7 +95,7 @@ test.describe('Boolean widget', { tag: ['@screenshot', '@widget'] }, () => {
test.describe('Slider widget', { tag: ['@screenshot', '@widget'] }, () => {
test('Can drag adjust value', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('inputs/simple_slider')
const node = (await comfyPage.getFirstNodeRef())!
const node = (await comfyPage.nodeOps.getFirstNodeRef())!
const widget = await node.getWidget(0)
await comfyPage.page.evaluate(() => {
@@ -117,7 +117,7 @@ test.describe('Number widget', { tag: ['@screenshot', '@widget'] }, () => {
test('Can drag adjust value', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('widgets/seed_widget')
const node = (await comfyPage.getFirstNodeRef())!
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]
@@ -165,7 +165,7 @@ test.describe('Image widget', { tag: ['@screenshot', '@widget'] }, () => {
await comfyPage.loadWorkflow('widgets/load_image_widget')
// Get position of the load image node
const nodes = await comfyPage.getNodeRefsByType('LoadImage')
const nodes = await comfyPage.nodeOps.getNodeRefsByType('LoadImage')
const loadImageNode = nodes[0]
const { x, y } = await loadImageNode.getPosition()
@@ -189,7 +189,7 @@ test.describe('Image widget', { tag: ['@screenshot', '@widget'] }, () => {
comfyPage
}) => {
await comfyPage.loadWorkflow('widgets/load_image_widget')
const nodes = await comfyPage.getNodeRefsByType('LoadImage')
const nodes = await comfyPage.nodeOps.getNodeRefsByType('LoadImage')
const loadImageNode = nodes[0]
// Click the combo widget used to select the image filename
@@ -253,7 +253,7 @@ test.describe(
await comfyPage.loadWorkflow('widgets/load_animated_webp')
// Get position of the load animated webp node
const nodes = await comfyPage.getNodeRefsByType(
const nodes = await comfyPage.nodeOps.getNodeRefsByType(
'DevToolsLoadAnimatedImageTest'
)
const loadAnimatedWebpNode = nodes[0]
@@ -282,7 +282,7 @@ test.describe(
await comfyPage.loadWorkflow('widgets/load_animated_webp')
// Get position of the load animated webp node
const nodes = await comfyPage.getNodeRefsByType(
const nodes = await comfyPage.nodeOps.getNodeRefsByType(
'DevToolsLoadAnimatedImageTest'
)
const loadAnimatedWebpNode = nodes[0]
@@ -304,7 +304,7 @@ test.describe(
await comfyPage.loadWorkflow('widgets/save_animated_webp')
// Get position of the load animated webp node
const loadNodes = await comfyPage.getNodeRefsByType(
const loadNodes = await comfyPage.nodeOps.getNodeRefsByType(
'DevToolsLoadAnimatedImageTest'
)
const loadAnimatedWebpNode = loadNodes[0]
@@ -317,7 +317,8 @@ test.describe(
await comfyPage.nextFrame()
// Get the SaveAnimatedWEBP node
const saveNodes = await comfyPage.getNodeRefsByType('SaveAnimatedWEBP')
const saveNodes =
await comfyPage.nodeOps.getNodeRefsByType('SaveAnimatedWEBP')
const saveAnimatedWebpNode = saveNodes[0]
if (!saveAnimatedWebpNode)
throw new Error('SaveAnimatedWEBP node not found')

View File

@@ -92,7 +92,7 @@ test.describe('Workflow Tab Thumbnails', { tag: '@workflow' }, () => {
)
await comfyPage.delay(300) // Wait for the popover to hide
await comfyPage.rightClickCanvas(200, 200)
await comfyPage.canvasOps.rightClick(200, 200)
await comfyPage.page.getByText('Add Node').click()
await comfyPage.nextFrame()
await comfyPage.page.getByText(category).click()