diff --git a/src/stores/executionStore.test.ts b/src/stores/executionStore.test.ts index cf531463d4..535667cf9c 100644 --- a/src/stores/executionStore.test.ts +++ b/src/stores/executionStore.test.ts @@ -7,12 +7,21 @@ import { useMissingNodesErrorStore } from '@/platform/nodeReplacement/missingNod import { executionIdToNodeLocatorId } from '@/utils/graphTraversalUtil' // Create mock functions that will be shared -const mockNodeExecutionIdToNodeLocatorId = vi.fn() -const mockNodeIdToNodeLocatorId = vi.fn() -const mockNodeLocatorIdToNodeExecutionId = vi.fn() +const { + mockNodeExecutionIdToNodeLocatorId, + mockNodeIdToNodeLocatorId, + mockNodeLocatorIdToNodeExecutionId, + mockShowTextPreview +} = vi.hoisted(() => ({ + mockNodeExecutionIdToNodeLocatorId: vi.fn(), + mockNodeIdToNodeLocatorId: vi.fn(), + mockNodeLocatorIdToNodeExecutionId: vi.fn(), + mockShowTextPreview: vi.fn() +})) import type * as WorkflowStoreModule from '@/platform/workflow/management/stores/workflowStore' import type { NodeProgressState } from '@/schemas/apiSchema' +import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' import { createMockLGraphNode } from '@/utils/__tests__/litegraphTestUtils' import { createTestingPinia } from '@pinia/testing' @@ -38,7 +47,7 @@ declare global { vi.mock('@/composables/node/useNodeProgressText', () => ({ useNodeProgressText: () => ({ - showTextPreview: vi.fn() + showTextPreview: mockShowTextPreview }) })) @@ -431,6 +440,56 @@ describe('useExecutionStore - reconcileInitializingJobs', () => { }) }) +describe('useExecutionStore - progress_text startup guard', () => { + let store: ReturnType + + function fireProgressText(detail: { + nodeId: string + text: string + prompt_id?: string + }) { + const handler = apiEventHandlers.get('progress_text') + if (!handler) throw new Error('progress_text handler not bound') + handler(new CustomEvent('progress_text', { detail })) + } + + beforeEach(() => { + vi.clearAllMocks() + apiEventHandlers.clear() + setActivePinia(createTestingPinia({ stubActions: false })) + store = useExecutionStore() + store.bindExecutionEvents() + }) + + it('should ignore progress_text before the canvas is initialized', async () => { + const { useCanvasStore } = + await import('@/renderer/core/canvas/canvasStore') + useCanvasStore().canvas = null + + expect(() => + fireProgressText({ + nodeId: '1', + text: 'warming up' + }) + ).not.toThrow() + + expect(mockShowTextPreview).not.toHaveBeenCalled() + }) + + it('should call showTextPreview when canvas is available', async () => { + const mockNode = createMockLGraphNode({ id: 1 }) + const { useCanvasStore } = + await import('@/renderer/core/canvas/canvasStore') + useCanvasStore().canvas = { + graph: { getNodeById: vi.fn(() => mockNode) } + } as unknown as LGraphCanvas + + fireProgressText({ nodeId: '1', text: 'warming up' }) + + expect(mockShowTextPreview).toHaveBeenCalledWith(mockNode, 'warming up') + }) +}) + describe('useExecutionErrorStore - Node Error Lookups', () => { let store: ReturnType diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index bbe42f227a..f69490c7a6 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -527,7 +527,7 @@ export const useExecutionStore = defineStore('execution', () => { // Handle execution node IDs for subgraphs const currentId = getNodeIdIfExecuting(nodeId) if (!currentId) return - const node = canvasStore.getCanvas().graph?.getNodeById(currentId) + const node = canvasStore.canvas?.graph?.getNodeById(currentId) if (!node) return useNodeProgressText().showTextPreview(node, text)