mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-26 21:19:43 -08:00
d97edbcffa
* fix(core): Make node execution order configurable, and backward-compatible * ⚡ Also add new Merge-Node behaviour * ⚡ Fix typo * Fix lint issue * update labels * rename legacy to v0 * remove the unnecessary log * default all new workflows to use v1 execution-order * remove the controller changes * clone default settings to avoid it getting modified --------- Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
201 lines
6.5 KiB
TypeScript
201 lines
6.5 KiB
TypeScript
import type { IRun, WorkflowTestData } from 'n8n-workflow';
|
|
import { createDeferredPromise, Workflow } from 'n8n-workflow';
|
|
import { WorkflowExecute } from '@/WorkflowExecute';
|
|
|
|
import * as Helpers from './helpers';
|
|
import { initLogger } from './helpers/utils';
|
|
import { legacyWorkflowExecuteTests, v1WorkflowExecuteTests } from './helpers/constants';
|
|
|
|
describe('WorkflowExecute', () => {
|
|
beforeAll(() => {
|
|
initLogger();
|
|
});
|
|
|
|
describe('v0 execution order', () => {
|
|
const tests: WorkflowTestData[] = legacyWorkflowExecuteTests;
|
|
|
|
const executionMode = 'manual';
|
|
const nodeTypes = Helpers.NodeTypes();
|
|
|
|
for (const testData of tests) {
|
|
test(testData.description, async () => {
|
|
const workflowInstance = new Workflow({
|
|
id: 'test',
|
|
nodes: testData.input.workflowData.nodes,
|
|
connections: testData.input.workflowData.connections,
|
|
active: false,
|
|
nodeTypes,
|
|
settings: {
|
|
executionOrder: 'v0',
|
|
},
|
|
});
|
|
|
|
const waitPromise = await createDeferredPromise<IRun>();
|
|
const nodeExecutionOrder: string[] = [];
|
|
const additionalData = Helpers.WorkflowExecuteAdditionalData(
|
|
waitPromise,
|
|
nodeExecutionOrder,
|
|
);
|
|
|
|
const workflowExecute = new WorkflowExecute(additionalData, executionMode);
|
|
|
|
const executionData = await workflowExecute.run(workflowInstance);
|
|
|
|
const result = await waitPromise.promise();
|
|
|
|
// Check if the data from WorkflowExecute is identical to data received
|
|
// by the webhooks
|
|
expect(executionData).toEqual(result);
|
|
|
|
// Check if the output data of the nodes is correct
|
|
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
|
if (result.data.resultData.runData[nodeName] === undefined) {
|
|
throw new Error(`Data for node "${nodeName}" is missing!`);
|
|
}
|
|
|
|
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
|
if (nodeData.data === undefined) {
|
|
return null;
|
|
}
|
|
return nodeData.data.main[0]!.map((entry) => entry.json);
|
|
});
|
|
|
|
expect(resultData).toEqual(testData.output.nodeData[nodeName]);
|
|
}
|
|
|
|
// Check if the nodes did execute in the correct order
|
|
expect(nodeExecutionOrder).toEqual(testData.output.nodeExecutionOrder);
|
|
|
|
// Check if other data has correct value
|
|
expect(result.finished).toEqual(true);
|
|
expect(result.data.executionData!.contextData).toEqual({});
|
|
expect(result.data.executionData!.nodeExecutionStack).toEqual([]);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe('v1 execution order', () => {
|
|
const tests: WorkflowTestData[] = v1WorkflowExecuteTests;
|
|
|
|
const executionMode = 'manual';
|
|
const nodeTypes = Helpers.NodeTypes();
|
|
|
|
for (const testData of tests) {
|
|
test(testData.description, async () => {
|
|
const workflowInstance = new Workflow({
|
|
id: 'test',
|
|
nodes: testData.input.workflowData.nodes,
|
|
connections: testData.input.workflowData.connections,
|
|
active: false,
|
|
nodeTypes,
|
|
settings: {
|
|
executionOrder: 'v1',
|
|
},
|
|
});
|
|
|
|
const waitPromise = await createDeferredPromise<IRun>();
|
|
const nodeExecutionOrder: string[] = [];
|
|
const additionalData = Helpers.WorkflowExecuteAdditionalData(
|
|
waitPromise,
|
|
nodeExecutionOrder,
|
|
);
|
|
|
|
const workflowExecute = new WorkflowExecute(additionalData, executionMode);
|
|
|
|
const executionData = await workflowExecute.run(workflowInstance);
|
|
|
|
const result = await waitPromise.promise();
|
|
|
|
// Check if the data from WorkflowExecute is identical to data received
|
|
// by the webhooks
|
|
expect(executionData).toEqual(result);
|
|
|
|
// Check if the output data of the nodes is correct
|
|
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
|
if (result.data.resultData.runData[nodeName] === undefined) {
|
|
throw new Error(`Data for node "${nodeName}" is missing!`);
|
|
}
|
|
|
|
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
|
if (nodeData.data === undefined) {
|
|
return null;
|
|
}
|
|
return nodeData.data.main[0]!.map((entry) => entry.json);
|
|
});
|
|
|
|
// expect(resultData).toEqual(testData.output.nodeData[nodeName]);
|
|
expect(resultData).toEqual(testData.output.nodeData[nodeName]);
|
|
}
|
|
|
|
// Check if the nodes did execute in the correct order
|
|
expect(nodeExecutionOrder).toEqual(testData.output.nodeExecutionOrder);
|
|
|
|
// Check if other data has correct value
|
|
expect(result.finished).toEqual(true);
|
|
expect(result.data.executionData!.contextData).toEqual({});
|
|
expect(result.data.executionData!.nodeExecutionStack).toEqual([]);
|
|
});
|
|
}
|
|
});
|
|
|
|
//run tests on json files from specified directory, default 'workflows'
|
|
//workflows must have pinned data that would be used to test output after execution
|
|
describe('run test workflows', () => {
|
|
const tests: WorkflowTestData[] = Helpers.workflowToTests(__dirname);
|
|
|
|
const executionMode = 'manual';
|
|
const nodeTypes = Helpers.NodeTypes(Helpers.getNodeTypes(tests));
|
|
|
|
for (const testData of tests) {
|
|
test(testData.description, async () => {
|
|
const workflowInstance = new Workflow({
|
|
id: 'test',
|
|
nodes: testData.input.workflowData.nodes,
|
|
connections: testData.input.workflowData.connections,
|
|
active: false,
|
|
nodeTypes,
|
|
settings: testData.input.workflowData.settings,
|
|
});
|
|
|
|
const waitPromise = await createDeferredPromise<IRun>();
|
|
const nodeExecutionOrder: string[] = [];
|
|
const additionalData = Helpers.WorkflowExecuteAdditionalData(
|
|
waitPromise,
|
|
nodeExecutionOrder,
|
|
);
|
|
|
|
const workflowExecute = new WorkflowExecute(additionalData, executionMode);
|
|
|
|
const executionData = await workflowExecute.run(workflowInstance);
|
|
|
|
const result = await waitPromise.promise();
|
|
|
|
// Check if the data from WorkflowExecute is identical to data received
|
|
// by the webhooks
|
|
expect(executionData).toEqual(result);
|
|
|
|
// Check if the output data of the nodes is correct
|
|
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
|
if (result.data.resultData.runData[nodeName] === undefined) {
|
|
throw new Error(`Data for node "${nodeName}" is missing!`);
|
|
}
|
|
|
|
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
|
if (nodeData.data === undefined) {
|
|
return null;
|
|
}
|
|
return nodeData.data.main[0];
|
|
});
|
|
|
|
expect(resultData).toEqual(testData.output.nodeData[nodeName]);
|
|
}
|
|
|
|
// Check if other data has correct value
|
|
expect(result.finished).toEqual(true);
|
|
// expect(result.data.executionData!.contextData).toEqual({}); //Fails when test workflow Includes splitInbatches
|
|
expect(result.data.executionData!.nodeExecutionStack).toEqual([]);
|
|
});
|
|
}
|
|
});
|
|
});
|