n8n/packages/core/test/WorkflowExecute.test.ts
कारतोफ्फेलस्क्रिप्ट™ d97edbcffa
fix(core): Make node execution order configurable, and backward-compatible (#6507)
* 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>
2023-07-05 18:47:34 +02:00

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([]);
});
}
});
});