n8n/packages/workflow/test/Workflow.test.ts
Jan 5a179cd5ae
Implement Wait functionality (#1817)
* refactor saving

* refactor api layer to be stateless

* refactor header details

* set variable for menu height

* clean up scss

* clean up indentation

* clean up dropdown impl

* refactor no tags view

* split away header

* Fix tslint issues

* Refactor tag manager

* add tags to patch request

* clean up scss

*  Refactor types to entities

* fix issues

* update no workflow error

* clean up tagscontainer

* use getters instead of state

* remove imports

* use custom colors

* clean up tags container

* clean up dropdown

* clean up focusoncreate

*  Ignore mistaken ID in POST /workflows

*  Fix undefined tag ID in PATCH /workflows

*  Shorten response for POST /tags

* remove scss mixins

* clean up imports

*  Implement validation with class-validator

* address ivan's comments

* implement modals

* Fix lint issues

* fix disabling shortcuts

* fix focus issues

* fix focus issues

* fix focus issues with modal

* fix linting issues

* use dispatch

* use constants for modal keys

* fix focus

* fix lint issues

* remove unused prop

* add modal root

* fix lint issues

* remove unused methods

* fix shortcut

* remove max width

*  Fix duplicate entry error for pg and MySQL

* update rename messaging

* update order of buttons

* fix firefox overflow on windows

* fix dropdown height

* 🔨 refactor tag crud controllers

* 🧹 remove unused imports

* use variable for number of items

* fix dropdown spacing

*  Restore type to fix build

*  Fix post-refactor PATCH /workflows/:id

*  Fix PATCH /workflows/:id for zero tags

*  Fix usage count becoming stringified

* address max's comments

* fix filter spacing

* fix blur bug

* address most of ivan's comments

* address tags type concern

* remove defaults

*  return tag id as string

* 🔨 add hooks to tag CUD operations

* 🏎 simplify timestamp pruning

* remove blur event

* fix onblur bug

*  Fix fs import to fix build

* address max's comments

* implement responsive tag container

* fix lint issues

* update tag limits

* address ivan's comments

* remove rename, refactor header, implement new designs for save, remove responsive tag container

* update styling

* update styling

* implement responsive tag container

* implement header tags edit

* implement header tags edit

* fix lint issues

* implement expandable input

* minor fixes

* minor fixes

* use variable

* rename save as

* duplicate fixes

* minor edit fixes

* lint fixes

* style fixes

* hook up saving name

* hook up tags

* clean up impl

* fix dirty state bug

* update limit

* update notification messages

* on click outside

* fix minor bug with count

* lint fixes

* handle minor edge cases

* handle minor edge cases

* handle minor bugs; fix firefox dropdown issue

* Fix min width

* apply tags only after api success

* remove count fix

* clean up workflow tags impl, fix tags delete bug

* fix minor issue

* fix minor spacing issue

* disable wrap for ops

* fix viewport root; save on click in dropdown

* save button loading when saving name/tags

* implement max width on tags container

* implement cleaner create experience

* disable edit while updating

* codacy hex color

* refactor tags container

* fix clickability

* fix workflow open and count

* clean up structure

* fix up lint issues

* fix button size

* increase workflow name limit for larger screen

* tslint fixes

* disable responsiveness for workflow modal

* rename event

* change min width for tags

* clean up pr

* address max's comments on styles

* remove success toasts

* add hover mode to name

* minor fixes

* refactor name preview

* fix name input not to jiggle

* finish up name input

* Fix up add tags

* clean up param

* clean up scss

* fix resizing name

* fix resizing name

* fix resize bug

* clean up edit spacing

* ignore on esc

* fix input bug

* focus input on clear

* build

* fix up add tags clickablity

* remove scrollbars

* move into folders

* clean up multiple patch req

* remove padding top from edit

* update tags on enter

* build

* rollout blur on enter behavior

* rollout esc behavior

* fix tags bug when duplicating tags

* move key to reload tags

* update header spacing

* build

* update hex case

* refactor workflow title

* remove unusued prop

* keep focus on error, fix bug on error

* Fix bug with name / tags toggle on error

* fix connection push bug

* :spakles: Implement wait functionality

* 🐛 Do not delete waiting executions with prune

*  Improve SQLite migration to not lose execution data anymore

*  Make it possible to restart waiting execution via webhook

*  Add missing file

* 🐛 Some more merge fixes

*  Do not show error for Wait-Nodes if in time-mode

*  Make $executionId available in expressions

* 👕 Fix lint issue

* 👕 Fix lint issue

* 👕 Fix lint issue

*  Set the unlimited sleep time as a variable

*  Add also sleeping webhook path to config

*  Make it possible to retrieve restartUrl in workflow

*  Add authentication to Wait-Node in Webhook-Mode

*  Return 404 when trying to restart execution via webhook which does
not support it

*  Make it possible to set absolute time on Wait-Node

*  Remove not needed imports

*  Fix description format

*  Implement missing webhook features on Wait-Node

*  Display webhook variable in NodeWebhooks

*  Include also date in displayed sleep time

*  Make it possible to see sleep time on node

*  Make sure that no executions does get executed twice

*  Add comment

*  Further improvements

*  Make Wait-Node easier to use

*  Add support for "notice" parameter type

* Fixing wait node to work with queue, improved logging and execution view

* Added support for mysql and pg

*  Add support for webhook postfix path

*  Make it possible to stop sleeping executions

*  Fix issue with webhook paths in not webhook mode

*  Remove not needed console.log

*  Update TODOs

*  Increase min time of workflow staying active to descrease possible issue
with overlap

* 👕 Fix lint issue

* 🐛 Fix issues with webhooks

*  Make error message clearer

*  Fix issue with missing execution ID in scaling mode

* Fixed execution list to correctly display waiting executins

* Feature: enable webhook wait workflows to continue after specified time

* Fixed linting

*  Improve waiting description text

*  Fix parameter display issue and rename

*  Remove comment

*  Do not display webhooks on Wait-Node

* Changed wording from restart to resume on wait node

* Fixed wording and inconsistent screen when changing resume modes

* Removed dots from the descriptions

* Changed docs url and renaming postfix to suffix

* Changed names from sleep to wait

*  Apply suggestions from ben

Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>

* Some fixes by Ben

*  Remove console.logs

*  Fixes and improvements

Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
2021-08-21 14:11:32 +02:00

1270 lines
27 KiB
TypeScript

import {
IConnections,
INode,
INodeExecutionData,
INodeParameters,
IRunExecutionData,
Workflow,
} from '../src';
process.env.TEST_VARIABLE_1 = 'valueEnvVariable1';
import * as Helpers from './Helpers';
interface StubNode {
name: string;
parameters: INodeParameters;
}
describe('Workflow', () => {
describe('renameNodeInExpressions', () => {
const tests = [
{
description: 'do nothing if there is no expression',
input: {
currentName: 'Node1',
newName: 'Node1New',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
output: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
description: 'should work with dot notation',
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 ["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 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: [
{
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 workflow = new Workflow({ nodes: [], connections: {}, active: false, nodeTypes });
for (const testData of tests) {
test(testData.description, () => {
const result = workflow.renameNodeInExpressions(testData.input.parameters, testData.input.currentName, testData.input.newName);
expect(result).toEqual(testData.output);
});
}
});
describe('renameNode', () => {
const tests = [
{
description: 'rename node without connections',
input: {
currentName: 'Node1',
newName: 'Node1New',
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
],
connections: {},
},
output: {
nodes: [
{
name: 'Node1New',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
],
connections: {},
},
},
{
description: 'rename node with one output connection',
input: {
currentName: 'Node1',
newName: 'Node1New',
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
],
connections: {
Node1: {
main: [
[
{
node: 'Node2',
type: 'main',
index: 0,
},
],
],
},
},
},
output: {
nodes: [
{
name: 'Node1New',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
],
connections: {
Node1New: {
main: [
[
{
node: 'Node2',
type: 'main',
index: 0,
},
],
],
},
},
},
},
{
description: 'rename node with one input connection',
input: {
currentName: 'Node2',
newName: 'Node2New',
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
],
connections: {
Node1: {
main: [
[
{
node: 'Node2',
type: 'main',
index: 0,
},
],
],
},
},
},
output: {
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2New',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
],
connections: {
Node1: {
main: [
[
{
node: 'Node2New',
type: 'main',
index: 0,
},
],
],
},
},
},
},
{
description: 'rename node with multiple input and output connection',
input: {
currentName: 'Node3',
newName: 'Node3New',
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
{
name: 'Node3',
parameters: {
value1: 'value1Node3',
value2: 'value2Node3',
},
},
{
name: 'Node4',
parameters: {
value1: 'value1Node4',
value2: 'value2Node4',
},
},
{
name: 'Node5',
parameters: {
value1: 'value1Node5',
value2: 'value2Node5',
},
},
],
connections: {
Node1: {
main: [
[
{
node: 'Node3',
type: 'main',
index: 0,
},
],
],
},
Node2: {
main: [
[
{
node: 'Node3',
type: 'main',
index: 0,
},
{
node: 'Node5',
type: 'main',
index: 0,
},
],
],
},
Node3: {
main: [
[
{
node: 'Node4',
type: 'main',
index: 0,
},
{
node: 'Node5',
type: 'main',
index: 0,
},
],
],
},
},
},
output: {
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: 'value1Node2',
value2: 'value2Node2',
},
},
{
name: 'Node3New',
parameters: {
value1: 'value1Node3',
value2: 'value2Node3',
},
},
{
name: 'Node4',
parameters: {
value1: 'value1Node4',
value2: 'value2Node4',
},
},
{
name: 'Node5',
parameters: {
value1: 'value1Node5',
value2: 'value2Node5',
},
},
],
connections: {
Node1: {
main: [
[
{
node: 'Node3New',
type: 'main',
index: 0,
},
],
],
},
Node2: {
main: [
[
{
node: 'Node3New',
type: 'main',
index: 0,
},
{
node: 'Node5',
type: 'main',
index: 0,
},
],
],
},
Node3New: {
main: [
[
{
node: 'Node4',
type: 'main',
index: 0,
},
{
node: 'Node5',
type: 'main',
index: 0,
},
],
],
},
},
},
},
// This does just a basic test if "renameNodeInExpressions" gets used. More complex
// tests with different formats and levels are in the separate tests for the function
// "renameNodeInExpressions"
{
description: 'change name also in expressions which use node-name (dot notation)',
input: {
currentName: 'Node1',
newName: 'Node1New',
nodes: [
{
name: 'Node1',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: '={{$node.Node1.data.value1 + \'Node1\'}}',
value2: '={{$node.Node1.data.value2 + \' - \' + $node.Node1.data.value2}}',
},
},
],
connections: {},
},
output: {
nodes: [
{
name: 'Node1New',
parameters: {
value1: 'value1Node1',
value2: 'value2Node1',
},
},
{
name: 'Node2',
parameters: {
value1: '={{$node.Node1New.data.value1 + \'Node1\'}}',
value2: '={{$node.Node1New.data.value2 + \' - \' + $node.Node1New.data.value2}}',
},
},
],
connections: {},
},
},
];
const nodeTypes = Helpers.NodeTypes();
let workflow: Workflow;
function createNodeData(stubData: StubNode): INode {
return {
name: stubData.name,
parameters: stubData.parameters,
type: 'test.set',
typeVersion: 1,
position: [
100,
100,
],
};
}
let executeNodes: INode[];
let resultNodes: {
[key: string]: INode;
};
for (const testData of tests) {
test(testData.description, () => {
executeNodes = [];
for (const node of testData.input.nodes) {
executeNodes.push(createNodeData(node));
}
workflow = new Workflow({ nodes: executeNodes, connections: testData.input.connections as IConnections, active: false, nodeTypes });
workflow.renameNode(testData.input.currentName, testData.input.newName);
resultNodes = {};
for (const node of testData.output.nodes) {
resultNodes[node.name] = createNodeData(node);
}
expect(workflow.nodes).toEqual(resultNodes);
expect(workflow.connectionsBySourceNode).toEqual(testData.output.connections);
});
}
});
describe('getParameterValue', () => {
const tests = [
{
description: 'read simple not expression value',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: 'valueNode2',
},
},
},
output: {
value1: 'valueNode2',
},
},
{
description: 'read simple math expression',
input: {
Node1: {
parameters: {
value1: '',
},
},
Node2: {
parameters: {
value1: '={{1+2}}',
},
},
},
output: {
value1: 3,
},
},
{
description: 'read data from node-output-data with with long "$node.{NODE}.data" syntax',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.data.value1}}',
},
},
},
output: {
value1: 'valueNode1',
},
},
{
description: 'read data from node-output-data with with long "$node.{NODE}.data" syntax add value and append text',
input: {
Node1: {
parameters: {
value1: 1,
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.data.value1 + 2}} asdf',
},
},
},
output: {
value1: '3 asdf',
},
},
{
description: 'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax with JavaScript Code',
input: {
Node1: {
parameters: {
value1: 'whatever',
},
// Overwrite the output data
outputJson: {
value1: {
a: 1,
b: 2,
c: 3,
},
},
},
Node2: {
parameters: {
value1: '={{Object.keys($node.Node1.data.value1).join(", ")}}',
},
},
},
output: {
value1: 'a, b, c',
},
},
{
description: 'read data from incoming-node-data with with short "data" syntax',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$data.value1}}',
},
},
},
output: {
value1: 'valueNode1',
},
},
{
description: 'read deep-data from incoming-node-data with with short "data" syntax',
input: {
Node1: {
parameters: {
value1: 'whatever',
},
// Overwrite the output data
outputJson: {
value1: {
a: {
b: 'deepDataNode1',
},
},
},
},
Node2: {
parameters: {
value1: '={{$data.value1.a.b}}',
},
},
},
output: {
value1: 'deepDataNode1',
},
},
{
description: 'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax',
input: {
Node1: {
parameters: {
value1: 'whatever',
},
// Overwrite the output data
outputJson: {
value1: {
a: {
b: 'deepDataNode1',
},
},
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.data.value1.a.b}}',
},
},
},
output: {
value1: 'deepDataNode1',
},
},
{
description: 'read binary-string-data from incoming-node-data with with short "$binary" syntax',
input: {
Node1: {
parameters: {
value1: 'whatever',
},
// Overwrite the output data
outputBinary: {
binaryKey: {
data: '',
type: '',
fileName: 'test-file1.jpg',
},
},
},
Node2: {
parameters: {
value1: '={{$binary.binaryKey.fileName}}',
},
},
},
output: {
value1: 'test-file1.jpg',
},
},
{
description: 'read binary-string-data from node-output-data with with long "$node.{NODE}.binary" syntax',
input: {
Node1: {
parameters: {
value1: 'whatever',
},
// Overwrite the output data
outputBinary: {
binaryKey: {
data: '',
type: '',
fileName: 'test-file1.jpg',
},
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.binary.binaryKey.fileName}}',
},
},
},
output: {
value1: 'test-file1.jpg',
},
},
{
description: 'read parameter from other node with with long "$node.parameter" syntax',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.parameter.value1}}',
},
},
},
output: {
value1: 'valueNode1',
},
},
{
description: 'read environment data "$env" syntax which exists',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$env.TEST_VARIABLE_1}}',
},
},
},
output: {
value1: 'valueEnvVariable1',
},
},
{
description: 'read environment data "$env" syntax which does not exists',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$env.DOES_NOT_EXIST}}',
},
},
},
output: {
value1: undefined,
},
},
{
description: 'read parameter from current node with short "$parameter" syntax',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: 'valueNode2',
value2: '={{$parameter.value1}}',
},
},
},
output: {
value1: 'valueNode2',
value2: 'valueNode2',
},
},
{
description: 'return resolved value when referencing another property with expression (long "$node.{NODE}.data" syntax)',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$node.Node1.data.value1}}',
value2: '={{$parameter.value1}}',
},
},
},
output: {
value1: 'valueNode1',
value2: 'valueNode1',
},
},
{
description: 'return resolved value when referencing another property with expression (short "data" syntax)',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$data.value1}}',
value2: '={{$parameter.value1}}',
},
},
},
output: {
value1: 'valueNode1',
value2: 'valueNode1',
},
},
{
description: 'return resolved value when referencing another property with expression when a node has spaces (long "$node["{NODE}"].parameter" syntax)',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$node["Node 4 with spaces"].parameter.value1}}',
},
},
},
output: {
value1: 'default-value1',
},
},
{
description: 'return resolved value when referencing another property with expression on another node (long "$node["{NODE}"].parameter" syntax)',
input: {
Node1: {
parameters: {
value1: 'valueNode1',
},
},
Node2: {
parameters: {
value1: '={{$node["Node1"].parameter.value1}}a',
},
},
Node3: {
parameters: {
value1: '={{$node["Node2"].parameter.value1}}b',
},
},
},
output: {
value1: 'valueNode1ab',
},
},
// TODO: Make that this test does not fail!
// {
// description: 'return resolved value when short "data" syntax got used in expression on paramter of not active node which got referenced by active one',
// input: {
// Node1: {
// parameters: {
// value1: 'valueNode1',
// }
// },
// Node2: {
// parameters: {
// value1: '={{$data.value1}}-Node2',
// },
// },
// Node3: {
// parameters: {
// value1: '={{$data.value1}}-Node3+1',
// value2: '={{node.Node2.data.value1}}-Node3+2',
// },
// }
// },
// output: {
// value1: 'valueNode1-Node2-Node3+1',
// value2: 'valueNode1-Node2-Node3+2',
// },
// },
];
const nodeTypes = Helpers.NodeTypes();
for (const testData of tests) {
test(testData.description, () => {
const nodes: INode[] = [
{
"name": "Node1",
"parameters": testData.input.Node1.parameters,
"type": "test.set",
"typeVersion": 1,
"position": [
100,
100,
],
},
{
"name": "Node2",
"parameters": testData.input.Node2.parameters,
"type": "test.set",
"typeVersion": 1,
"position": [
100,
200,
],
},
{
"name": "Node3",
// @ts-ignore
"parameters": testData.input.hasOwnProperty('Node3') ? testData.input.Node3.parameters : {},
"type": "test.set",
"typeVersion": 1,
"position": [
100,
300,
],
},
{
"name": "Node 4 with spaces",
// @ts-ignore
"parameters": testData.input.hasOwnProperty('Node4') ? testData.input.Node4.parameters : {},
"type": "test.set",
"typeVersion": 1,
"position": [
100,
400,
],
},
];
const connections: IConnections = {
"Node1": {
"main": [
[
{
"node": "Node2",
"type": "main",
"index": 0,
},
],
],
},
"Node2": {
"main": [
[
{
"node": "Node3",
"type": "main",
"index": 0,
},
],
],
},
};
const workflow = new Workflow({ nodes, connections, active: false, nodeTypes });
const activeNodeName = testData.input.hasOwnProperty('Node3') ? 'Node3' : 'Node2';
const runExecutionData: IRunExecutionData = {
resultData: {
runData: {
Node1: [
{
startTime: 1,
executionTime: 1,
// @ts-ignore
data: {
main: [
[
{
// @ts-ignore
json: testData.input.Node1.outputJson || testData.input.Node1.parameters,
// @ts-ignore
binary: testData.input.Node1.outputBinary,
},
],
],
},
},
],
},
},
};
const itemIndex = 0;
const runIndex = 0;
const connectionInputData: INodeExecutionData[] = runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
for (const parameterName of Object.keys(testData.output)) {
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[parameterName];
const result = workflow.expression.getParameterValue(parameterValue, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, 'manual', {});
// @ts-ignore
expect(result).toEqual(testData.output[parameterName]);
}
});
}
// test('should be able to set and read key data without initial data set', () => {
// const nodes: Node[] = [
// {
// "name": "Node1",
// "parameters": {
// "value": "outputSet1"
// },
// "type": "test.set",
// "typeVersion": 1,
// "position": [
// 100,
// 200
// ]
// },
// {
// "name": "Node2",
// "parameters": {
// "name": "=[data.propertyName]"
// },
// "type": "test.set",
// "typeVersion": 1,
// "position": [
// 100,
// 300
// ]
// }
// ];
// const connections: Connections = {
// "Node1": {
// "main": [
// [
// {
// "node": "Node2",
// "type": "main",
// "index": 0
// }
// ]
// ]
// }
// };
// const nodeTypes = Helpers.NodeTypes();
// const workflow = new Workflow({ nodes, connections, active: false, nodeTypes });
// const activeNodeName = 'Node2';
// // @ts-ignore
// const parameterValue = nodes.find((node) => node.name === activeNodeName).parameters.name;
// // const parameterValue = '=[data.propertyName]'; // TODO: Make this dynamic from node-data via "activeNodeName"!
// const runData: RunData = {
// Node1: [
// {
// startTime: 1,
// executionTime: 1,
// data: {
// main: [
// [
// {
// json: {
// propertyName: 'outputSet1'
// }
// }
// ]
// ]
// }
// }
// ]
// };
// const itemIndex = 0;
// const connectionInputData: NodeExecutionData[] = runData!['Node1']![0]!.data!.main[0]!;
// const result = workflow.getParameterValue(parameterValue, runData, itemIndex, activeNodeName, connectionInputData);
// expect(result).toEqual('outputSet1');
// });
test('should also resolve all child parameters when the parent get requested', () => {
const nodeTypes = Helpers.NodeTypes();
const nodes: INode[] = [
{
"name": "Node1",
"parameters": {
"values": {
"string": [
{
"name": "name1",
"value": "value1",
},
{
"name": "name2",
"value": "={{$parameter.values.string[0].value}}A",
},
],
},
},
"type": "test.setMulti",
"typeVersion": 1,
"position": [
100,
100,
],
},
];
const connections: IConnections = {};
const workflow = new Workflow({ nodes, connections, active: false, nodeTypes });
const activeNodeName = 'Node1';
const runExecutionData: IRunExecutionData = {
resultData: {
runData: {
Node1: [
{
startTime: 1,
executionTime: 1,
data: {
main: [
[
{
json: {},
},
],
],
},
},
],
},
},
};
const itemIndex = 0;
const runIndex = 0;
const connectionInputData: INodeExecutionData[] = runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
const parameterName = 'values';
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[parameterName];
const result = workflow.expression.getParameterValue(parameterValue, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, 'manual', {});
expect(result).toEqual({
string: [
{
name: 'name1',
value: 'value1',
},
{
name: 'name2',
value: 'value1A',
},
],
});
});
});
});