Compare commits

...

8 Commits

Author SHA1 Message Date
Benjamin Lu
fafaba09d1 Merge origin/main into qpo-progressbar-node-name 2026-03-06 14:08:19 -08:00
Alexander Brown
f349184290 Merge branch 'main' into qpo-progressbar-node-name 2026-01-05 16:06:03 -08:00
Csongor Czezar
530717983f fix: use public api 2026-01-02 15:00:56 -08:00
Csongor Czezar
6866bd4792 refactor: moved all the tests into the main executionstore test file 2026-01-02 14:46:01 -08:00
Csongor Czezar
1bfd617265 refactor: moving mock functions out of global 2026-01-02 14:17:38 -08:00
Csongor Czezar
bd1e15ad70 refactor: using test helpers 2026-01-02 13:52:05 -08:00
Csongor Czezar
a8458c6508 fix: code review items has been aligned 2026-01-02 13:52:05 -08:00
Csongor Czezar
e4110dd254 fix: QPO progress bar now shows node name in subgraphs 2026-01-02 13:52:04 -08:00
3 changed files with 106 additions and 20 deletions

View File

@@ -65,7 +65,6 @@ describe('ComfyApp.getNodeDefs', () => {
const result = await comfyApp.getNodeDefs()
// When display_name is empty, should fall back to name
expect(result.TestNode.display_name).toBe('TestNode')
})
@@ -84,7 +83,6 @@ describe('ComfyApp.getNodeDefs', () => {
}
vi.mocked(api.getNodeDefs).mockResolvedValue(mockNodeDefs)
// Mock st to return a translation instead of fallback
vi.mocked(st).mockReturnValue('Translated Display Name')
const result = await comfyApp.getNodeDefs()

View File

@@ -1,6 +1,11 @@
import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { app } from '@/scripts/app'
import {
createTestSubgraph,
createTestSubgraphNode
} from '@/lib/litegraph/src/subgraph/__fixtures__/subgraphHelpers'
import { useExecutionStore } from '@/stores/executionStore'
import { useExecutionErrorStore } from '@/stores/executionErrorStore'
import { executionIdToNodeLocatorId } from '@/utils/graphTraversalUtil'
@@ -346,6 +351,100 @@ describe('useExecutionErrorStore - Node Error Lookups', () => {
})
})
describe('useExecutionStore - executingNode with subgraphs', () => {
let store: ReturnType<typeof useExecutionStore>
beforeEach(() => {
vi.clearAllMocks()
setActivePinia(createTestingPinia({ stubActions: false }))
store = useExecutionStore()
})
it('should find executing node in root graph', () => {
const mockNode = createMockLGraphNode({
id: '123',
title: 'Test Node',
type: 'TestNode'
})
vi.mocked(app.rootGraph.getNodeById).mockReturnValue(mockNode)
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 = createMockLGraphNode({
id: '789',
title: 'Nested Node',
type: 'NestedNode'
})
const testSubgraph = createTestSubgraph({
id: 'sub-uuid'
})
testSubgraph.add(mockNodeInSubgraph)
const mockSubgraphNode = createTestSubgraphNode(testSubgraph, {
id: '456'
})
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'
}
}
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()
})
})
describe('useExecutionErrorStore - setMissingNodeTypes', () => {
let store: ReturnType<typeof useExecutionErrorStore>

View File

@@ -6,11 +6,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,
@@ -32,7 +28,10 @@ import { useJobPreviewStore } from '@/stores/jobPreviewStore'
import { useExecutionErrorStore } from '@/stores/executionErrorStore'
import type { NodeLocatorId } from '@/types/nodeIdentification'
import { classifyCloudValidationError } from '@/utils/executionErrorUtil'
import { executionIdToNodeLocatorId } from '@/utils/graphTraversalUtil'
import {
executionIdToNodeLocatorId,
getNodeByExecutionId
} from '@/utils/graphTraversalUtil'
interface QueuedJob {
/**
@@ -142,20 +141,10 @@ export const useExecutionStore = defineStore('execution', () => {
)
// For backward compatibility - returns the primary executing node
const executingNode = computed<ComfyNode | null>(() => {
const executingNode = computed(() => {
if (!executingNodeId.value) return null
const workflow: ComfyWorkflow | undefined = activeJob.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
)
return getNodeByExecutionId(app.rootGraph, String(executingNodeId.value))
})
// This is the progress of the currently executing node (for backward compatibility)