Files
ComfyUI_frontend/.claude/skills/writing-playwright-tests/core/nodes.md
2026-02-03 16:54:38 -08:00

4.7 KiB

Node Patterns

⚠️ LiteGraph Mode: These patterns apply to the default LiteGraph canvas rendering. For Vue Nodes 2.0 (DOM-based rendering), see vue-nodes.md.

Mode Node Access Example
LiteGraph comfyPage.getNodeRefsByTitle()[0] node.click(), node.getWidget('seed')
Vue Nodes comfyPage.vueNodes.getNodeByTitle() Playwright locators, CSS classes

Getting Node References

By Title (Preferred)

// Use display names (e.g., 'KSampler', 'VAE Decode', 'CLIP Text Encode (Prompt)')
// These match the display_name from node definitions, not internal type names
const node = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]

// For multi-selection
await comfyPage.selectNodes(['KSampler', 'VAE Decode'])

By ID

// When you know the specific node ID
const node = comfyPage.getNodeRefById(5)

First/Last Node

const firstNode = comfyPage.getFirstNode()
const lastNode = comfyPage.getLastNode()

Node Operations

Click Node

const node = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
await node.click()
await comfyPage.nextFrame()

Drag Node

const node = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]
await node.drag({ x: 100, y: 50 })
await comfyPage.nextFrame()

Collapse/Expand

await node.collapse()
await comfyPage.nextFrame()

await node.expand()
await comfyPage.nextFrame()

// Assert state
await expect(node).toBeCollapsed()

Bypass

await node.bypass()
await comfyPage.nextFrame()

// Assert state
await expect(node).toBeBypassed()

Pin

await node.pin()
await comfyPage.nextFrame()

// Assert state
await expect(node).toBePinned()

Delete

await node.click()
await comfyPage.canvas.focus()
await comfyPage.page.keyboard.press('Delete')
await comfyPage.nextFrame()

Slots (Inputs/Outputs)

Get Slot Reference

// Output slot
const outputSlot = node.getOutputSlot('MODEL')

// Input slot
const inputSlot = node.getInputSlot('model')

Get Slot Position

const position = await outputSlot.getPosition()
// { x: number, y: number }

Connect Slots

const sourceNode = (await comfyPage.getNodeRefsByTitle('Load Checkpoint'))[0]
const targetNode = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]

const outputSlot = sourceNode.getOutputSlot('MODEL')
const inputSlot = targetNode.getInputSlot('model')

await comfyMouse.dragFromTo(
  await outputSlot.getPosition(),
  await inputSlot.getPosition(),
  { steps: 10 }
)
await comfyPage.nextFrame()

Widgets

Get Widget

const widget = node.getWidget('seed')
const stepsWidget = node.getWidget('steps')

Set Widget Value

await widget.setValue(12345)
await comfyPage.nextFrame()

Get Widget Value

const value = await widget.getValue()
expect(value).toBe(12345)

Widget Types

See patterns/widgets.md for type-specific patterns.

Node Assertions

// Visibility
await expect(node.locator).toBeVisible()

// States (custom matchers)
await expect(node).toBeCollapsed()
await expect(node).toBeBypassed()
await expect(node).toBePinned()

Example: Complete Node Test

import {
  comfyPageFixture as test,
  comfyExpect as expect
} from './fixtures/ComfyPage'

test.describe('Node Operations', { tag: ['@node'] }, () => {
  test.beforeEach(async ({ comfyPage }) => {
    await comfyPage.loadWorkflow('nodes/basic')
    await comfyPage.nextFrame()
  })

  test.afterEach(async ({ comfyPage }) => {
    await comfyPage.resetView()
  })

  test('collapses and expands node', async ({ comfyPage }) => {
    const node = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]

    await node.collapse()
    await comfyPage.nextFrame()
    await expect(node).toBeCollapsed()

    await node.expand()
    await comfyPage.nextFrame()
    await expect(node).not.toBeCollapsed()
  })

  test('connects two nodes', async ({ comfyPage, comfyMouse }) => {
    const source = (await comfyPage.getNodeRefsByTitle('Load Checkpoint'))[0]
    const target = (await comfyPage.getNodeRefsByTitle('KSampler'))[0]

    await comfyMouse.dragFromTo(
      await source.getOutputSlot('MODEL').getPosition(),
      await target.getInputSlot('model').getPosition(),
      { steps: 10 }
    )
    await comfyPage.nextFrame()

    // Verify connection via screenshot or workflow state
    await expect(comfyPage.canvas).toHaveScreenshot('connected.png')
  })
})