From ddc36989a08b898a019a93d62dffa0eae5f674e6 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Tue, 17 Sep 2024 14:37:47 +0300 Subject: [PATCH] tests, review update --- packages/editor-ui/src/components/Node.vue | 14 ++- .../__tests__/useRunWorkflow.spec.ts | 100 +++++++++++++++++- .../src/plugins/i18n/locales/en.json | 3 +- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/packages/editor-ui/src/components/Node.vue b/packages/editor-ui/src/components/Node.vue index 948d918997..7c99fad935 100644 --- a/packages/editor-ui/src/components/Node.vue +++ b/packages/editor-ui/src/components/Node.vue @@ -321,7 +321,7 @@ const nodeTitle = computed(() => { const waiting = computed(() => { const workflowExecution = workflowsStore.getWorkflowExecution as ExecutionSummary; - if (workflowExecution?.waitTill && !workflowExecution?.finished) { + if (workflowExecution?.waitTill) { const lastNodeExecuted = get(workflowExecution, 'data.resultData.lastNodeExecuted'); if (props.name === lastNodeExecuted) { const node = props.workflow.getNode(lastNodeExecuted); @@ -330,13 +330,11 @@ const waiting = computed(() => { node.type === WAIT_NODE_TYPE && ['webhook', 'form'].includes(node.parameters.resume as string) ) { - const eventType = - node.parameters.resume === 'webhook' ? 'incoming webhook call' : 'form submission'; - return i18n.baseText('node.theNodeIsWaitingForCall', { - interpolate: { - eventType, - }, - }); + const event = + node.parameters.resume === 'webhook' + ? i18n.baseText('node.theNodeIsWaitingWebhookCall') + : i18n.baseText('node.theNodeIsWaitingFormCall'); + return event; } const waitDate = new Date(workflowExecution.waitTill); if (waitDate.toISOString() === WAIT_TIME_UNLIMITED) { diff --git a/packages/editor-ui/src/composables/__tests__/useRunWorkflow.spec.ts b/packages/editor-ui/src/composables/__tests__/useRunWorkflow.spec.ts index a1583280a9..5c46c8ba9a 100644 --- a/packages/editor-ui/src/composables/__tests__/useRunWorkflow.spec.ts +++ b/packages/editor-ui/src/composables/__tests__/useRunWorkflow.spec.ts @@ -6,7 +6,7 @@ import { ExpressionError, type IPinData, type IRunData, type Workflow } from 'n8 import { useRootStore } from '@/stores/root.store'; import { useRunWorkflow } from '@/composables/useRunWorkflow'; -import type { IStartRunData, IWorkflowData } from '@/Interface'; +import type { IExecutionResponse, IStartRunData, IWorkflowData } from '@/Interface'; import { useWorkflowsStore } from '@/stores/workflows.store'; import { useUIStore } from '@/stores/ui.store'; import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers'; @@ -22,6 +22,7 @@ vi.mock('@/stores/workflows.store', () => ({ executionWaitingForWebhook: false, getCurrentWorkflow: vi.fn().mockReturnValue({ id: '123' }), getNodeByName: vi.fn(), + getExecution: vi.fn(), }), })); @@ -306,4 +307,101 @@ describe('useRunWorkflow({ router })', () => { expect(result.runData).toEqual(undefined); }); }); + + describe('useRunWorkflow({ router }) - runWorkflowResolvePending', () => { + let uiStore: ReturnType; + let workflowsStore: ReturnType; + let router: ReturnType; + + beforeAll(() => { + const pinia = createTestingPinia({ stubActions: false }); + setActivePinia(pinia); + rootStore = useRootStore(); + uiStore = useUIStore(); + workflowsStore = useWorkflowsStore(); + router = useRouter(); + workflowHelpers = useWorkflowHelpers({ router }); + }); + + beforeEach(() => { + uiStore.activeActions = []; + vi.mocked(workflowsStore).runWorkflow.mockReset(); + }); + + it('should resolve when runWorkflow finished', async () => { + const { runWorkflowResolvePending } = useRunWorkflow({ router }); + const mockExecutionResponse = { executionId: '123' }; + + vi.mocked(workflowsStore).runWorkflow.mockResolvedValue(mockExecutionResponse); + vi.mocked(workflowsStore).allNodes = []; + vi.mocked(workflowsStore).getExecution.mockResolvedValue({ + finished: true, + } as unknown as IExecutionResponse); + vi.mocked(workflowsStore).workflowExecutionData = { + id: '123', + } as unknown as IExecutionResponse; + + const result = await runWorkflowResolvePending({}); + + expect(result).toEqual(mockExecutionResponse); + }); + + it('should return when workflowExecutionData is null', async () => { + const { runWorkflowResolvePending } = useRunWorkflow({ router }); + const mockExecutionResponse = { executionId: '123' }; + + vi.mocked(workflowsStore).runWorkflow.mockResolvedValue(mockExecutionResponse); + vi.mocked(workflowsStore).allNodes = []; + vi.mocked(workflowsStore).getExecution.mockResolvedValue({ + finished: true, + } as unknown as IExecutionResponse); + vi.mocked(workflowsStore).workflowExecutionData = null; + + const result = await runWorkflowResolvePending({}); + + expect(result).toEqual(mockExecutionResponse); + }); + + it('should handle workflow execution error properly', async () => { + const { runWorkflowResolvePending } = useRunWorkflow({ router }); + const mockExecutionResponse = { executionId: '123' }; + + vi.mocked(workflowsStore).runWorkflow.mockResolvedValue(mockExecutionResponse); + vi.mocked(workflowsStore).allNodes = []; + vi.mocked(workflowsStore).getExecution.mockResolvedValue({ + finished: false, + status: 'error', + } as unknown as IExecutionResponse); + + await runWorkflowResolvePending({}); + + expect(workflowsStore.setWorkflowExecutionData).toHaveBeenCalled(); + expect(workflowsStore.workflowExecutionData).toBe(null); + }); + + it('should retry execution when waiting for webhook and eventually resolve', async () => { + const { runWorkflowResolvePending } = useRunWorkflow({ router }); + const mockExecutionResponse = { waitingForWebhook: true }; + + vi.mocked(workflowsStore) + .runWorkflow.mockResolvedValueOnce(mockExecutionResponse) + .mockResolvedValueOnce({ + executionId: '123', + }); + vi.mocked(workflowsStore).allNodes = []; + + vi.mocked(workflowsStore) + .getExecution.mockResolvedValueOnce({ status: 'waiting' } as unknown as IExecutionResponse) + .mockResolvedValueOnce({ status: 'waiting' } as unknown as IExecutionResponse) + .mockResolvedValueOnce({ finished: true } as unknown as IExecutionResponse); + + const result = await runWorkflowResolvePending({}); + + expect(result).toEqual({ + executionId: '123', + }); + expect(workflowsStore.getExecution).toHaveBeenCalledTimes(4); + expect(workflowsStore.getExecution).toHaveBeenNthCalledWith(4, '123'); + }); + }); }); diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index bcb8bc15f8..9a2f276503 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -1001,7 +1001,8 @@ "node.nodeIsExecuting": "Node is executing", "node.nodeIsWaitingTill": "Node is waiting until {date} {time}", "node.theNodeIsWaitingIndefinitelyForAnIncomingWebhookCall": "The node is waiting for an incoming webhook call (indefinitely)", - "node.theNodeIsWaitingForCall": "The node is waiting for an {eventType}", + "node.theNodeIsWaitingWebhookCall": "The node is waiting for an incoming webhook call", + "node.theNodeIsWaitingFormCall": "The node is waiting for an form submission", "node.waitingForYouToCreateAnEventIn": "Waiting for you to create an event in {nodeType}", "node.discovery.pinData.canvas": "You can pin this output instead of waiting for a test event. Open node to do so.", "node.discovery.pinData.ndv": "You can pin this output instead of waiting for a test event.",