Compare commits

...

6 Commits

Author SHA1 Message Date
bymyself
d1e43d1a46 fix: adapt round-trip test and comment to current domWidgetStore API
The positionOverride store API was removed upstream. Rewrite the unit
test to exercise the same graph→app→graph visibility restoration with a
single active node, and drop the stale positionOverride reference from
the watcher comment.
2026-06-26 15:07:59 -07:00
bymyself
d0e83a56fa Merge remote-tracking branch 'origin/main' into fix/1.42-promoted-widgets-invisible
# Conflicts:
#	browser_tests/tests/subgraph/subgraphPromotionDom.spec.ts
#	src/components/graph/DomWidgets.test.ts
2026-06-26 15:02:38 -07:00
Christian Byrne
0921ec370b Merge branch 'main' into fix/1.42-promoted-widgets-invisible 2026-04-17 20:21:09 -07:00
bymyself
9556b5e333 fix: assert updateWidgets is called on mode switch
Addresses review feedback:
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10999#discussion_r3061095500
2026-04-10 17:50:39 -07:00
bymyself
ec4cdaaede fix: use toggleAppMode() instead of page.evaluate for mode switching
Addresses review feedback:
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10999#discussion_r3061070200
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10999#discussion_r3061079965
2026-04-10 17:50:04 -07:00
bymyself
bfc19dc80d fix: restore promoted widget visibility after graph→app→graph round-trip
Promoted DOM widgets on SubgraphNodes become invisible after switching
from graph mode to app mode and back. The canvas is hidden via v-show
during app mode, so updateWidgets() never runs and widgetState.visible
stays stale (false).

Add a watcher that calls updateWidgets() when leaving linear/app mode
so promoted widgets with positionOverride are correctly marked visible.
2026-04-09 14:39:16 -07:00
3 changed files with 101 additions and 0 deletions

View File

@@ -165,5 +165,39 @@ test.describe(
})
}
)
test.describe('App Mode Round-Trip', { tag: ['@vue-nodes'] }, () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.appMode.enableLinearMode()
await comfyPage.appMode.suppressVueNodeSwitchPopup()
})
test('Promoted DOM widget stays visible after graph → app → graph round-trip', async ({
comfyPage
}) => {
await comfyPage.workflow.loadWorkflow(
'subgraphs/subgraph-with-promoted-text-widget'
)
const promotedTextarea = comfyPage.vueNodes
.getNodeLocator('11')
.getByRole('textbox', { name: 'text' })
await expect(promotedTextarea).toBeVisible()
const graphContainer = comfyPage.page.locator('#graph-canvas-container')
// Enter app mode — the canvas is hidden via v-show, so updateWidgets()
// never runs and widgetState.visible goes stale.
await comfyPage.appMode.toggleAppMode()
await expect(graphContainer).toBeHidden()
// Return to graph mode — the whenever watcher must restore visibility.
await comfyPage.appMode.toggleAppMode()
await expect(graphContainer).toBeVisible()
await expect(promotedTextarea).toBeVisible()
await expect(promotedTextarea).toHaveCount(1)
})
})
}
)

View File

@@ -2,12 +2,17 @@ import { createTestingPinia } from '@pinia/testing'
import { fromPartial } from '@total-typescript/shoehorn'
import { render } from '@testing-library/vue'
import { setActivePinia } from 'pinia'
import { nextTick } from 'vue'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import DomWidgets from '@/components/graph/DomWidgets.vue'
import { useAppMode } from '@/composables/useAppMode'
import { Rectangle } from '@/lib/litegraph/src/infrastructure/Rectangle'
import { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph'
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
import type { LoadedComfyWorkflow } from '@/platform/workflow/management/stores/comfyWorkflow'
import { ComfyWorkflow } from '@/platform/workflow/management/stores/comfyWorkflow'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import type { BaseDOMWidget } from '@/scripts/domWidget'
import { useDomWidgetStore } from '@/stores/domWidgetStore'
@@ -57,6 +62,62 @@ function drawFrame(canvas: LGraphCanvas) {
canvas.onDrawForeground?.({} as CanvasRenderingContext2D, new Rectangle())
}
describe('DomWidgets app mode round-trip', () => {
beforeEach(() => {
setActivePinia(createTestingPinia({ stubActions: false }))
})
it('restores promoted widget visibility after graph → app → graph', async () => {
const canvasStore = useCanvasStore()
const domWidgetStore = useDomWidgetStore()
const { setMode } = useAppMode()
// Set up an active workflow so linearMode is driven by activeMode
const workflowStore = useWorkflowStore()
const workflow = new ComfyWorkflow({
path: 'workflows/test.json',
modified: Date.now(),
size: 1
})
workflow.activeMode = 'graph'
workflowStore.activeWorkflow = workflow as unknown as LoadedComfyWorkflow
const graph = new LGraph()
const node = createNode(graph, 1, 'host', [100, 200])
const widget = createWidget('round-trip-widget', node, 14)
domWidgetStore.registerWidget(widget)
const canvas = createCanvas(graph)
canvasStore.canvas = canvas
render(DomWidgets, {
global: { stubs: { DomWidget: true } }
})
// Initial draw — widget visible
drawFrame(canvas)
const widgetState = domWidgetStore.widgetStates.get(widget.id)!
expect(widgetState.visible).toBe(true)
// Enter app mode — canvas is hidden, no more draw calls
setMode('app')
await nextTick()
// Simulate stale visibility from lack of draw calls during app mode
// (in production, v-show hides the canvas so updateWidgets doesn't run)
widgetState.visible = false
vi.mocked(canvas.isNodeVisible).mockClear()
// Return to graph mode
setMode('graph')
await nextTick()
// The whenever watcher should have called updateWidgets automatically
expect(canvas.isNodeVisible).toHaveBeenCalled()
expect(widgetState.visible).toBe(true)
})
})
describe('DomWidgets positioning', () => {
beforeEach(() => {
setActivePinia(createTestingPinia({ stubActions: false }))

View File

@@ -75,4 +75,10 @@ whenever(
)),
{ immediate: true }
)
// When returning from app mode, the canvas was hidden (v-show) so
// updateWidgets() hasn't run — widgetState.visible is stale.
// Run it immediately so widgets are correctly marked visible before
// DomWidget tries to mount elements.
whenever(() => !canvasStore.linearMode, updateWidgets)
</script>