mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## 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>
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import type { MaybeRefOrGetter } from 'vue'
|
|
import { computed, toValue } from 'vue'
|
|
|
|
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
|
import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
|
|
import { useNodeOutputStore } from '@/stores/nodeOutputStore'
|
|
import { usePromotionStore } from '@/stores/promotionStore'
|
|
import { createNodeLocatorId } from '@/types/nodeIdentification'
|
|
|
|
interface PromotedPreview {
|
|
sourceNodeId: string
|
|
sourceWidgetName: string
|
|
type: 'image' | 'video' | 'audio'
|
|
urls: string[]
|
|
}
|
|
|
|
/**
|
|
* Returns reactive preview media from promoted `$$` pseudo-widgets
|
|
* on a SubgraphNode. Each promoted preview interior node produces
|
|
* a separate entry so they render independently.
|
|
*/
|
|
export function usePromotedPreviews(
|
|
lgraphNode: MaybeRefOrGetter<LGraphNode | null | undefined>
|
|
) {
|
|
const promotionStore = usePromotionStore()
|
|
const nodeOutputStore = useNodeOutputStore()
|
|
|
|
const promotedPreviews = computed((): PromotedPreview[] => {
|
|
const node = toValue(lgraphNode)
|
|
if (!(node instanceof SubgraphNode)) return []
|
|
|
|
const entries = promotionStore.getPromotions(node.rootGraph.id, node.id)
|
|
const pseudoEntries = entries.filter((e) =>
|
|
e.sourceWidgetName.startsWith('$$')
|
|
)
|
|
if (!pseudoEntries.length) return []
|
|
|
|
const previews: PromotedPreview[] = []
|
|
|
|
for (const entry of pseudoEntries) {
|
|
const interiorNode = node.subgraph.getNodeById(entry.sourceNodeId)
|
|
if (!interiorNode) continue
|
|
|
|
// Read from both reactive refs to establish Vue dependency
|
|
// tracking. getNodeImageUrls reads from non-reactive
|
|
// app.nodeOutputs / app.nodePreviewImages, so without this
|
|
// access the computed would never re-evaluate.
|
|
const locatorId = createNodeLocatorId(
|
|
node.subgraph.id,
|
|
entry.sourceNodeId
|
|
)
|
|
const reactiveOutputs = nodeOutputStore.nodeOutputs[locatorId]
|
|
const reactivePreviews = nodeOutputStore.nodePreviewImages[locatorId]
|
|
if (!reactiveOutputs?.images?.length && !reactivePreviews?.length)
|
|
continue
|
|
|
|
const urls = nodeOutputStore.getNodeImageUrls(interiorNode)
|
|
if (!urls?.length) continue
|
|
|
|
const type =
|
|
interiorNode.previewMediaType === 'video'
|
|
? 'video'
|
|
: interiorNode.previewMediaType === 'audio'
|
|
? 'audio'
|
|
: 'image'
|
|
|
|
previews.push({
|
|
sourceNodeId: entry.sourceNodeId,
|
|
sourceWidgetName: entry.sourceWidgetName,
|
|
type,
|
|
urls
|
|
})
|
|
}
|
|
|
|
return previews
|
|
})
|
|
|
|
return { promotedPreviews }
|
|
}
|