mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-11 13:15:28 +03:00
refactor(core): Add more unit tests for Workflow.ts
(no-changelog) (#9868)
Co-authored-by: Danny Martini <danny@n8n.io>
This commit is contained in:
parent
e25682ddad
commit
9454a851bb
@ -63,6 +63,18 @@ function dedupe<T>(arr: T[]): T[] {
|
|||||||
return [...new Set(arr)];
|
return [...new Set(arr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkflowParameters {
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
nodes: INode[];
|
||||||
|
connections: IConnections;
|
||||||
|
active: boolean;
|
||||||
|
nodeTypes: INodeTypes;
|
||||||
|
staticData?: IDataObject;
|
||||||
|
settings?: IWorkflowSettings;
|
||||||
|
pinData?: IPinData;
|
||||||
|
}
|
||||||
|
|
||||||
export class Workflow {
|
export class Workflow {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@ -90,18 +102,7 @@ export class Workflow {
|
|||||||
|
|
||||||
pinData?: IPinData;
|
pinData?: IPinData;
|
||||||
|
|
||||||
// constructor(id: string | undefined, nodes: INode[], connections: IConnections, active: boolean, nodeTypes: INodeTypes, staticData?: IDataObject, settings?: IWorkflowSettings) {
|
constructor(parameters: WorkflowParameters) {
|
||||||
constructor(parameters: {
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
nodes: INode[];
|
|
||||||
connections: IConnections;
|
|
||||||
active: boolean;
|
|
||||||
nodeTypes: INodeTypes;
|
|
||||||
staticData?: IDataObject;
|
|
||||||
settings?: IWorkflowSettings;
|
|
||||||
pinData?: IPinData;
|
|
||||||
}) {
|
|
||||||
this.id = parameters.id as string; // @tech_debt Ensure this is not optional
|
this.id = parameters.id as string; // @tech_debt Ensure this is not optional
|
||||||
this.name = parameters.name;
|
this.name = parameters.name;
|
||||||
this.nodeTypes = parameters.nodeTypes;
|
this.nodeTypes = parameters.nodeTypes;
|
||||||
@ -251,16 +252,14 @@ export class Workflow {
|
|||||||
* is fine. If there are issues it returns the issues
|
* is fine. If there are issues it returns the issues
|
||||||
* which have been found for the different nodes.
|
* which have been found for the different nodes.
|
||||||
* TODO: Does currently not check for credential issues!
|
* TODO: Does currently not check for credential issues!
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
checkReadyForExecution(inputData: {
|
checkReadyForExecution(
|
||||||
startNode?: string;
|
inputData: {
|
||||||
destinationNode?: string;
|
startNode?: string;
|
||||||
pinDataNodeNames?: string[];
|
destinationNode?: string;
|
||||||
}): IWorkflowIssues | null {
|
pinDataNodeNames?: string[];
|
||||||
let node: INode;
|
} = {},
|
||||||
let nodeType: INodeType | undefined;
|
): IWorkflowIssues | null {
|
||||||
let nodeIssues: INodeIssues | null = null;
|
|
||||||
const workflowIssues: IWorkflowIssues = {};
|
const workflowIssues: IWorkflowIssues = {};
|
||||||
|
|
||||||
let checkNodes: string[] = [];
|
let checkNodes: string[] = [];
|
||||||
@ -277,14 +276,14 @@ export class Workflow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const nodeName of checkNodes) {
|
for (const nodeName of checkNodes) {
|
||||||
nodeIssues = null;
|
let nodeIssues: INodeIssues | null = null;
|
||||||
node = this.nodes[nodeName];
|
const node = this.nodes[nodeName];
|
||||||
|
|
||||||
if (node.disabled === true) {
|
if (node.disabled === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
const nodeType = this.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||||
|
|
||||||
if (nodeType === undefined) {
|
if (nodeType === undefined) {
|
||||||
// Node type is not known
|
// Node type is not known
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { mock } from 'jest-mock-extended';
|
||||||
|
import { NodeConnectionType } from '@/Interfaces';
|
||||||
import type {
|
import type {
|
||||||
IBinaryKeyData,
|
IBinaryKeyData,
|
||||||
IConnections,
|
IConnections,
|
||||||
@ -5,10 +7,14 @@ import type {
|
|||||||
INode,
|
INode,
|
||||||
INodeExecutionData,
|
INodeExecutionData,
|
||||||
INodeParameters,
|
INodeParameters,
|
||||||
|
INodeType,
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeTypes,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
NodeParameterValueType,
|
NodeParameterValueType,
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
import { Workflow } from '@/Workflow';
|
import { Workflow, type WorkflowParameters } from '@/Workflow';
|
||||||
|
import * as NodeHelpers from '@/NodeHelpers';
|
||||||
|
|
||||||
process.env.TEST_VARIABLE_1 = 'valueEnvVariable1';
|
process.env.TEST_VARIABLE_1 = 'valueEnvVariable1';
|
||||||
|
|
||||||
@ -20,303 +26,426 @@ interface StubNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('Workflow', () => {
|
describe('Workflow', () => {
|
||||||
describe('renameNodeInParameterValue for expressions', () => {
|
describe('checkIfWorkflowCanBeActivated', () => {
|
||||||
const tests = [
|
const disabledNode = mock<INode>({ type: 'triggerNode', disabled: true });
|
||||||
{
|
const unknownNode = mock<INode>({ type: 'unknownNode' });
|
||||||
description: 'do nothing if there is no expression',
|
const noTriggersNode = mock<INode>({ type: 'noTriggersNode' });
|
||||||
input: {
|
const pollNode = mock<INode>({ type: 'pollNode' });
|
||||||
currentName: 'Node1',
|
const triggerNode = mock<INode>({ type: 'triggerNode' });
|
||||||
newName: 'Node1New',
|
const webhookNode = mock<INode>({ type: 'webhookNode' });
|
||||||
parameters: {
|
|
||||||
|
const nodeTypes = mock<INodeTypes>();
|
||||||
|
nodeTypes.getByNameAndVersion.mockImplementation((type) => {
|
||||||
|
// TODO: getByNameAndVersion signature needs to be updated to allow returning undefined
|
||||||
|
if (type === 'unknownNode') return undefined as unknown as INodeType;
|
||||||
|
const partial: Partial<INodeType> = {
|
||||||
|
poll: undefined,
|
||||||
|
trigger: undefined,
|
||||||
|
webhook: undefined,
|
||||||
|
description: mock<INodeTypeDescription>({
|
||||||
|
properties: [],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
if (type === 'pollNode') partial.poll = jest.fn();
|
||||||
|
if (type === 'triggerNode') partial.trigger = jest.fn();
|
||||||
|
if (type === 'webhookNode') partial.webhook = jest.fn();
|
||||||
|
return mock(partial);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
['should skip disabled nodes', disabledNode, [], false],
|
||||||
|
['should skip nodes marked as ignored', triggerNode, ['triggerNode'], false],
|
||||||
|
['should skip unknown nodes', unknownNode, [], false],
|
||||||
|
['should skip nodes with no trigger method', noTriggersNode, [], false],
|
||||||
|
['should activate if poll method exists', pollNode, [], true],
|
||||||
|
['should activate if trigger method exists', triggerNode, [], true],
|
||||||
|
['should activate if webhook method exists', webhookNode, [], true],
|
||||||
|
])('%s', async (_, node, ignoredNodes, expected) => {
|
||||||
|
const params = mock<WorkflowParameters>({ nodeTypes });
|
||||||
|
params.nodes = [node];
|
||||||
|
const workflow = new Workflow(params);
|
||||||
|
expect(workflow.checkIfWorkflowCanBeActivated(ignoredNodes)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkReadyForExecution', () => {
|
||||||
|
const disabledNode = mock<INode>({ name: 'Disabled Node', disabled: true });
|
||||||
|
const startNode = mock<INode>({ name: 'Start Node' });
|
||||||
|
const unknownNode = mock<INode>({ name: 'Unknown Node', type: 'unknownNode' });
|
||||||
|
|
||||||
|
const nodeParamIssuesSpy = jest.spyOn(NodeHelpers, 'getNodeParametersIssues');
|
||||||
|
|
||||||
|
const nodeTypes = mock<INodeTypes>();
|
||||||
|
nodeTypes.getByNameAndVersion.mockImplementation((type) => {
|
||||||
|
// TODO: getByNameAndVersion signature needs to be updated to allow returning undefined
|
||||||
|
if (type === 'unknownNode') return undefined as unknown as INodeType;
|
||||||
|
return mock<INodeType>({
|
||||||
|
description: {
|
||||||
|
properties: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => jest.clearAllMocks());
|
||||||
|
|
||||||
|
it('should return null if there are no nodes', () => {
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const issues = workflow.checkReadyForExecution();
|
||||||
|
expect(issues).toBe(null);
|
||||||
|
expect(nodeTypes.getByNameAndVersion).not.toHaveBeenCalled();
|
||||||
|
expect(nodeParamIssuesSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null if there are no enabled nodes', () => {
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodes: [disabledNode],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const issues = workflow.checkReadyForExecution({ startNode: disabledNode.name });
|
||||||
|
expect(issues).toBe(null);
|
||||||
|
expect(nodeTypes.getByNameAndVersion).toHaveBeenCalledTimes(1);
|
||||||
|
expect(nodeParamIssuesSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return typeUnknown for unknown nodes', () => {
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodes: [unknownNode],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const issues = workflow.checkReadyForExecution({ startNode: unknownNode.name });
|
||||||
|
expect(issues).toEqual({ [unknownNode.name]: { typeUnknown: true } });
|
||||||
|
expect(nodeTypes.getByNameAndVersion).toHaveBeenCalledTimes(2);
|
||||||
|
expect(nodeParamIssuesSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return issues for regular nodes', () => {
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodes: [startNode],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes,
|
||||||
|
});
|
||||||
|
nodeParamIssuesSpy.mockReturnValue({ execution: false });
|
||||||
|
|
||||||
|
const issues = workflow.checkReadyForExecution({ startNode: startNode.name });
|
||||||
|
expect(issues).toEqual({ [startNode.name]: { execution: false } });
|
||||||
|
expect(nodeTypes.getByNameAndVersion).toHaveBeenCalledTimes(2);
|
||||||
|
expect(nodeParamIssuesSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('renameNodeInParameterValue', () => {
|
||||||
|
describe('for expressions', () => {
|
||||||
|
const tests = [
|
||||||
|
{
|
||||||
|
description: 'do nothing if there is no expression',
|
||||||
|
input: {
|
||||||
|
currentName: 'Node1',
|
||||||
|
newName: 'Node1New',
|
||||||
|
parameters: {
|
||||||
|
value1: 'value1Node1',
|
||||||
|
value2: 'value2Node1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
value1: 'value1Node1',
|
value1: 'value1Node1',
|
||||||
value2: 'value2Node1',
|
value2: 'value2Node1',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: 'value1Node1',
|
description: 'should work with dot notation',
|
||||||
value2: 'value2Node1',
|
input: {
|
||||||
},
|
currentName: 'Node1',
|
||||||
},
|
newName: 'NewName',
|
||||||
{
|
parameters: {
|
||||||
description: 'should work with dot notation',
|
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
input: {
|
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||||
currentName: 'Node1',
|
},
|
||||||
newName: 'NewName',
|
},
|
||||||
parameters: {
|
output: {
|
||||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value1: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
value2: "={{$node.NewName.data.value2 + ' - ' + $node.NewName.data.value2}}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: "={{$node.NewName.data.value1 + 'Node1'}}",
|
description: 'should work with ["nodeName"]',
|
||||||
value2: "={{$node.NewName.data.value2 + ' - ' + $node.NewName.data.value2}}",
|
input: {
|
||||||
},
|
currentName: 'Node1',
|
||||||
},
|
newName: 'NewName',
|
||||||
{
|
parameters: {
|
||||||
description: 'should work with ["nodeName"]',
|
value1: '={{$node["Node1"]["data"]["value1"] + \'Node1\'}}',
|
||||||
input: {
|
value2:
|
||||||
currentName: 'Node1',
|
'={{$node["Node1"]["data"]["value2"] + \' - \' + $node["Node1"]["data"]["value2"]}}',
|
||||||
newName: 'NewName',
|
},
|
||||||
parameters: {
|
},
|
||||||
value1: '={{$node["Node1"]["data"]["value1"] + \'Node1\'}}',
|
output: {
|
||||||
|
value1: '={{$node["NewName"]["data"]["value1"] + \'Node1\'}}',
|
||||||
value2:
|
value2:
|
||||||
'={{$node["Node1"]["data"]["value2"] + \' - \' + $node["Node1"]["data"]["value2"]}}',
|
'={{$node["NewName"]["data"]["value2"] + \' - \' + $node["NewName"]["data"]["value2"]}}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: '={{$node["NewName"]["data"]["value1"] + \'Node1\'}}',
|
description: 'should work with $("Node1")',
|
||||||
value2:
|
input: {
|
||||||
'={{$node["NewName"]["data"]["value2"] + \' - \' + $node["NewName"]["data"]["value2"]}}',
|
currentName: 'Node1',
|
||||||
},
|
newName: 'NewName',
|
||||||
},
|
parameters: {
|
||||||
{
|
value1: '={{$("Node1")["data"]["value1"] + \'Node1\'}}',
|
||||||
description: 'should work with $("Node1")',
|
value2: '={{$("Node1")["data"]["value2"] + \' - \' + $("Node1")["data"]["value2"]}}',
|
||||||
input: {
|
},
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName',
|
|
||||||
parameters: {
|
|
||||||
value1: '={{$("Node1")["data"]["value1"] + \'Node1\'}}',
|
|
||||||
value2: '={{$("Node1")["data"]["value2"] + \' - \' + $("Node1")["data"]["value2"]}}',
|
|
||||||
},
|
},
|
||||||
},
|
output: {
|
||||||
output: {
|
value1: '={{$("NewName")["data"]["value1"] + \'Node1\'}}',
|
||||||
value1: '={{$("NewName")["data"]["value1"] + \'Node1\'}}',
|
|
||||||
value2: '={{$("NewName")["data"]["value2"] + \' - \' + $("NewName")["data"]["value2"]}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'should work with $items("Node1")',
|
|
||||||
input: {
|
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName',
|
|
||||||
parameters: {
|
|
||||||
value1: '={{$items("Node1")["data"]["value1"] + \'Node1\'}}',
|
|
||||||
value2:
|
value2:
|
||||||
'={{$items("Node1")["data"]["value2"] + \' - \' + $items("Node1")["data"]["value2"]}}',
|
'={{$("NewName")["data"]["value2"] + \' - \' + $("NewName")["data"]["value2"]}}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: '={{$items("NewName")["data"]["value1"] + \'Node1\'}}',
|
description: 'should work with $items("Node1")',
|
||||||
value2:
|
input: {
|
||||||
'={{$items("NewName")["data"]["value2"] + \' - \' + $items("NewName")["data"]["value2"]}}',
|
currentName: 'Node1',
|
||||||
},
|
newName: 'NewName',
|
||||||
},
|
parameters: {
|
||||||
{
|
value1: '={{$items("Node1")["data"]["value1"] + \'Node1\'}}',
|
||||||
description: 'should work with $items("Node1", 0, 1)',
|
value2:
|
||||||
input: {
|
'={{$items("Node1")["data"]["value2"] + \' - \' + $items("Node1")["data"]["value2"]}}',
|
||||||
currentName: 'Node1',
|
},
|
||||||
newName: 'NewName',
|
},
|
||||||
parameters: {
|
output: {
|
||||||
value1: '={{$items("Node1", 0, 1)["data"]["value1"] + \'Node1\'}}',
|
value1: '={{$items("NewName")["data"]["value1"] + \'Node1\'}}',
|
||||||
value2:
|
value2:
|
||||||
'={{$items("Node1", 0, 1)["data"]["value2"] + \' - \' + $items("Node1", 0, 1)["data"]["value2"]}}',
|
'={{$items("NewName")["data"]["value2"] + \' - \' + $items("NewName")["data"]["value2"]}}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: '={{$items("NewName", 0, 1)["data"]["value1"] + \'Node1\'}}',
|
description: 'should work with $items("Node1", 0, 1)',
|
||||||
value2:
|
input: {
|
||||||
'={{$items("NewName", 0, 1)["data"]["value2"] + \' - \' + $items("NewName", 0, 1)["data"]["value2"]}}',
|
currentName: 'Node1',
|
||||||
},
|
newName: 'NewName',
|
||||||
},
|
parameters: {
|
||||||
{
|
value1: '={{$items("Node1", 0, 1)["data"]["value1"] + \'Node1\'}}',
|
||||||
description: 'should work with dot notation that contains space and special character',
|
value2:
|
||||||
input: {
|
'={{$items("Node1", 0, 1)["data"]["value2"] + \' - \' + $items("Node1", 0, 1)["data"]["value2"]}}',
|
||||||
currentName: 'Node1',
|
},
|
||||||
newName: 'New $ Name',
|
|
||||||
parameters: {
|
|
||||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
|
||||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
|
||||||
},
|
},
|
||||||
},
|
output: {
|
||||||
output: {
|
value1: '={{$items("NewName", 0, 1)["data"]["value1"] + \'Node1\'}}',
|
||||||
value1: '={{$node["New $ Name"].data.value1 + \'Node1\'}}',
|
|
||||||
value2:
|
|
||||||
'={{$node["New $ Name"].data.value2 + \' - \' + $node["New $ Name"].data.value2}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'should work with dot notation that contains space and trailing $',
|
|
||||||
input: {
|
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName$',
|
|
||||||
parameters: {
|
|
||||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
|
||||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
value1: '={{$node["NewName$"].data.value1 + \'Node1\'}}',
|
|
||||||
value2: '={{$node["NewName$"].data.value2 + \' - \' + $node["NewName$"].data.value2}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'should work with dot notation that contains space and special character',
|
|
||||||
input: {
|
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName $ $& $` $$$',
|
|
||||||
parameters: {
|
|
||||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
|
||||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
value1: '={{$node["NewName $ $& $` $$$"].data.value1 + \'Node1\'}}',
|
|
||||||
value2:
|
|
||||||
'={{$node["NewName $ $& $` $$$"].data.value2 + \' - \' + $node["NewName $ $& $` $$$"].data.value2}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'should work with dot notation without trailing dot',
|
|
||||||
input: {
|
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName',
|
|
||||||
parameters: {
|
|
||||||
value1: "={{$node.Node1 + 'Node1'}}",
|
|
||||||
value2: "={{$node.Node1 + ' - ' + $node.Node1}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
value1: "={{$node.NewName + 'Node1'}}",
|
|
||||||
value2: "={{$node.NewName + ' - ' + $node.NewName}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "should work with ['nodeName']",
|
|
||||||
input: {
|
|
||||||
currentName: 'Node1',
|
|
||||||
newName: 'NewName',
|
|
||||||
parameters: {
|
|
||||||
value1: "={{$node['Node1']['data']['value1'] + 'Node1'}}",
|
|
||||||
value2:
|
value2:
|
||||||
"={{$node['Node1']['data']['value2'] + ' - ' + $node['Node1']['data']['value2']}}",
|
'={{$items("NewName", 0, 1)["data"]["value2"] + \' - \' + $items("NewName", 0, 1)["data"]["value2"]}}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
{
|
||||||
value1: "={{$node['NewName']['data']['value1'] + 'Node1'}}",
|
description: 'should work with dot notation that contains space and special character',
|
||||||
value2:
|
input: {
|
||||||
"={{$node['NewName']['data']['value2'] + ' - ' + $node['NewName']['data']['value2']}}",
|
currentName: 'Node1',
|
||||||
|
newName: 'New $ Name',
|
||||||
|
parameters: {
|
||||||
|
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
value1: '={{$node["New $ Name"].data.value1 + \'Node1\'}}',
|
||||||
|
value2:
|
||||||
|
'={{$node["New $ Name"].data.value2 + \' - \' + $node["New $ Name"].data.value2}}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
description: 'should work with dot notation that contains space and trailing $',
|
||||||
description: 'should work on lower levels',
|
input: {
|
||||||
input: {
|
currentName: 'Node1',
|
||||||
currentName: 'Node1',
|
newName: 'NewName$',
|
||||||
newName: 'NewName',
|
parameters: {
|
||||||
parameters: {
|
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
level1a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
value1: '={{$node["NewName$"].data.value1 + \'Node1\'}}',
|
||||||
|
value2: '={{$node["NewName$"].data.value2 + \' - \' + $node["NewName$"].data.value2}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should work with dot notation that contains space and special character',
|
||||||
|
input: {
|
||||||
|
currentName: 'Node1',
|
||||||
|
newName: 'NewName $ $& $` $$$',
|
||||||
|
parameters: {
|
||||||
|
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
value1: '={{$node["NewName $ $& $` $$$"].data.value1 + \'Node1\'}}',
|
||||||
|
value2:
|
||||||
|
'={{$node["NewName $ $& $` $$$"].data.value2 + \' - \' + $node["NewName $ $& $` $$$"].data.value2}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should work with dot notation without trailing dot',
|
||||||
|
input: {
|
||||||
|
currentName: 'Node1',
|
||||||
|
newName: 'NewName',
|
||||||
|
parameters: {
|
||||||
|
value1: "={{$node.Node1 + 'Node1'}}",
|
||||||
|
value2: "={{$node.Node1 + ' - ' + $node.Node1}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
value1: "={{$node.NewName + 'Node1'}}",
|
||||||
|
value2: "={{$node.NewName + ' - ' + $node.NewName}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "should work with ['nodeName']",
|
||||||
|
input: {
|
||||||
|
currentName: 'Node1',
|
||||||
|
newName: 'NewName',
|
||||||
|
parameters: {
|
||||||
|
value1: "={{$node['Node1']['data']['value1'] + 'Node1'}}",
|
||||||
|
value2:
|
||||||
|
"={{$node['Node1']['data']['value2'] + ' - ' + $node['Node1']['data']['value2']}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
value1: "={{$node['NewName']['data']['value1'] + 'Node1'}}",
|
||||||
|
value2:
|
||||||
|
"={{$node['NewName']['data']['value2'] + ' - ' + $node['NewName']['data']['value2']}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should work on lower levels',
|
||||||
|
input: {
|
||||||
|
currentName: 'Node1',
|
||||||
|
newName: 'NewName',
|
||||||
|
parameters: {
|
||||||
|
level1a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
level1b: [
|
||||||
|
{
|
||||||
|
value2a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value2b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
level1c: {
|
||||||
|
value2a: {
|
||||||
|
value3a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value3b: [
|
||||||
|
{
|
||||||
|
value4a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value4b: {
|
||||||
|
value5a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
value5b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as INodeParameters,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
level1a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
level1b: [
|
level1b: [
|
||||||
{
|
{
|
||||||
value2a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value2a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
value2b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value2b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
level1c: {
|
level1c: {
|
||||||
value2a: {
|
value2a: {
|
||||||
value3a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value3a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
value3b: [
|
value3b: [
|
||||||
{
|
{
|
||||||
value4a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value4a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
value4b: {
|
value4b: {
|
||||||
value5a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value5a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
value5b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
value5b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as INodeParameters,
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
level1a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
level1b: [
|
|
||||||
{
|
|
||||||
value2a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
value2b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
level1c: {
|
|
||||||
value2a: {
|
|
||||||
value3a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
value3b: [
|
|
||||||
{
|
|
||||||
value4a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
value4b: {
|
|
||||||
value5a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
value5b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
const nodeTypes = Helpers.NodeTypes();
|
const nodeTypes = Helpers.NodeTypes();
|
||||||
const workflow = new Workflow({ nodes: [], connections: {}, active: false, nodeTypes });
|
const workflow = new Workflow({ nodes: [], connections: {}, active: false, nodeTypes });
|
||||||
|
|
||||||
for (const testData of tests) {
|
for (const testData of tests) {
|
||||||
test(testData.description, () => {
|
test(testData.description, () => {
|
||||||
const result = workflow.renameNodeInParameterValue(
|
const result = workflow.renameNodeInParameterValue(
|
||||||
testData.input.parameters,
|
testData.input.parameters,
|
||||||
testData.input.currentName,
|
testData.input.currentName,
|
||||||
testData.input.newName,
|
testData.input.newName,
|
||||||
);
|
);
|
||||||
expect(result).toEqual(testData.output);
|
expect(result).toEqual(testData.output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
describe('renameNodeInParameterValue for node with renamable content', () => {
|
|
||||||
const tests = [
|
|
||||||
{
|
|
||||||
description: "should work with $('name')",
|
|
||||||
input: {
|
|
||||||
currentName: 'Old',
|
|
||||||
newName: 'New',
|
|
||||||
parameters: { jsCode: "$('Old').first();" },
|
|
||||||
},
|
|
||||||
output: { jsCode: "$('New').first();" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "should work with $node['name'] and $node.name",
|
|
||||||
input: {
|
|
||||||
currentName: 'Old',
|
|
||||||
newName: 'New',
|
|
||||||
parameters: { jsCode: "$node['Old'].first(); $node.Old.first();" },
|
|
||||||
},
|
|
||||||
output: { jsCode: "$node['New'].first(); $node.New.first();" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'should work with $items()',
|
|
||||||
input: {
|
|
||||||
currentName: 'Old',
|
|
||||||
newName: 'New',
|
|
||||||
parameters: { jsCode: "$items('Old').first();" },
|
|
||||||
},
|
|
||||||
output: { jsCode: "$items('New').first();" },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const workflow = new Workflow({
|
|
||||||
nodes: [],
|
|
||||||
connections: {},
|
|
||||||
active: false,
|
|
||||||
nodeTypes: Helpers.NodeTypes(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const t of tests) {
|
describe('for node with renamable content', () => {
|
||||||
test(t.description, () => {
|
const tests = [
|
||||||
expect(
|
{
|
||||||
workflow.renameNodeInParameterValue(
|
description: "should work with $('name')",
|
||||||
t.input.parameters,
|
input: {
|
||||||
t.input.currentName,
|
currentName: 'Old',
|
||||||
t.input.newName,
|
newName: 'New',
|
||||||
{ hasRenamableContent: true },
|
parameters: { jsCode: "$('Old').first();" },
|
||||||
),
|
},
|
||||||
).toEqual(t.output);
|
output: { jsCode: "$('New').first();" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "should work with $node['name'] and $node.name",
|
||||||
|
input: {
|
||||||
|
currentName: 'Old',
|
||||||
|
newName: 'New',
|
||||||
|
parameters: { jsCode: "$node['Old'].first(); $node.Old.first();" },
|
||||||
|
},
|
||||||
|
output: { jsCode: "$node['New'].first(); $node.New.first();" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should work with $items()',
|
||||||
|
input: {
|
||||||
|
currentName: 'Old',
|
||||||
|
newName: 'New',
|
||||||
|
parameters: { jsCode: "$items('Old').first();" },
|
||||||
|
},
|
||||||
|
output: { jsCode: "$items('New').first();" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodes: [],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
nodeTypes: Helpers.NodeTypes(),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
for (const t of tests) {
|
||||||
|
test(t.description, () => {
|
||||||
|
expect(
|
||||||
|
workflow.renameNodeInParameterValue(
|
||||||
|
t.input.parameters,
|
||||||
|
t.input.currentName,
|
||||||
|
t.input.newName,
|
||||||
|
{ hasRenamableContent: true },
|
||||||
|
),
|
||||||
|
).toEqual(t.output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('renameNode', () => {
|
describe('renameNode', () => {
|
||||||
@ -377,7 +506,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2',
|
node: 'Node2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -408,7 +537,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2',
|
node: 'Node2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -444,7 +573,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2',
|
node: 'Node2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -475,7 +604,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2New',
|
node: 'Node2New',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -532,7 +661,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node3',
|
node: 'Node3',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -543,12 +672,12 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node3',
|
node: 'Node3',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'Node5',
|
node: 'Node5',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -559,12 +688,12 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node4',
|
node: 'Node4',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'Node5',
|
node: 'Node5',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -616,7 +745,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node3New',
|
node: 'Node3New',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -627,12 +756,12 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node3New',
|
node: 'Node3New',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'Node5',
|
node: 'Node5',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -643,12 +772,12 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node4',
|
node: 'Node4',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'Node5',
|
node: 'Node5',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1229,7 +1358,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2',
|
node: 'Node2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1240,7 +1369,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node3',
|
node: 'Node3',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1251,7 +1380,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Node2',
|
node: 'Node2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1521,7 +1650,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set',
|
node: 'Set',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1532,7 +1661,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set1',
|
node: 'Set1',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1591,21 +1720,21 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set1',
|
node: 'Set1',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set',
|
node: 'Set',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set',
|
node: 'Set',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1616,7 +1745,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set2',
|
node: 'Set2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1627,7 +1756,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set2',
|
node: 'Set2',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1691,7 +1820,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set',
|
node: 'Set',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1699,7 +1828,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Switch',
|
node: 'Switch',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1710,7 +1839,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set1',
|
node: 'Set1',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1721,12 +1850,12 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set1',
|
node: 'Set1',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'Switch',
|
node: 'Switch',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -1737,7 +1866,7 @@ describe('Workflow', () => {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
node: 'Set1',
|
node: 'Set1',
|
||||||
type: 'main',
|
type: NodeConnectionType.Main,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user