|
| 1 | +import { expect } from '@playwright/test' |
| 2 | + |
| 3 | +import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage' |
| 4 | + |
| 5 | +test.describe( |
| 6 | + 'Subgraph creation boundary links', |
| 7 | + { tag: ['@slow', '@subgraph'] }, |
| 8 | + () => { |
| 9 | + test.beforeEach(async ({ comfyPage }) => { |
| 10 | + await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Disabled') |
| 11 | + await comfyPage.workflow.loadWorkflow('default') |
| 12 | + await comfyPage.nodeOps.selectNodes(['KSampler', 'VAE Decode']) |
| 13 | + const ksampler = await comfyPage.nodeOps.getNodeRefById('3') |
| 14 | + await ksampler.convertToSubgraph() |
| 15 | + }) |
| 16 | + |
| 17 | + test('rewires every boundary link onto the new subgraph node', async ({ |
| 18 | + comfyPage |
| 19 | + }) => { |
| 20 | + await expect |
| 21 | + .poll(() => |
| 22 | + comfyPage.page.evaluate(() => { |
| 23 | + const graph = window.app!.graph! |
| 24 | + const host = graph.nodes.find((node) => node.isSubgraphNode()) |
| 25 | + if (!host) return { error: 'no subgraph node' } |
| 26 | + |
| 27 | + const links = [...graph.links.values()] |
| 28 | + return { |
| 29 | + rootLinkCount: links.length, |
| 30 | + inputCount: host.inputs.length, |
| 31 | + outputCount: host.outputs.length, |
| 32 | + unconnectedInputs: host.inputs.filter( |
| 33 | + (input) => input.link == null |
| 34 | + ).length, |
| 35 | + sources: links |
| 36 | + .filter((link) => link.target_id === host.id) |
| 37 | + .map((link) => `${link.origin_id}:${link.origin_slot}`) |
| 38 | + .sort(), |
| 39 | + saveImageFedByHost: |
| 40 | + links.find((link) => String(link.target_id) === '9') |
| 41 | + ?.origin_id === host.id |
| 42 | + } |
| 43 | + }) |
| 44 | + ) |
| 45 | + .toEqual({ |
| 46 | + rootLinkCount: 6, |
| 47 | + inputCount: 5, |
| 48 | + outputCount: 1, |
| 49 | + unconnectedInputs: 0, |
| 50 | + sources: ['4:0', '4:2', '5:0', '6:0', '7:0'], |
| 51 | + saveImageFedByHost: true |
| 52 | + }) |
| 53 | + }) |
| 54 | + |
| 55 | + test('lands each boundary link on a type-compatible slot', async ({ |
| 56 | + comfyPage |
| 57 | + }) => { |
| 58 | + await expect |
| 59 | + .poll(() => |
| 60 | + comfyPage.page.evaluate(() => { |
| 61 | + const graph = window.app!.graph! |
| 62 | + const host = graph.nodes.find((node) => node.isSubgraphNode()) |
| 63 | + if (!host) return ['no subgraph node'] |
| 64 | + |
| 65 | + return [...graph.links.values()] |
| 66 | + .filter((link) => link.target_id === host.id) |
| 67 | + .filter( |
| 68 | + (link) => host.inputs[link.target_slot]?.type !== link.type |
| 69 | + ) |
| 70 | + .map( |
| 71 | + (link) => |
| 72 | + `${link.type} link landed on slot ${link.target_slot} typed ${host.inputs[link.target_slot]?.type}` |
| 73 | + ) |
| 74 | + }) |
| 75 | + ) |
| 76 | + .toEqual([]) |
| 77 | + }) |
| 78 | + |
| 79 | + test('preserves the rewiring across a save and reload', async ({ |
| 80 | + comfyPage |
| 81 | + }) => { |
| 82 | + const serialisedLinks = () => |
| 83 | + comfyPage.page.evaluate(() => |
| 84 | + [...window.app!.graph!.links.values()] |
| 85 | + .map( |
| 86 | + (link) => |
| 87 | + `${link.origin_id}:${link.origin_slot}->${link.target_id}:${link.target_slot}` |
| 88 | + ) |
| 89 | + .sort() |
| 90 | + ) |
| 91 | + |
| 92 | + const beforeReload = await serialisedLinks() |
| 93 | + await comfyPage.nodeOps.loadGraph( |
| 94 | + await comfyPage.nodeOps.getSerializedGraph() |
| 95 | + ) |
| 96 | + |
| 97 | + await expect.poll(serialisedLinks).toEqual(beforeReload) |
| 98 | + }) |
| 99 | + } |
| 100 | +) |
0 commit comments