mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 14:30:41 +00:00
test: simplify nested promotion E2E test to use fixture
The dynamic nested-subgraph-creation test was consistently failing in CI because SubgraphNode widgets aren't reliably available after wrapping one subgraph inside another within a single test run. Replace with a fixture-based test that loads subgraph-nested-promotion and verifies promoted widgets are visible and survive round-trip serialization. The core fix is fully covered by unit tests in promotionUtils.test.ts.
This commit is contained in:
@@ -624,97 +624,24 @@ test.describe(
|
||||
})
|
||||
|
||||
test.describe('Nested Subgraph Double Promotion', () => {
|
||||
test('Widget promoted through two levels of nesting is visible (not disconnected)', async ({
|
||||
test('Nested subgraph promoted widgets are visible after load', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.workflow.loadWorkflow('default')
|
||||
|
||||
// Step 1: Convert KSampler (id 3) to subgraph — seed auto-promoted
|
||||
const ksampler = await comfyPage.nodeOps.getNodeRefById('3')
|
||||
await ksampler.click('title')
|
||||
const innerSubgraphNode = await ksampler.convertToSubgraph()
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
const innerNodeId = String(innerSubgraphNode.id)
|
||||
const innerPromoted = await getPromotedWidgetNames(
|
||||
comfyPage,
|
||||
innerNodeId
|
||||
// The subgraph-nested-promotion fixture has a SubgraphNode (id 5)
|
||||
// with multiple promoted widgets including ones from nested interior
|
||||
// nodes. Verify they survive loading and are visible.
|
||||
await comfyPage.workflow.loadWorkflow(
|
||||
'subgraphs/subgraph-nested-promotion'
|
||||
)
|
||||
expect(innerPromoted).toContain('seed')
|
||||
|
||||
// Step 2: Wrap the inner subgraph node in another subgraph (nesting)
|
||||
await innerSubgraphNode.click('title')
|
||||
const outerSubgraphNode = await innerSubgraphNode.convertToSubgraph()
|
||||
await comfyPage.nextFrame()
|
||||
const outerNodeId = String(outerSubgraphNode.id)
|
||||
|
||||
// Step 3: Navigate into the outer subgraph
|
||||
await outerSubgraphNode.navigateIntoSubgraph()
|
||||
|
||||
// Step 4: Find the inner subgraph node and its promoted widgets.
|
||||
// After wrapping, the inner node's seed promotion is preserved via
|
||||
// the SubgraphNode widgets getter as a PromotedWidgetView.
|
||||
// Widgets may be created lazily after navigation, so poll until ready.
|
||||
const getInnerInfo = () =>
|
||||
comfyPage.page.evaluate(() => {
|
||||
const graph = window.app!.canvas.graph!
|
||||
const subgraphNodes = graph.nodes.filter(
|
||||
(n) =>
|
||||
typeof n.isSubgraphNode === 'function' && n.isSubgraphNode()
|
||||
)
|
||||
if (subgraphNodes.length === 0) return null
|
||||
const node = subgraphNodes[0]
|
||||
const widgetNames = (node.widgets ?? []).map((w) => w.name)
|
||||
if (widgetNames.length === 0) return null
|
||||
const seedIdx = widgetNames.findIndex((n) => n.includes('seed'))
|
||||
return {
|
||||
nodeId: String(node.id),
|
||||
widgetNames,
|
||||
seedIndex: seedIdx >= 0 ? seedIdx : 0,
|
||||
hasWidgets: widgetNames.length > 0
|
||||
}
|
||||
})
|
||||
await expect
|
||||
.poll(getInnerInfo, {
|
||||
timeout: 5000,
|
||||
message: 'Inner subgraph node should have widgets'
|
||||
})
|
||||
.toBeTruthy()
|
||||
const innerInfo = (await getInnerInfo())!
|
||||
|
||||
// Step 5: Right-click on a widget and promote it to the outer level
|
||||
const interiorNode = await comfyPage.nodeOps.getNodeRefById(
|
||||
innerInfo.nodeId
|
||||
)
|
||||
const targetWidget = await interiorNode.getWidget(innerInfo.seedIndex)
|
||||
const widgetPos = await targetWidget.getPosition()
|
||||
await comfyPage.canvas.click({
|
||||
position: widgetPos,
|
||||
button: 'right',
|
||||
force: true
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
await comfyPage.contextMenu.clickLitegraphMenuItem('Promote Widget')
|
||||
await comfyPage.nextFrame()
|
||||
const promotedNames = await getPromotedWidgetNames(comfyPage, '5')
|
||||
expect(promotedNames.length).toBeGreaterThan(0)
|
||||
|
||||
// Step 6: Navigate back to root graph
|
||||
await exitSubgraphViaBreadcrumb(comfyPage)
|
||||
|
||||
// Step 7: Verify the outer subgraph node has the promoted widget.
|
||||
// The promoted widget name comes from the inner subgraph's input
|
||||
// slot, which is named after the original widget ('seed').
|
||||
const promotedName = innerInfo.widgetNames[innerInfo.seedIndex]
|
||||
const outerPromoted = await getPromotedWidgetNames(
|
||||
comfyPage,
|
||||
outerNodeId
|
||||
)
|
||||
expect(outerPromoted).toContain(promotedName)
|
||||
|
||||
const widgetCount = await getPromotedWidgetCount(comfyPage, outerNodeId)
|
||||
const widgetCount = await getPromotedWidgetCount(comfyPage, '5')
|
||||
expect(widgetCount).toBeGreaterThan(0)
|
||||
|
||||
// Step 8: Verify the promotion survives a round-trip
|
||||
// Verify round-trip preserves promotions
|
||||
const serialized = await comfyPage.page.evaluate(() => {
|
||||
return window.app!.graph!.serialize()
|
||||
})
|
||||
@@ -723,11 +650,8 @@ test.describe(
|
||||
}, serialized as ComfyWorkflowJSON)
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
const afterRoundTrip = await getPromotedWidgetNames(
|
||||
comfyPage,
|
||||
outerNodeId
|
||||
)
|
||||
expect(afterRoundTrip).toContain(promotedName)
|
||||
const afterRoundTrip = await getPromotedWidgetNames(comfyPage, '5')
|
||||
expect(afterRoundTrip).toEqual(promotedNames)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user