mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
Co-authored-by: Yiorgis Gozadinos <yiorgis@n8n.io> Co-authored-by: JP van Oosten <jp@n8n.io>
68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import assert from 'assert';
|
|
import type { IRunExecutionData, IPinData, IWorkflowBase } from 'n8n-workflow';
|
|
|
|
import { TestCaseExecutionError } from '@/evaluation.ee/test-runner/errors.ee';
|
|
|
|
// Entity representing a node in a workflow under test, for which data should be mocked during test execution
|
|
export type MockedNodeItem = {
|
|
name?: string;
|
|
id: string;
|
|
};
|
|
|
|
/**
|
|
* Extracts the execution data from the past execution
|
|
* and creates a pin data object from it for the given workflow.
|
|
* It uses a list of mocked nodes defined in a test definition
|
|
* to decide which nodes to pin.
|
|
*/
|
|
export function createPinData(
|
|
workflow: IWorkflowBase,
|
|
mockedNodes: MockedNodeItem[],
|
|
executionData: IRunExecutionData,
|
|
pastWorkflowData?: IWorkflowBase,
|
|
) {
|
|
const pinData = {} as IPinData;
|
|
|
|
const workflowNodeIds = new Map(workflow.nodes.map((node) => [node.id, node.name]));
|
|
|
|
// If the past workflow data is provided, use it to create a map between node IDs and node names
|
|
const pastWorkflowNodeIds = new Map<string, string>();
|
|
if (pastWorkflowData) {
|
|
for (const node of pastWorkflowData.nodes) {
|
|
pastWorkflowNodeIds.set(node.id, node.name);
|
|
}
|
|
}
|
|
|
|
for (const mockedNode of mockedNodes) {
|
|
assert(mockedNode.id, 'Mocked node ID is missing');
|
|
|
|
const nodeName = workflowNodeIds.get(mockedNode.id);
|
|
|
|
// If mocked node is still present in the workflow
|
|
if (nodeName) {
|
|
// Try to restore node name from past execution data (it might have been renamed between past execution and up-to-date workflow)
|
|
const pastNodeName = pastWorkflowNodeIds.get(mockedNode.id) ?? nodeName;
|
|
const nodeData = executionData.resultData.runData[pastNodeName];
|
|
|
|
if (nodeData?.[0]?.data?.main?.[0]) {
|
|
pinData[nodeName] = nodeData[0]?.data?.main?.[0];
|
|
} else {
|
|
throw new TestCaseExecutionError('MOCKED_NODE_DOES_NOT_EXIST');
|
|
}
|
|
}
|
|
}
|
|
|
|
return pinData;
|
|
}
|
|
|
|
/**
|
|
* Returns the trigger node of the past execution.
|
|
* The trigger node is the node that has no source and has run data.
|
|
*/
|
|
export function getPastExecutionTriggerNode(executionData: IRunExecutionData) {
|
|
return Object.keys(executionData.resultData.runData).find((nodeName) => {
|
|
const data = executionData.resultData.runData[nodeName];
|
|
return !data[0].source || data[0].source.length === 0 || data[0].source[0] === null;
|
|
});
|
|
}
|