test: add regression for collapsed bypass toggle, drive via user actions

Add two E2E tests covering the stale collapsedSize cache bug fixed in
2693ec256: toggling bypass on a collapsed node (which changes body width
via the Bypassed badge) previously left the selection bounding box at
the pre-toggle width.

Switch the existing Vue-mode and legacy-mode selection bounding box
tests from programmatic NodeReference.setCollapsed to the Alt+C
keyboard shortcut. Since the keybinding is mode-agnostic, the same
user-action path now drives both modes and removes the divergence
between DOM-driven Vue tests and programmatic legacy tests.

Add KeyboardHelper.collapse() (Alt+C) next to the existing bypass()
(Ctrl+B) so the shortcut has a discoverable helper. Drop the unused
NodeReference.setCollapsed helper introduced earlier in this PR.
This commit is contained in:
jaeone94
2026-04-15 16:18:07 +09:00
parent 2693ec2560
commit 4ded224173
3 changed files with 97 additions and 14 deletions

View File

@@ -19,6 +19,15 @@ export class KeyboardHelper {
await this.nextFrame()
}
async altSend(
keyToPress: string,
locator: Locator | null = this.canvas
): Promise<void> {
const target = locator ?? this.page.keyboard
await target.press(`Alt+${keyToPress}`)
await this.nextFrame()
}
async selectAll(locator?: Locator | null): Promise<void> {
await this.ctrlSend('KeyA', locator)
}
@@ -27,6 +36,10 @@ export class KeyboardHelper {
await this.ctrlSend('KeyB', locator)
}
async collapse(locator?: Locator | null): Promise<void> {
await this.altSend('KeyC', locator)
}
async undo(locator?: Locator | null): Promise<void> {
await this.ctrlSend('KeyZ', locator)
}

View File

@@ -332,18 +332,6 @@ export class NodeReference {
async isCollapsed() {
return !!(await this.getFlags()).collapsed
}
/** Deterministic setter using node.collapse() API (not a toggle). */
async setCollapsed(collapsed: boolean) {
await this.comfyPage.page.evaluate(
([id, collapsed]) => {
const node = window.app!.canvas.graph!.getNodeById(id)
if (!node) throw new Error('Node not found')
if (node.collapsed !== collapsed) node.collapse(true)
},
[this.id, collapsed] as const
)
await this.comfyPage.nextFrame()
}
async isBypassed() {
return (await this.getProperty<number | null | undefined>('mode')) === 4
}

View File

@@ -4,6 +4,7 @@ import type { Page } from '@playwright/test'
import type { ComfyPage } from '@e2e/fixtures/ComfyPage'
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
import { measureSelectionBounds } from '@e2e/fixtures/helpers/boundsUtils'
import type { NodeReference } from '@e2e/fixtures/utils/litegraphUtils'
const SUBGRAPH_ID = '2'
const REGULAR_ID = '3'
@@ -27,6 +28,19 @@ function getRefId(type: NodeType): string {
return type === 'subgraph' ? REGULAR_ID : SUBGRAPH_ID
}
async function userToggleCollapse(
comfyPage: ComfyPage,
nodeRef: NodeReference
) {
await nodeRef.click('title')
await comfyPage.keyboard.collapse()
}
async function userToggleBypass(comfyPage: ComfyPage, nodeRef: NodeReference) {
await nodeRef.click('title')
await comfyPage.keyboard.bypass()
}
async function assertSelectionEncompassesNodes(
page: Page,
comfyPage: ComfyPage,
@@ -94,7 +108,8 @@ test.describe(
if (state === 'collapsed') {
const nodeRef = await comfyPage.nodeOps.getNodeRefById(targetId)
await nodeRef.setCollapsed(true)
await userToggleCollapse(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isCollapsed()).toBe(true)
}
await assertSelectionEncompassesNodes(comfyPage.page, comfyPage, [
@@ -108,6 +123,72 @@ test.describe(
}
)
test.describe(
'Selection bounding box (Vue mode) — collapsed node bypass toggle',
{ tag: ['@canvas', '@node'] },
() => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.settings.setSetting('Comfy.VueNodes.Enabled', true)
await comfyPage.workflow.loadWorkflow(WORKFLOW)
await comfyPage.vueNodes.waitForNodes()
})
test.afterEach(async ({ comfyPage }) => {
await comfyPage.canvasOps.resetView()
})
test('collapsed node narrows bounding box when bypass is removed', async ({
comfyPage
}) => {
await comfyPage.nodeOps.repositionNodes({
[SUBGRAPH_ID]: REF_POS,
[REGULAR_ID]: TARGET_POSITIONS['bottom-right']
})
await comfyPage.nextFrame()
await comfyPage.vueNodes.waitForNodes()
const nodeRef = await comfyPage.nodeOps.getNodeRefById(REGULAR_ID)
await userToggleBypass(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isBypassed()).toBe(true)
await userToggleCollapse(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isCollapsed()).toBe(true)
await userToggleBypass(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isBypassed()).toBe(false)
await comfyPage.nextFrame()
await assertSelectionEncompassesNodes(comfyPage.page, comfyPage, [
SUBGRAPH_ID,
REGULAR_ID
])
})
test('collapsed node widens bounding box when bypass is added', async ({
comfyPage
}) => {
await comfyPage.nodeOps.repositionNodes({
[SUBGRAPH_ID]: REF_POS,
[REGULAR_ID]: TARGET_POSITIONS['bottom-right']
})
await comfyPage.nextFrame()
await comfyPage.vueNodes.waitForNodes()
const nodeRef = await comfyPage.nodeOps.getNodeRefById(REGULAR_ID)
await userToggleCollapse(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isCollapsed()).toBe(true)
await userToggleBypass(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isBypassed()).toBe(true)
await comfyPage.nextFrame()
await assertSelectionEncompassesNodes(comfyPage.page, comfyPage, [
SUBGRAPH_ID,
REGULAR_ID
])
})
}
)
test.describe(
'Selection bounding box (legacy mode)',
{ tag: ['@canvas', '@node'] },
@@ -138,7 +219,8 @@ test.describe(
if (state === 'collapsed') {
const nodeRef = await comfyPage.nodeOps.getNodeRefById(REGULAR_ID)
await nodeRef.setCollapsed(true)
await userToggleCollapse(comfyPage, nodeRef)
await expect.poll(() => nodeRef.isCollapsed()).toBe(true)
}
await assertSelectionEncompassesNodes(comfyPage.page, comfyPage, [