mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(core): Add batching and other options to declarative nodes (#8885)
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
@@ -19,7 +19,10 @@ import type {
|
||||
import { RoutingNode } from '@/RoutingNode';
|
||||
import { Workflow } from '@/Workflow';
|
||||
|
||||
import * as utilsModule from '@/utils';
|
||||
|
||||
import * as Helpers from './Helpers';
|
||||
import { applyDeclarativeNodeOptionParameters } from '@/NodeHelpers';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
const postReceiveFunction1 = async function (
|
||||
@@ -42,6 +45,23 @@ const preSendFunction1 = async function (
|
||||
describe('RoutingNode', () => {
|
||||
const additionalData = mock<IWorkflowExecuteAdditionalData>();
|
||||
|
||||
test('applyDeclarativeNodeOptionParameters', () => {
|
||||
const nodeTypes = Helpers.NodeTypes();
|
||||
const nodeType = nodeTypes.getByNameAndVersion('test.setMulti');
|
||||
|
||||
applyDeclarativeNodeOptionParameters(nodeType);
|
||||
|
||||
const options = nodeType.description.properties.find(
|
||||
(property) => property.name === 'requestOptions',
|
||||
);
|
||||
|
||||
expect(options?.options).toBeDefined;
|
||||
|
||||
const optionNames = options!.options!.map((option) => option.name);
|
||||
|
||||
expect(optionNames).toEqual(['batching', 'allowUnauthorizedCerts', 'proxy', 'timeout']);
|
||||
});
|
||||
|
||||
describe('getRequestOptionsFromParameters', () => {
|
||||
const tests: Array<{
|
||||
description: string;
|
||||
@@ -717,6 +737,11 @@ describe('RoutingNode', () => {
|
||||
const tests: Array<{
|
||||
description: string;
|
||||
input: {
|
||||
specialTestOptions?: {
|
||||
applyDeclarativeNodeOptionParameters?: boolean;
|
||||
numberOfItems?: number;
|
||||
sleepCalls?: number[][];
|
||||
};
|
||||
nodeType: {
|
||||
properties?: INodeProperties[];
|
||||
credentials?: INodeCredentialDescription[];
|
||||
@@ -772,6 +797,7 @@ describe('RoutingNode', () => {
|
||||
},
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -821,6 +847,7 @@ describe('RoutingNode', () => {
|
||||
},
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -876,6 +903,7 @@ describe('RoutingNode', () => {
|
||||
},
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -931,6 +959,7 @@ describe('RoutingNode', () => {
|
||||
},
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -988,6 +1017,154 @@ describe('RoutingNode', () => {
|
||||
offset: 10,
|
||||
},
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'multiple parameters, from applyDeclarativeNodeOptionParameters',
|
||||
input: {
|
||||
specialTestOptions: {
|
||||
applyDeclarativeNodeOptionParameters: true,
|
||||
numberOfItems: 5,
|
||||
sleepCalls: [[500], [500]],
|
||||
},
|
||||
node: {
|
||||
parameters: {
|
||||
requestOptions: {
|
||||
allowUnauthorizedCerts: true,
|
||||
batching: {
|
||||
batch: {
|
||||
batchSize: 2,
|
||||
batchInterval: 500,
|
||||
},
|
||||
},
|
||||
proxy: 'http://user:password@127.0.0.1:8080',
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
nodeType: {
|
||||
properties: [],
|
||||
},
|
||||
},
|
||||
output: [
|
||||
[
|
||||
{
|
||||
json: {
|
||||
headers: {},
|
||||
statusCode: 200,
|
||||
requestOptions: {
|
||||
qs: {},
|
||||
headers: {},
|
||||
proxy: {
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
},
|
||||
host: '127.0.0.1',
|
||||
protocol: 'http',
|
||||
port: 8080,
|
||||
},
|
||||
body: {},
|
||||
returnFullResponse: true,
|
||||
skipSslCertificateValidation: true,
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
headers: {},
|
||||
statusCode: 200,
|
||||
requestOptions: {
|
||||
qs: {},
|
||||
headers: {},
|
||||
proxy: {
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
},
|
||||
host: '127.0.0.1',
|
||||
protocol: 'http',
|
||||
port: 8080,
|
||||
},
|
||||
body: {},
|
||||
returnFullResponse: true,
|
||||
skipSslCertificateValidation: true,
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
headers: {},
|
||||
statusCode: 200,
|
||||
requestOptions: {
|
||||
qs: {},
|
||||
headers: {},
|
||||
proxy: {
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
},
|
||||
host: '127.0.0.1',
|
||||
protocol: 'http',
|
||||
port: 8080,
|
||||
},
|
||||
body: {},
|
||||
returnFullResponse: true,
|
||||
skipSslCertificateValidation: true,
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
headers: {},
|
||||
statusCode: 200,
|
||||
requestOptions: {
|
||||
qs: {},
|
||||
headers: {},
|
||||
proxy: {
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
},
|
||||
host: '127.0.0.1',
|
||||
protocol: 'http',
|
||||
port: 8080,
|
||||
},
|
||||
body: {},
|
||||
returnFullResponse: true,
|
||||
skipSslCertificateValidation: true,
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
headers: {},
|
||||
statusCode: 200,
|
||||
requestOptions: {
|
||||
qs: {},
|
||||
headers: {},
|
||||
proxy: {
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'password',
|
||||
},
|
||||
host: '127.0.0.1',
|
||||
protocol: 'http',
|
||||
port: 8080,
|
||||
},
|
||||
body: {},
|
||||
returnFullResponse: true,
|
||||
skipSslCertificateValidation: true,
|
||||
timeout: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1424,6 +1601,7 @@ describe('RoutingNode', () => {
|
||||
addedIn: 'preSendFunction1',
|
||||
},
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -1519,6 +1697,7 @@ describe('RoutingNode', () => {
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
url: '/test-url',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1698,15 +1877,12 @@ describe('RoutingNode', () => {
|
||||
const connectionInputData: INodeExecutionData[] = [];
|
||||
const runExecutionData: IRunExecutionData = { resultData: { runData: {} } };
|
||||
const nodeType = nodeTypes.getByNameAndVersion(baseNode.type);
|
||||
applyDeclarativeNodeOptionParameters(nodeType);
|
||||
|
||||
const propertiesOriginal = nodeType.description.properties;
|
||||
|
||||
const inputData: ITaskDataConnections = {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
json: {},
|
||||
},
|
||||
],
|
||||
],
|
||||
main: [[]],
|
||||
};
|
||||
|
||||
for (const testData of tests) {
|
||||
@@ -1719,6 +1895,9 @@ describe('RoutingNode', () => {
|
||||
};
|
||||
|
||||
nodeType.description = { ...testData.input.nodeType } as INodeTypeDescription;
|
||||
if (testData.input.specialTestOptions?.applyDeclarativeNodeOptionParameters) {
|
||||
nodeType.description.properties = propertiesOriginal;
|
||||
}
|
||||
|
||||
const workflow = new Workflow({
|
||||
nodes: workflowData.nodes,
|
||||
@@ -1742,18 +1921,46 @@ describe('RoutingNode', () => {
|
||||
source: null,
|
||||
} as IExecuteData;
|
||||
|
||||
const executeFunctions = mock<IExecuteFunctions>();
|
||||
const executeSingleFunctions = Helpers.getExecuteSingleFunctions(
|
||||
workflow,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
node,
|
||||
itemIndex,
|
||||
);
|
||||
|
||||
const nodeExecuteFunctions: Partial<INodeExecuteFunctions> = {
|
||||
getExecuteFunctions: () => mock<IExecuteFunctions>(),
|
||||
getExecuteSingleFunctions: () =>
|
||||
Helpers.getExecuteSingleFunctions(
|
||||
workflow,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
node,
|
||||
itemIndex,
|
||||
),
|
||||
getExecuteFunctions: () => executeFunctions,
|
||||
getExecuteSingleFunctions: () => executeSingleFunctions,
|
||||
};
|
||||
|
||||
const numberOfItems = testData.input.specialTestOptions?.numberOfItems ?? 1;
|
||||
if (!inputData.main[0] || inputData.main[0].length !== numberOfItems) {
|
||||
inputData.main[0] = [];
|
||||
for (let i = 0; i < numberOfItems; i++) {
|
||||
inputData.main[0].push({ json: {} });
|
||||
}
|
||||
}
|
||||
|
||||
const spy = jest.spyOn(utilsModule, 'sleep').mockReturnValue(
|
||||
new Promise((resolve) => {
|
||||
resolve();
|
||||
}),
|
||||
);
|
||||
|
||||
spy.mockClear();
|
||||
|
||||
executeFunctions.getNodeParameter.mockImplementation(
|
||||
(parameterName: string) => testData.input.node.parameters[parameterName] || {},
|
||||
);
|
||||
|
||||
const getNodeParameter = executeSingleFunctions.getNodeParameter;
|
||||
executeSingleFunctions.getNodeParameter = (parameterName: string) =>
|
||||
parameterName in testData.input.node.parameters
|
||||
? testData.input.node.parameters[parameterName]
|
||||
: getNodeParameter(parameterName) ?? {};
|
||||
|
||||
const result = await routingNode.runNode(
|
||||
inputData,
|
||||
runIndex,
|
||||
@@ -1762,6 +1969,12 @@ describe('RoutingNode', () => {
|
||||
nodeExecuteFunctions as INodeExecuteFunctions,
|
||||
);
|
||||
|
||||
if (testData.input.specialTestOptions?.sleepCalls) {
|
||||
expect(spy.mock.calls).toEqual(testData.input.specialTestOptions?.sleepCalls);
|
||||
} else {
|
||||
expect(spy).toHaveBeenCalledTimes(0);
|
||||
}
|
||||
|
||||
expect(result).toEqual(testData.output);
|
||||
});
|
||||
}
|
||||
@@ -1820,6 +2033,7 @@ describe('RoutingNode', () => {
|
||||
},
|
||||
baseURL: 'http://127.0.0.1:5678',
|
||||
returnFullResponse: true,
|
||||
timeout: 300000,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user