diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 5505548807..8542a8815d 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -2320,6 +2320,9 @@ export function getExecuteSingleFunctions( return allItems[itemIndex]; }, + getItemIndex() { + return itemIndex; + }, getMode: (): WorkflowExecuteMode => { return mode; }, diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 59b3cff53a..7642ef83d4 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -566,6 +566,7 @@ export interface IExecuteSingleFunctions { getContext(type: string): IContextObject; getCredentials(type: string): Promise; getInputData(inputIndex?: number, inputName?: string): INodeExecutionData; + getItemIndex(): number; getMode(): WorkflowExecuteMode; getNode(): INode; getNodeParameter( diff --git a/packages/workflow/test/Helpers.ts b/packages/workflow/test/Helpers.ts index 818c7bffe8..6f84e58d2c 100644 --- a/packages/workflow/test/Helpers.ts +++ b/packages/workflow/test/Helpers.ts @@ -427,6 +427,9 @@ export function getExecuteSingleFunctions( return allItems[itemIndex]; }, + getItemIndex: () => { + return itemIndex; + }, getMode: (): WorkflowExecuteMode => { return mode; }, diff --git a/packages/workflow/test/RoutingNode.test.ts b/packages/workflow/test/RoutingNode.test.ts index aa1371baa8..396411f88d 100644 --- a/packages/workflow/test/RoutingNode.test.ts +++ b/packages/workflow/test/RoutingNode.test.ts @@ -1748,4 +1748,194 @@ describe('RoutingNode', () => { }); } }); + + describe('itemIndex', () => { + const tests: Array<{ + description: string; + input: { + nodeType: { + properties?: INodeProperties[]; + credentials?: INodeCredentialDescription[]; + requestDefaults?: IHttpRequestOptions; + requestOperations?: IN8nRequestOperations; + }; + node: { + parameters: INodeParameters; + }; + }; + output: INodeExecutionData[][] | undefined; + }> = [ + { + description: 'single parameter, only send defined, fixed value, using requestDefaults', + input: { + nodeType: { + requestDefaults: { + baseURL: 'http://127.0.0.1:5678', + url: '/test-url', + }, + properties: [ + { + displayName: 'Email', + name: 'email', + type: 'string', + routing: { + send: { + property: 'toEmail', + type: 'body', + value: 'fixedValue', + }, + }, + default: '', + }, + ], + }, + node: { + parameters: {}, + }, + }, + output: [ + [ + { + json: { + headers: {}, + statusCode: 200, + requestOptions: { + url: '/test-url', + qs: {}, + body: { + toEmail: 'fixedValue', + }, + baseURL: 'http://127.0.0.1:5678', + returnFullResponse: true, + }, + }, + }, + ], + ], + }, + ]; + + const nodeTypes = Helpers.NodeTypes(); + const baseNode: INode = { + parameters: {}, + name: 'test', + type: 'test.set', + typeVersion: 1, + position: [0, 0], + }; + + const mode = 'internal'; + const runIndex = 0; + const itemIndex = 0; + const connectionInputData: INodeExecutionData[] = []; + const runExecutionData: IRunExecutionData = { resultData: { runData: {} } }; + const additionalData = Helpers.WorkflowExecuteAdditionalData(); + const nodeType = nodeTypes.getByNameAndVersion(baseNode.type); + + const inputData: ITaskDataConnections = { + main: [ + [ + { + json: {}, + }, + { + json: {}, + }, + { + json: {}, + }, + ], + ], + }; + + for (const testData of tests) { + test(testData.description, async () => { + const node: INode = { ...baseNode, ...testData.input.node }; + + const workflowData = { + nodes: [node], + connections: {}, + }; + + // @ts-ignore + nodeType.description = { ...testData.input.nodeType }; + + const workflow = new Workflow({ + nodes: workflowData.nodes, + connections: workflowData.connections, + active: false, + nodeTypes, + }); + + const routingNode = new RoutingNode( + workflow, + node, + connectionInputData, + runExecutionData ?? null, + additionalData, + mode, + ); + + const executeData = { + data: {}, + node, + source: null, + } as IExecuteData; + + let currentItemIndex = 0; + for (let iteration = 0; iteration < inputData.main[0]!.length; iteration++) { + // @ts-ignore + const nodeExecuteFunctions: INodeExecuteFunctions = { + getExecuteFunctions: () => { + return Helpers.getExecuteFunctions( + workflow, + runExecutionData, + runIndex, + connectionInputData, + {}, + node, + itemIndex + iteration, + additionalData, + executeData, + mode, + ); + }, + getExecuteSingleFunctions: () => { + return Helpers.getExecuteSingleFunctions( + workflow, + runExecutionData, + runIndex, + connectionInputData, + {}, + node, + itemIndex + iteration, + additionalData, + executeData, + mode, + ); + }, + }; + + const routingNodeExecutionContext = nodeExecuteFunctions.getExecuteSingleFunctions( + routingNode.workflow, + routingNode.runExecutionData, + runIndex, + routingNode.connectionInputData, + inputData, + routingNode.node, + iteration, + routingNode.additionalData, + executeData, + routingNode.mode, + ); + + currentItemIndex = routingNodeExecutionContext.getItemIndex(); + } + + const expectedItemIndex = inputData.main[0]!.length - 1; + + expect(currentItemIndex).toEqual(expectedItemIndex); + }); + } + }); });