From e4110dd254e79f496a1aa67e7a784a83a3d2668e Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Sat, 20 Dec 2025 15:40:21 -0800 Subject: [PATCH 1/6] fix: QPO progress bar now shows node name in subgraphs --- src/stores/executionStore.ts | 24 +-- .../executionStore.executingNode.test.ts | 157 ++++++++++++++++++ 2 files changed, 165 insertions(+), 16 deletions(-) create mode 100644 tests-ui/tests/store/executionStore.executingNode.test.ts diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index b9f89c29a11..57b52bf67ba 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -7,11 +7,7 @@ import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore' import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore' -import type { - ComfyNode, - ComfyWorkflowJSON, - NodeId -} from '@/platform/workflow/validation/schemas/workflowSchema' +import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import type { ExecutedWsMessage, @@ -194,20 +190,16 @@ export const useExecutionStore = defineStore('execution', () => { ) // For backward compatibility - returns the primary executing node - const executingNode = computed(() => { + const executingNode = computed(() => { if (!executingNodeId.value) return null - const workflow: ComfyWorkflow | undefined = activePrompt.value?.workflow - if (!workflow) return null - - const canvasState: ComfyWorkflowJSON | null = - workflow.changeTracker?.activeState ?? null - if (!canvasState) return null - - return ( - canvasState.nodes.find((n) => String(n.id) === executingNodeId.value) ?? - null + // Use getNodeByExecutionId to find nodes even in subgraphs + // executingNodeId may be a simple ID like "123" or a hierarchical ID like "123:456" + const node = getNodeByExecutionId( + app.rootGraph, + String(executingNodeId.value) ) + return node ?? null }) // This is the progress of the currently executing node (for backward compatibility) diff --git a/tests-ui/tests/store/executionStore.executingNode.test.ts b/tests-ui/tests/store/executionStore.executingNode.test.ts new file mode 100644 index 00000000000..f242eb2dff6 --- /dev/null +++ b/tests-ui/tests/store/executionStore.executingNode.test.ts @@ -0,0 +1,157 @@ +import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import { useExecutionStore } from '@/stores/executionStore' + +// Create mock functions +const mockNodeExecutionIdToNodeLocatorId = vi.fn() +const mockNodeIdToNodeLocatorId = vi.fn() +const mockNodeLocatorIdToNodeExecutionId = vi.fn() + +// Create a mocked graph that we can manipulate +let mockRootGraph: any + +// Mock the app import with proper implementation +vi.mock('@/scripts/app', () => ({ + app: { + get rootGraph() { + return mockRootGraph + }, + revokePreviews: vi.fn(), + nodePreviewImages: {} + } +})) + +// Mock the workflowStore +vi.mock('@/platform/workflow/management/stores/workflowStore', async () => { + const { ComfyWorkflow } = await vi.importActual< + typeof import('@/platform/workflow/management/stores/workflowStore') + >('@/platform/workflow/management/stores/workflowStore') + return { + ComfyWorkflow, + useWorkflowStore: vi.fn(() => ({ + nodeExecutionIdToNodeLocatorId: mockNodeExecutionIdToNodeLocatorId, + nodeIdToNodeLocatorId: mockNodeIdToNodeLocatorId, + nodeLocatorIdToNodeExecutionId: mockNodeLocatorIdToNodeExecutionId + })) + } +}) + +vi.mock('@/composables/node/useNodeProgressText', () => ({ + useNodeProgressText: () => ({ + showTextPreview: vi.fn() + }) +})) + +describe('useExecutionStore - executingNode with subgraphs', () => { + beforeEach(() => { + setActivePinia(createPinia()) + vi.clearAllMocks() + + // Reset the mock root graph + mockRootGraph = { + getNodeById: vi.fn(), + nodes: [] + } + }) + + it('should find executing node in root graph', () => { + const mockNode = { + id: '123', + title: 'Test Node', + type: 'TestNode' + } as LGraphNode + + mockRootGraph.getNodeById = vi.fn((id) => { + return id === '123' ? mockNode : null + }) + + const store = useExecutionStore() + + // Simulate node execution starting + store.nodeProgressStates = { + '123': { + state: 'running', + value: 0, + max: 100, + display_node_id: '123', + prompt_id: 'test-prompt', + node_id: '123' + } + } + + expect(store.executingNode).toBe(mockNode) + }) + + it('should find executing node in subgraph using execution ID', () => { + const mockNodeInSubgraph = { + id: '789', + title: 'Nested Node', + type: 'NestedNode' + } as LGraphNode + + const mockSubgraphNode = { + id: '456', + title: 'Node In Subgraph', + type: 'SubgraphNode', + isSubgraphNode: () => true, + subgraph: { + id: 'sub-uuid', + getNodeById: vi.fn((id) => { + return id === '789' ? mockNodeInSubgraph : null + }), + _nodes: [] + } + } as unknown as LGraphNode + + // Mock the graph traversal + mockRootGraph.getNodeById = vi.fn((id) => { + return id === '456' ? mockSubgraphNode : null + }) + + const store = useExecutionStore() + + // Simulate node execution in subgraph with hierarchical execution ID "456:789" + store.nodeProgressStates = { + '456:789': { + state: 'running', + value: 0, + max: 100, + display_node_id: '456:789', + prompt_id: 'test-prompt', + node_id: '456:789' + } + } + + // The executingNode should resolve to the nested node + expect(store.executingNode).toBe(mockNodeInSubgraph) + }) + + it('should return null when no node is executing', () => { + const store = useExecutionStore() + + store.nodeProgressStates = {} + + expect(store.executingNode).toBeNull() + }) + + it('should return null when executing node cannot be found', () => { + mockRootGraph.getNodeById = vi.fn(() => null) + + const store = useExecutionStore() + + store.nodeProgressStates = { + '999': { + state: 'running', + value: 0, + max: 100, + display_node_id: '999', + prompt_id: 'test-prompt', + node_id: '999' + } + } + + expect(store.executingNode).toBeNull() + }) +}) From a8458c6508ef443ef66a7e2845f7ba12c9092a7b Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Fri, 26 Dec 2025 14:14:16 -0800 Subject: [PATCH 2/6] fix: code review items has been aligned --- .../executionStore.executingNode.test.ts | 106 +++++++++++------- 1 file changed, 66 insertions(+), 40 deletions(-) diff --git a/tests-ui/tests/store/executionStore.executingNode.test.ts b/tests-ui/tests/store/executionStore.executingNode.test.ts index f242eb2dff6..f88909b1ee5 100644 --- a/tests-ui/tests/store/executionStore.executingNode.test.ts +++ b/tests-ui/tests/store/executionStore.executingNode.test.ts @@ -1,22 +1,54 @@ import { createPinia, setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import type { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph' import { useExecutionStore } from '@/stores/executionStore' +// Mock factory function to create a root graph +const createMockRootGraph = ( + options: Partial> = {} +): Partial => ({ + getNodeById: options.getNodeById ?? vi.fn(() => null), + nodes: options.nodes ?? [], + ...options +}) + +// Mock factory function to create a subgraph node +const createMockSubgraphNode = ( + nodeId: string, + subgraphNodeId: string, + innerNode: LGraphNode +): LGraphNode => + ({ + id: nodeId, + title: 'Node In Subgraph', + type: 'SubgraphNode', + isSubgraphNode: (() => true) as any, + subgraph: { + id: 'sub-uuid', + getNodeById: vi.fn((id) => (id === subgraphNodeId ? innerNode : null)), + _nodes: [] + } as Partial + }) as unknown as LGraphNode + // Create mock functions const mockNodeExecutionIdToNodeLocatorId = vi.fn() const mockNodeIdToNodeLocatorId = vi.fn() const mockNodeLocatorIdToNodeExecutionId = vi.fn() -// Create a mocked graph that we can manipulate -let mockRootGraph: any +// Keep track of the current mock root graph +const mockAppState = { + rootGraph: createMockRootGraph() +} // Mock the app import with proper implementation vi.mock('@/scripts/app', () => ({ app: { get rootGraph() { - return mockRootGraph + return mockAppState.rootGraph + }, + set rootGraph(value) { + mockAppState.rootGraph = value }, revokePreviews: vi.fn(), nodePreviewImages: {} @@ -24,19 +56,23 @@ vi.mock('@/scripts/app', () => ({ })) // Mock the workflowStore -vi.mock('@/platform/workflow/management/stores/workflowStore', async () => { - const { ComfyWorkflow } = await vi.importActual< - typeof import('@/platform/workflow/management/stores/workflowStore') - >('@/platform/workflow/management/stores/workflowStore') - return { - ComfyWorkflow, - useWorkflowStore: vi.fn(() => ({ - nodeExecutionIdToNodeLocatorId: mockNodeExecutionIdToNodeLocatorId, - nodeIdToNodeLocatorId: mockNodeIdToNodeLocatorId, - nodeLocatorIdToNodeExecutionId: mockNodeLocatorIdToNodeExecutionId - })) +vi.mock( + '@/platform/workflow/management/stores/workflowStore', + async (importOriginal) => { + const { ComfyWorkflow } = + await importOriginal< + typeof import('@/platform/workflow/management/stores/workflowStore') + >() + return { + ComfyWorkflow, + useWorkflowStore: vi.fn(() => ({ + nodeExecutionIdToNodeLocatorId: mockNodeExecutionIdToNodeLocatorId, + nodeIdToNodeLocatorId: mockNodeIdToNodeLocatorId, + nodeLocatorIdToNodeExecutionId: mockNodeLocatorIdToNodeExecutionId + })) + } } -}) +) vi.mock('@/composables/node/useNodeProgressText', () => ({ useNodeProgressText: () => ({ @@ -49,11 +85,8 @@ describe('useExecutionStore - executingNode with subgraphs', () => { setActivePinia(createPinia()) vi.clearAllMocks() - // Reset the mock root graph - mockRootGraph = { - getNodeById: vi.fn(), - nodes: [] - } + // Reset the mock root graph using factory + mockAppState.rootGraph = createMockRootGraph() }) it('should find executing node in root graph', () => { @@ -63,8 +96,8 @@ describe('useExecutionStore - executingNode with subgraphs', () => { type: 'TestNode' } as LGraphNode - mockRootGraph.getNodeById = vi.fn((id) => { - return id === '123' ? mockNode : null + mockAppState.rootGraph = createMockRootGraph({ + getNodeById: vi.fn((id) => (id === '123' ? mockNode : null)) }) const store = useExecutionStore() @@ -91,23 +124,14 @@ describe('useExecutionStore - executingNode with subgraphs', () => { type: 'NestedNode' } as LGraphNode - const mockSubgraphNode = { - id: '456', - title: 'Node In Subgraph', - type: 'SubgraphNode', - isSubgraphNode: () => true, - subgraph: { - id: 'sub-uuid', - getNodeById: vi.fn((id) => { - return id === '789' ? mockNodeInSubgraph : null - }), - _nodes: [] - } - } as unknown as LGraphNode + const mockSubgraphNode = createMockSubgraphNode( + '456', + '789', + mockNodeInSubgraph + ) as LGraphNode - // Mock the graph traversal - mockRootGraph.getNodeById = vi.fn((id) => { - return id === '456' ? mockSubgraphNode : null + mockAppState.rootGraph = createMockRootGraph({ + getNodeById: vi.fn((id) => (id === '456' ? mockSubgraphNode : null)) }) const store = useExecutionStore() @@ -137,7 +161,9 @@ describe('useExecutionStore - executingNode with subgraphs', () => { }) it('should return null when executing node cannot be found', () => { - mockRootGraph.getNodeById = vi.fn(() => null) + mockAppState.rootGraph = createMockRootGraph({ + getNodeById: vi.fn(() => null) + }) const store = useExecutionStore() From bd1e15ad70bbb392e0574f312493f13bc250a425 Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Fri, 26 Dec 2025 14:43:08 -0800 Subject: [PATCH 3/6] refactor: using test helpers --- .../executionStore.executingNode.test.ts | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/tests-ui/tests/store/executionStore.executingNode.test.ts b/tests-ui/tests/store/executionStore.executingNode.test.ts index f88909b1ee5..0fbec3367f5 100644 --- a/tests-ui/tests/store/executionStore.executingNode.test.ts +++ b/tests-ui/tests/store/executionStore.executingNode.test.ts @@ -3,6 +3,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import type { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph' import { useExecutionStore } from '@/stores/executionStore' +import { + createTestSubgraph, + createTestSubgraphNode +} from '../litegraph/subgraph/fixtures/subgraphHelpers' // Mock factory function to create a root graph const createMockRootGraph = ( @@ -13,24 +17,6 @@ const createMockRootGraph = ( ...options }) -// Mock factory function to create a subgraph node -const createMockSubgraphNode = ( - nodeId: string, - subgraphNodeId: string, - innerNode: LGraphNode -): LGraphNode => - ({ - id: nodeId, - title: 'Node In Subgraph', - type: 'SubgraphNode', - isSubgraphNode: (() => true) as any, - subgraph: { - id: 'sub-uuid', - getNodeById: vi.fn((id) => (id === subgraphNodeId ? innerNode : null)), - _nodes: [] - } as Partial - }) as unknown as LGraphNode - // Create mock functions const mockNodeExecutionIdToNodeLocatorId = vi.fn() const mockNodeIdToNodeLocatorId = vi.fn() @@ -41,7 +27,7 @@ const mockAppState = { rootGraph: createMockRootGraph() } -// Mock the app import with proper implementation +// Mock the app import and its rootGraph property vi.mock('@/scripts/app', () => ({ app: { get rootGraph() { @@ -124,11 +110,23 @@ describe('useExecutionStore - executingNode with subgraphs', () => { type: 'NestedNode' } as LGraphNode - const mockSubgraphNode = createMockSubgraphNode( - '456', - '789', - mockNodeInSubgraph - ) as LGraphNode + // Create a real subgraph with the test helper + const testSubgraph = createTestSubgraph({ + id: 'sub-uuid' + }) + // Add the mock node to the subgraph + testSubgraph._nodes.push(mockNodeInSubgraph) + + // Create a subgraph node using the helper + const mockSubgraphNode = createTestSubgraphNode(testSubgraph, { + id: '456' + }) + + // Mock the subgraph's getNodeById to return our mock node + vi.spyOn(testSubgraph, 'getNodeById').mockImplementation( + (id: string | number | null | undefined) => + id === '789' ? mockNodeInSubgraph : null + ) mockAppState.rootGraph = createMockRootGraph({ getNodeById: vi.fn((id) => (id === '456' ? mockSubgraphNode : null)) From 1bfd61726570548749549f9e1f708103d83138fa Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Fri, 2 Jan 2026 14:17:38 -0800 Subject: [PATCH 4/6] refactor: moving mock functions out of global --- .../tests/store/executionStore.executingNode.test.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests-ui/tests/store/executionStore.executingNode.test.ts b/tests-ui/tests/store/executionStore.executingNode.test.ts index 0fbec3367f5..005ecc08424 100644 --- a/tests-ui/tests/store/executionStore.executingNode.test.ts +++ b/tests-ui/tests/store/executionStore.executingNode.test.ts @@ -17,16 +17,10 @@ const createMockRootGraph = ( ...options }) -// Create mock functions -const mockNodeExecutionIdToNodeLocatorId = vi.fn() -const mockNodeIdToNodeLocatorId = vi.fn() -const mockNodeLocatorIdToNodeExecutionId = vi.fn() - // Keep track of the current mock root graph const mockAppState = { rootGraph: createMockRootGraph() } - // Mock the app import and its rootGraph property vi.mock('@/scripts/app', () => ({ app: { @@ -40,7 +34,6 @@ vi.mock('@/scripts/app', () => ({ nodePreviewImages: {} } })) - // Mock the workflowStore vi.mock( '@/platform/workflow/management/stores/workflowStore', @@ -49,6 +42,10 @@ vi.mock( await importOriginal< typeof import('@/platform/workflow/management/stores/workflowStore') >() + const mockNodeExecutionIdToNodeLocatorId = vi.fn() + const mockNodeIdToNodeLocatorId = vi.fn() + const mockNodeLocatorIdToNodeExecutionId = vi.fn() + return { ComfyWorkflow, useWorkflowStore: vi.fn(() => ({ From 6866bd47925c651bb87f97bdff6cc50d7a2c90e3 Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Fri, 2 Jan 2026 14:46:01 -0800 Subject: [PATCH 5/6] refactor: moved all the tests into the main executionstore test file --- .../executionStore.executingNode.test.ts | 178 ------------------ tests-ui/tests/store/executionStore.test.ts | 106 +++++++++++ 2 files changed, 106 insertions(+), 178 deletions(-) delete mode 100644 tests-ui/tests/store/executionStore.executingNode.test.ts diff --git a/tests-ui/tests/store/executionStore.executingNode.test.ts b/tests-ui/tests/store/executionStore.executingNode.test.ts deleted file mode 100644 index 005ecc08424..00000000000 --- a/tests-ui/tests/store/executionStore.executingNode.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { createPinia, setActivePinia } from 'pinia' -import { beforeEach, describe, expect, it, vi } from 'vitest' - -import type { LGraph, LGraphNode } from '@/lib/litegraph/src/litegraph' -import { useExecutionStore } from '@/stores/executionStore' -import { - createTestSubgraph, - createTestSubgraphNode -} from '../litegraph/subgraph/fixtures/subgraphHelpers' - -// Mock factory function to create a root graph -const createMockRootGraph = ( - options: Partial> = {} -): Partial => ({ - getNodeById: options.getNodeById ?? vi.fn(() => null), - nodes: options.nodes ?? [], - ...options -}) - -// Keep track of the current mock root graph -const mockAppState = { - rootGraph: createMockRootGraph() -} -// Mock the app import and its rootGraph property -vi.mock('@/scripts/app', () => ({ - app: { - get rootGraph() { - return mockAppState.rootGraph - }, - set rootGraph(value) { - mockAppState.rootGraph = value - }, - revokePreviews: vi.fn(), - nodePreviewImages: {} - } -})) -// Mock the workflowStore -vi.mock( - '@/platform/workflow/management/stores/workflowStore', - async (importOriginal) => { - const { ComfyWorkflow } = - await importOriginal< - typeof import('@/platform/workflow/management/stores/workflowStore') - >() - const mockNodeExecutionIdToNodeLocatorId = vi.fn() - const mockNodeIdToNodeLocatorId = vi.fn() - const mockNodeLocatorIdToNodeExecutionId = vi.fn() - - return { - ComfyWorkflow, - useWorkflowStore: vi.fn(() => ({ - nodeExecutionIdToNodeLocatorId: mockNodeExecutionIdToNodeLocatorId, - nodeIdToNodeLocatorId: mockNodeIdToNodeLocatorId, - nodeLocatorIdToNodeExecutionId: mockNodeLocatorIdToNodeExecutionId - })) - } - } -) - -vi.mock('@/composables/node/useNodeProgressText', () => ({ - useNodeProgressText: () => ({ - showTextPreview: vi.fn() - }) -})) - -describe('useExecutionStore - executingNode with subgraphs', () => { - beforeEach(() => { - setActivePinia(createPinia()) - vi.clearAllMocks() - - // Reset the mock root graph using factory - mockAppState.rootGraph = createMockRootGraph() - }) - - it('should find executing node in root graph', () => { - const mockNode = { - id: '123', - title: 'Test Node', - type: 'TestNode' - } as LGraphNode - - mockAppState.rootGraph = createMockRootGraph({ - getNodeById: vi.fn((id) => (id === '123' ? mockNode : null)) - }) - - const store = useExecutionStore() - - // Simulate node execution starting - store.nodeProgressStates = { - '123': { - state: 'running', - value: 0, - max: 100, - display_node_id: '123', - prompt_id: 'test-prompt', - node_id: '123' - } - } - - expect(store.executingNode).toBe(mockNode) - }) - - it('should find executing node in subgraph using execution ID', () => { - const mockNodeInSubgraph = { - id: '789', - title: 'Nested Node', - type: 'NestedNode' - } as LGraphNode - - // Create a real subgraph with the test helper - const testSubgraph = createTestSubgraph({ - id: 'sub-uuid' - }) - // Add the mock node to the subgraph - testSubgraph._nodes.push(mockNodeInSubgraph) - - // Create a subgraph node using the helper - const mockSubgraphNode = createTestSubgraphNode(testSubgraph, { - id: '456' - }) - - // Mock the subgraph's getNodeById to return our mock node - vi.spyOn(testSubgraph, 'getNodeById').mockImplementation( - (id: string | number | null | undefined) => - id === '789' ? mockNodeInSubgraph : null - ) - - mockAppState.rootGraph = createMockRootGraph({ - getNodeById: vi.fn((id) => (id === '456' ? mockSubgraphNode : null)) - }) - - const store = useExecutionStore() - - // Simulate node execution in subgraph with hierarchical execution ID "456:789" - store.nodeProgressStates = { - '456:789': { - state: 'running', - value: 0, - max: 100, - display_node_id: '456:789', - prompt_id: 'test-prompt', - node_id: '456:789' - } - } - - // The executingNode should resolve to the nested node - expect(store.executingNode).toBe(mockNodeInSubgraph) - }) - - it('should return null when no node is executing', () => { - const store = useExecutionStore() - - store.nodeProgressStates = {} - - expect(store.executingNode).toBeNull() - }) - - it('should return null when executing node cannot be found', () => { - mockAppState.rootGraph = createMockRootGraph({ - getNodeById: vi.fn(() => null) - }) - - const store = useExecutionStore() - - store.nodeProgressStates = { - '999': { - state: 'running', - value: 0, - max: 100, - display_node_id: '999', - prompt_id: 'test-prompt', - node_id: '999' - } - } - - expect(store.executingNode).toBeNull() - }) -}) diff --git a/tests-ui/tests/store/executionStore.test.ts b/tests-ui/tests/store/executionStore.test.ts index 7c893bd6016..7b192f78558 100644 --- a/tests-ui/tests/store/executionStore.test.ts +++ b/tests-ui/tests/store/executionStore.test.ts @@ -4,6 +4,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { app } from '@/scripts/app' import { useExecutionStore } from '@/stores/executionStore' +import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import { + createTestSubgraph, + createTestSubgraphNode +} from '../litegraph/subgraph/fixtures/subgraphHelpers' + // Create mock functions that will be shared const mockNodeExecutionIdToNodeLocatorId = vi.fn() const mockNodeIdToNodeLocatorId = vi.fn() @@ -297,3 +303,103 @@ describe('useExecutionStore - Node Error Lookups', () => { }) }) }) + +describe('useExecutionStore - executingNode with subgraphs', () => { + let store: ReturnType + + beforeEach(() => { + vi.clearAllMocks() + setActivePinia(createPinia()) + store = useExecutionStore() + }) + + it('should find executing node in root graph', () => { + const mockNode = { + id: '123', + title: 'Test Node', + type: 'TestNode' + } as LGraphNode + + vi.mocked(app.rootGraph.getNodeById).mockReturnValue(mockNode) + + // Simulate node execution starting + store.nodeProgressStates = { + '123': { + state: 'running', + value: 0, + max: 100, + display_node_id: '123', + prompt_id: 'test-prompt', + node_id: '123' + } + } + + expect(store.executingNode).toBe(mockNode) + }) + + it('should find executing node in subgraph using execution ID', () => { + const mockNodeInSubgraph = { + id: '789', + title: 'Nested Node', + type: 'NestedNode' + } as LGraphNode + + // Create a real subgraph with the test helper + const testSubgraph = createTestSubgraph({ + id: 'sub-uuid' + }) + // Add the mock node to the subgraph + testSubgraph._nodes.push(mockNodeInSubgraph) + + // Create a subgraph node using the helper + const mockSubgraphNode = createTestSubgraphNode(testSubgraph, { + id: '456' + }) + + // Mock the subgraph's getNodeById to return our mock node + vi.spyOn(testSubgraph, 'getNodeById').mockImplementation( + (id: string | number | null | undefined) => + id === '789' ? mockNodeInSubgraph : null + ) + + vi.mocked(app.rootGraph.getNodeById).mockReturnValue(mockSubgraphNode) + + // Simulate node execution in subgraph with hierarchical execution ID "456:789" + store.nodeProgressStates = { + '456:789': { + state: 'running', + value: 0, + max: 100, + display_node_id: '456:789', + prompt_id: 'test-prompt', + node_id: '456:789' + } + } + + // The executingNode should resolve to the nested node + expect(store.executingNode).toBe(mockNodeInSubgraph) + }) + + it('should return null when no node is executing', () => { + store.nodeProgressStates = {} + + expect(store.executingNode).toBeNull() + }) + + it('should return null when executing node cannot be found', () => { + vi.mocked(app.rootGraph.getNodeById).mockReturnValue(null) + + store.nodeProgressStates = { + '999': { + state: 'running', + value: 0, + max: 100, + display_node_id: '999', + prompt_id: 'test-prompt', + node_id: '999' + } + } + + expect(store.executingNode).toBeNull() + }) +}) From 530717983fbb769a3671fc7149ff5c758ddcd07b Mon Sep 17 00:00:00 2001 From: Csongor Czezar Date: Fri, 2 Jan 2026 15:00:56 -0800 Subject: [PATCH 6/6] fix: use public api --- tests-ui/tests/store/executionStore.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-ui/tests/store/executionStore.test.ts b/tests-ui/tests/store/executionStore.test.ts index 7b192f78558..89d4ff21890 100644 --- a/tests-ui/tests/store/executionStore.test.ts +++ b/tests-ui/tests/store/executionStore.test.ts @@ -349,7 +349,7 @@ describe('useExecutionStore - executingNode with subgraphs', () => { id: 'sub-uuid' }) // Add the mock node to the subgraph - testSubgraph._nodes.push(mockNodeInSubgraph) + testSubgraph.add(mockNodeInSubgraph) // Create a subgraph node using the helper const mockSubgraphNode = createTestSubgraphNode(testSubgraph, {