Files
ComfyUI_frontend/browser_tests/helpers/promotedWidgets.ts
Alexander Brown 4d57c41fdb test: subgraph integration contracts and expanded Playwright coverage (#10123)
## Summary

Add integration contract tests (unit) and expanded Playwright coverage
for subgraph promotion, hydration, navigation, and lifecycle edge
behaviors.

## Changes

- **What**: 22 unit/integration tests across 9 files covering promotion
store sync, widget view lifecycle, input link resolution, pseudo-widget
cache, navigation viewport restore, and subgraph operations. 13
Playwright E2E tests covering proxyWidgets hydration stability, promoted
source removal cleanup, pseudo-preview unpack/remove, multi-link
representative round-trip, nested promotion retarget, and navigation
state on workflow switch.
- **Helpers**: Added `isPseudoPreviewEntry`, `getPseudoPreviewWidgets`,
`getNonPreviewPromotedWidgets` to promotedWidgets helper. Added
`SubgraphHelper.getNodeCount()`.

## Review Focus

- Test-only PR — no production code changes
- Validates existing subgraph behaviors are covered by regression tests
before further feature work
- Phase 4 (unit/integration contracts) and Phase 5 (Playwright
expansion) of the subgraph test coverage plan

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10123-test-subgraph-integration-contracts-and-expanded-Playwright-coverage-3256d73d365081258023e3a763859e00)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
2026-03-19 23:54:15 +00:00

112 lines
3.0 KiB
TypeScript

import type { ComfyPage } from '../fixtures/ComfyPage'
export type PromotedWidgetEntry = [string, string]
export interface PromotedWidgetSnapshot {
proxyWidgets: PromotedWidgetEntry[]
widgetNames: string[]
}
export function isPromotedWidgetEntry(
entry: unknown
): entry is PromotedWidgetEntry {
return (
Array.isArray(entry) &&
entry.length === 2 &&
typeof entry[0] === 'string' &&
typeof entry[1] === 'string'
)
}
export function normalizePromotedWidgets(
value: unknown
): PromotedWidgetEntry[] {
if (!Array.isArray(value)) return []
return value.filter(isPromotedWidgetEntry)
}
export async function getPromotedWidgets(
comfyPage: ComfyPage,
nodeId: string
): Promise<PromotedWidgetEntry[]> {
const raw = await comfyPage.page.evaluate((id) => {
const node = window.app!.canvas.graph!.getNodeById(id)
return node?.properties?.proxyWidgets ?? []
}, nodeId)
return normalizePromotedWidgets(raw)
}
export async function getPromotedWidgetSnapshot(
comfyPage: ComfyPage,
nodeId: string
): Promise<PromotedWidgetSnapshot> {
const raw = await comfyPage.page.evaluate((id) => {
const node = window.app!.canvas.graph!.getNodeById(id)
return {
proxyWidgets: node?.properties?.proxyWidgets ?? [],
widgetNames: (node?.widgets ?? []).map((widget) => widget.name)
}
}, nodeId)
return {
proxyWidgets: normalizePromotedWidgets(raw.proxyWidgets),
widgetNames: Array.isArray(raw.widgetNames)
? raw.widgetNames.filter(
(name): name is string => typeof name === 'string'
)
: []
}
}
export async function getPromotedWidgetNames(
comfyPage: ComfyPage,
nodeId: string
): Promise<string[]> {
const promotedWidgets = await getPromotedWidgets(comfyPage, nodeId)
return promotedWidgets.map(([, widgetName]) => widgetName)
}
export async function getPromotedWidgetCount(
comfyPage: ComfyPage,
nodeId: string
): Promise<number> {
const promotedWidgets = await getPromotedWidgets(comfyPage, nodeId)
return promotedWidgets.length
}
export function isPseudoPreviewEntry(entry: PromotedWidgetEntry): boolean {
return entry[1].startsWith('$$')
}
export async function getPseudoPreviewWidgets(
comfyPage: ComfyPage,
nodeId: string
): Promise<PromotedWidgetEntry[]> {
const widgets = await getPromotedWidgets(comfyPage, nodeId)
return widgets.filter(isPseudoPreviewEntry)
}
export async function getNonPreviewPromotedWidgets(
comfyPage: ComfyPage,
nodeId: string
): Promise<PromotedWidgetEntry[]> {
const widgets = await getPromotedWidgets(comfyPage, nodeId)
return widgets.filter((entry) => !isPseudoPreviewEntry(entry))
}
export async function getPromotedWidgetCountByName(
comfyPage: ComfyPage,
nodeId: string,
widgetName: string
): Promise<number> {
return comfyPage.page.evaluate(
([id, name]) => {
const node = window.app!.canvas.graph!.getNodeById(id)
const widgets = node?.widgets ?? []
return widgets.filter((widget) => widget.name === name).length
},
[nodeId, widgetName] as const
)
}