From 4d454091b2251d6409c118c56ea9aa2e581b4405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Fri, 27 Dec 2024 14:50:35 +0100 Subject: [PATCH] tests and docs for processSuccessExecution --- packages/core/src/WorkflowExecute.ts | 21 +++++ packages/core/test/WorkflowExecute.test.ts | 105 ++++++++++++++++++++- 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index 39e2f904e1d6c..a9e3738dde5e1 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -2092,6 +2092,27 @@ export class WorkflowExecute { }); } + /** + * Processes the final state of a workflow execution and prepares the execution result. + * This method handles different completion scenarios: success, waiting, error, and canceled states. + * It also manages cleanup tasks like static data updates and trigger deactivation. + * + * @param startedAt - The timestamp when the workflow execution started + * @param workflow - The workflow being executed + * @param executionError - Optional error that occurred during execution + * @param closeFunction - Optional promise that handles cleanup of triggers/webhooks + * + * @returns A promise that resolves to the complete workflow execution data (IRun) + * + * @remarks + * The function performs these tasks in order: + * 1. Generates full execution data + * 2. Sets appropriate status based on execution outcome + * 3. Handles any static data changes + * 4. Moves node metadata to its final location + * 5. Executes the 'workflowExecuteAfter' hook + * 6. Performs cleanup via closeFunction if provided + */ async processSuccessExecution( startedAt: Date, workflow: Workflow, diff --git a/packages/core/test/WorkflowExecute.test.ts b/packages/core/test/WorkflowExecute.test.ts index 4816617ff1af3..3176050d44437 100644 --- a/packages/core/test/WorkflowExecute.test.ts +++ b/packages/core/test/WorkflowExecute.test.ts @@ -12,6 +12,7 @@ import { mock } from 'jest-mock-extended'; import { pick } from 'lodash'; import type { + ExecutionBaseError, IConnection, IExecuteData, INode, @@ -22,7 +23,6 @@ import type { IRun, IRunData, IRunExecutionData, - ITaskMetadata, ITriggerResponse, IWorkflowExecuteAdditionalData, WorkflowTestData, @@ -1192,4 +1192,107 @@ describe('WorkflowExecute', () => { }); }); }); + + describe('processSuccessExecution', () => { + const startedAt: Date = new Date('2023-01-01T00:00:00.000Z'); + const workflow = new Workflow({ + id: 'test', + nodes: [], + connections: {}, + active: false, + nodeTypes: mock(), + }); + + let runExecutionData: IRunExecutionData; + let workflowExecute: WorkflowExecute; + + beforeEach(() => { + runExecutionData = { + startData: {}, + resultData: { runData: {} }, + executionData: { + contextData: {}, + nodeExecutionStack: [], + metadata: {}, + waitingExecution: {}, + waitingExecutionSource: null, + }, + }; + workflowExecute = new WorkflowExecute(mock(), 'manual', runExecutionData); + + jest.spyOn(workflowExecute, 'executeHook').mockResolvedValue(undefined); + jest.spyOn(workflowExecute, 'moveNodeMetadata').mockImplementation(); + }); + + test('should handle different workflow completion scenarios', async () => { + // Test successful execution + const successResult = await workflowExecute.processSuccessExecution(startedAt, workflow); + expect(successResult.status).toBe('success'); + expect(successResult.finished).toBe(true); + + // Test execution with wait + runExecutionData.waitTill = new Date('2024-01-01'); + const waitResult = await workflowExecute.processSuccessExecution(startedAt, workflow); + expect(waitResult.status).toBe('waiting'); + expect(waitResult.waitTill).toEqual(runExecutionData.waitTill); + + // Test execution with error + const testError = new Error('Test error') as ExecutionBaseError; + + // Reset the status since it was changed by previous tests + workflowExecute['status'] = 'new'; + runExecutionData.waitTill = undefined; + const errorResult = await workflowExecute.processSuccessExecution( + startedAt, + workflow, + testError, + ); + expect(errorResult.data.resultData.error).toBeDefined(); + expect(errorResult.data.resultData.error?.message).toBe('Test error'); + + // Test canceled execution + const cancelError = new Error('Workflow execution canceled') as ExecutionBaseError; + const cancelResult = await workflowExecute.processSuccessExecution( + startedAt, + workflow, + cancelError, + ); + expect(cancelResult.data.resultData.error).toBeDefined(); + expect(cancelResult.data.resultData.error?.message).toBe('Workflow execution canceled'); + }); + + test('should handle static data, hooks, and cleanup correctly', async () => { + // Mock static data change + workflow.staticData.__dataChanged = true; + workflow.staticData.testData = 'changed'; + + // Mock cleanup function that's actually a promise + let cleanupCalled = false; + const mockCleanupPromise = new Promise((resolve) => { + setTimeout(() => { + cleanupCalled = true; + resolve(); + }, 0); + }); + + const result = await workflowExecute.processSuccessExecution( + startedAt, + workflow, + undefined, + mockCleanupPromise, + ); + + // Verify static data handling + expect(result).toBeDefined(); + expect(workflowExecute.moveNodeMetadata).toHaveBeenCalled(); + expect(workflowExecute.executeHook).toHaveBeenCalledWith('workflowExecuteAfter', [ + result, + workflow.staticData, + ]); + + // Verify cleanup was called + await mockCleanupPromise; + expect(cleanupCalled).toBe(true); + }); + }); });