mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
fix(Execute Workflow Node): Fix 'Continue (using error output)' mode to output errors correctly (#19240)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, IWorkflowDataProxyData } from 'n8n-workflow';
|
||||
import type { IExecuteFunctions, IWorkflowDataProxyData, INode } from 'n8n-workflow';
|
||||
|
||||
import { ExecuteWorkflow } from './ExecuteWorkflow.node';
|
||||
import { getWorkflowInfo } from './GenericFunctions';
|
||||
@@ -81,13 +81,15 @@ describe('ExecuteWorkflow', () => {
|
||||
expect(result).toEqual([[{ json: { key: 'value' }, index: 0, pairedItem: { item: 0 } }]]);
|
||||
});
|
||||
|
||||
test('should handle errors and continue on fail', async () => {
|
||||
test('should handle errors and continue on fail, no items, < 1.3 version', async () => {
|
||||
executeFunctions.getNodeParameter
|
||||
.mockReturnValueOnce('database') // source
|
||||
.mockReturnValueOnce('each') // mode
|
||||
.mockReturnValueOnce(true) // waitForSubWorkflow
|
||||
.mockReturnValueOnce([]); // workflowInputs.schema
|
||||
|
||||
executeFunctions.getNode.mockReturnValue({ typeVersion: 1.2 } as INode);
|
||||
|
||||
(getWorkflowInfo as jest.Mock).mockRejectedValue(new Error('Test error'));
|
||||
(executeFunctions.continueOnFail as jest.Mock).mockReturnValue(true);
|
||||
|
||||
@@ -96,6 +98,77 @@ describe('ExecuteWorkflow', () => {
|
||||
expect(result).toEqual([[{ json: { error: 'Test error' }, pairedItem: { item: 0 } }]]);
|
||||
});
|
||||
|
||||
test('should handle errors and continue on fail, multiple items, < 1.3 version', async () => {
|
||||
executeFunctions.getNodeParameter
|
||||
.mockReturnValueOnce('database') // source
|
||||
.mockReturnValueOnce('each') // mode
|
||||
.mockReturnValueOnce(true) // waitForSubWorkflow
|
||||
.mockReturnValue([]); // workflowInputs.schema
|
||||
|
||||
executeFunctions.getNode.mockReturnValue({ typeVersion: 1.2 } as INode);
|
||||
executeFunctions.getInputData.mockReturnValueOnce([
|
||||
{ json: { key: '1' } },
|
||||
{ json: { key: '2' } },
|
||||
{ json: { key: '3' } },
|
||||
]);
|
||||
|
||||
(getWorkflowInfo as jest.Mock).mockRejectedValue(new Error('Test error'));
|
||||
(executeFunctions.continueOnFail as jest.Mock).mockReturnValue(true);
|
||||
|
||||
const result = await executeWorkflow.execute.call(executeFunctions);
|
||||
|
||||
expect(result).toEqual([
|
||||
[{ json: { error: 'Test error' }, pairedItem: { item: 0 }, metadata: undefined }],
|
||||
[{ json: { error: 'Test error' }, pairedItem: { item: 1 }, metadata: undefined }],
|
||||
[{ json: { error: 'Test error' }, pairedItem: { item: 2 }, metadata: undefined }],
|
||||
]);
|
||||
});
|
||||
|
||||
test('should handle errors and continue on fail, no items, >= 1.3 version', async () => {
|
||||
executeFunctions.getNodeParameter
|
||||
.mockReturnValueOnce('database') // source
|
||||
.mockReturnValueOnce('each') // mode
|
||||
.mockReturnValueOnce(true) // waitForSubWorkflow
|
||||
.mockReturnValueOnce([]); // workflowInputs.schema
|
||||
|
||||
executeFunctions.getNode.mockReturnValue({ typeVersion: 1.3 } as INode);
|
||||
|
||||
(getWorkflowInfo as jest.Mock).mockRejectedValue(new Error('Test error'));
|
||||
(executeFunctions.continueOnFail as jest.Mock).mockReturnValue(true);
|
||||
|
||||
const result = await executeWorkflow.execute.call(executeFunctions);
|
||||
|
||||
expect(result).toEqual([[{ json: { error: 'Test error' }, pairedItem: { item: 0 } }]]);
|
||||
});
|
||||
|
||||
test('should handle errors and continue on fail, multiple items, >= 1.3 version', async () => {
|
||||
executeFunctions.getNodeParameter
|
||||
.mockReturnValueOnce('database') // source
|
||||
.mockReturnValueOnce('each') // mode
|
||||
.mockReturnValueOnce(true) // waitForSubWorkflow
|
||||
.mockReturnValueOnce([]); // workflowInputs.schema
|
||||
|
||||
executeFunctions.getNode.mockReturnValue({ typeVersion: 1.3 } as INode);
|
||||
executeFunctions.getInputData.mockReturnValueOnce([
|
||||
{ json: { key: '1' } },
|
||||
{ json: { key: '2' } },
|
||||
{ json: { key: '3' } },
|
||||
]);
|
||||
|
||||
(getWorkflowInfo as jest.Mock).mockRejectedValue(new Error('Test error'));
|
||||
(executeFunctions.continueOnFail as jest.Mock).mockReturnValue(true);
|
||||
|
||||
const result = await executeWorkflow.execute.call(executeFunctions);
|
||||
|
||||
expect(result).toEqual([
|
||||
[
|
||||
{ json: { error: 'Test error' }, pairedItem: { item: 0 }, metadata: undefined },
|
||||
{ json: { error: 'Test error' }, pairedItem: { item: 1 }, metadata: undefined },
|
||||
{ json: { error: 'Test error' }, pairedItem: { item: 2 }, metadata: undefined },
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('should throw error if not continuing on fail', async () => {
|
||||
executeFunctions.getNodeParameter
|
||||
.mockReturnValueOnce('database') // source
|
||||
|
||||
@@ -20,7 +20,7 @@ export class ExecuteWorkflow implements INodeType {
|
||||
icon: 'fa:sign-in-alt',
|
||||
iconColor: 'orange-red',
|
||||
group: ['transform'],
|
||||
version: [1, 1.1, 1.2],
|
||||
version: [1, 1.1, 1.2, 1.3],
|
||||
subtitle: '={{"Workflow: " + $parameter["workflowId"]}}',
|
||||
description: 'Execute another workflow',
|
||||
defaults: {
|
||||
@@ -369,11 +369,16 @@ export class ExecuteWorkflow implements INodeType {
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
if (returnData[i] === undefined) {
|
||||
returnData[i] = [];
|
||||
}
|
||||
const nodeVersion = this.getNode().typeVersion;
|
||||
// In versions < 1.3 using the "Continue (using error output)" mode
|
||||
// the node would return items in extra "error branches" instead of
|
||||
// returning an array of items on the error output. These branches weren't really shown correctly on the UI.
|
||||
// In the fixed >= 1.3 versions the errors are now all output into the single error output as an array of error items.
|
||||
const outputIndex = nodeVersion >= 1.3 ? 0 : i;
|
||||
|
||||
returnData[outputIndex] ??= [];
|
||||
const metadata = parseErrorMetadata(error);
|
||||
returnData[i].push({
|
||||
returnData[outputIndex].push({
|
||||
json: { error: error.message },
|
||||
pairedItem: { item: i },
|
||||
metadata,
|
||||
|
||||
Reference in New Issue
Block a user