diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index 7fb705ff63..700cef1c1e 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -599,8 +599,57 @@ export class WorkflowExecute { break; } + let nodeInputData = executionData.data; + const changesIncomingData = workflow.getNodeChangesData(executionData.node); + + if (executionData.node.disabled !== true) { + + if (changesIncomingData.value !== false) { + // Data has to be copied + + // Copy only the data which is needed + const copyKeys = changesIncomingData.keys!.split(','); + + const allInputsData = executionData.data.main; + let inputData: INodeExecutionData[] | null; + const newAllInputsData: Array = []; + let newEntries: INodeExecutionData[]; + let newEntry: INodeExecutionData; + for (let inputIndex = 0; inputIndex < allInputsData.length; inputIndex++) { + inputData = allInputsData[inputIndex]; + if (inputData === null) { + newAllInputsData.push(null); + continue; + } + + newEntries = []; + for (const entry of inputData) { + newEntry = { + json: {}, + }; + for (const key of Object.keys(entry)) { + if (copyKeys.includes(key)) { + newEntry[key] = JSON.parse(JSON.stringify(entry[key])); + } else { + // Data does NOT have to get copied + newEntry[key] = entry[key]; + } + } + + + newEntries.push(newEntry); + } + newAllInputsData.push(newEntries); + } + + nodeInputData = { + main: newAllInputsData, + }; + } + } + runExecutionData.resultData.lastNodeExecuted = executionData.node.name; - nodeSuccessData = await workflow.runNode(executionData.node, JSON.parse(JSON.stringify(executionData.data)), runExecutionData, runIndex, this.additionalData, NodeExecuteFunctions, this.mode); + nodeSuccessData = await workflow.runNode(executionData.node, nodeInputData, runExecutionData, runIndex, this.additionalData, NodeExecuteFunctions, this.mode); if (nodeSuccessData === null) { // If null gets returned it means that the node did succeed diff --git a/packages/node-dev/README.md b/packages/node-dev/README.md index 0d88644c16..d5d3729a86 100644 --- a/packages/node-dev/README.md +++ b/packages/node-dev/README.md @@ -157,7 +157,7 @@ Property overview The following properties can be set in the node description: - - **credentials** [optional]: Credentials the node requests access to + - **changesIncomingData** [optional]: Object with "keys" and "value" If value is set to true it means that incomign data gets changed. If that is the case then "keys" can additionally be set to define which data (binary,json) gets changed. - **defaults** [required]: Default "name" and "color" to set on node when it gets created - **displayName** [required]: Name to display users in Editor UI - **description** [required]: Description to display users in Editor UI diff --git a/packages/nodes-base/nodes/Cron.node.ts b/packages/nodes-base/nodes/Cron.node.ts index e361929531..128a4f832f 100644 --- a/packages/nodes-base/nodes/Cron.node.ts +++ b/packages/nodes-base/nodes/Cron.node.ts @@ -31,6 +31,9 @@ export class Cron implements INodeType { }, inputs: [], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Trigger Times', diff --git a/packages/nodes-base/nodes/EmailReadImap.node.ts b/packages/nodes-base/nodes/EmailReadImap.node.ts index 9ef58802e7..1f20537a7b 100644 --- a/packages/nodes-base/nodes/EmailReadImap.node.ts +++ b/packages/nodes-base/nodes/EmailReadImap.node.ts @@ -30,6 +30,9 @@ export class EmailReadImap implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Mailbox Name', diff --git a/packages/nodes-base/nodes/EmailSend.node.ts b/packages/nodes-base/nodes/EmailSend.node.ts index b5cebaae05..bef05e0b1d 100644 --- a/packages/nodes-base/nodes/EmailSend.node.ts +++ b/packages/nodes-base/nodes/EmailSend.node.ts @@ -31,6 +31,9 @@ export class EmailSend implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ // TODO: Add cc, bcc and choice for text as text or html (maybe also from name) { diff --git a/packages/nodes-base/nodes/ErrorTrigger.node.ts b/packages/nodes-base/nodes/ErrorTrigger.node.ts index 434f34cd1e..dc82db3da6 100644 --- a/packages/nodes-base/nodes/ErrorTrigger.node.ts +++ b/packages/nodes-base/nodes/ErrorTrigger.node.ts @@ -21,6 +21,9 @@ export class ErrorTrigger implements INodeType { }, inputs: [], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [] }; diff --git a/packages/nodes-base/nodes/ExecuteCommand.node.ts b/packages/nodes-base/nodes/ExecuteCommand.node.ts index 1d57e9084a..0c365e3a22 100644 --- a/packages/nodes-base/nodes/ExecuteCommand.node.ts +++ b/packages/nodes-base/nodes/ExecuteCommand.node.ts @@ -58,6 +58,9 @@ export class ExecuteCommand implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Execute Once', diff --git a/packages/nodes-base/nodes/Function.node.ts b/packages/nodes-base/nodes/Function.node.ts index 622fbd1436..74b0913f4c 100644 --- a/packages/nodes-base/nodes/Function.node.ts +++ b/packages/nodes-base/nodes/Function.node.ts @@ -21,6 +21,10 @@ export class Function implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'json,binary', + }, properties: [ { displayName: 'Function', diff --git a/packages/nodes-base/nodes/FunctionItem.node.ts b/packages/nodes-base/nodes/FunctionItem.node.ts index 694bbc36f3..659fb0b79a 100644 --- a/packages/nodes-base/nodes/FunctionItem.node.ts +++ b/packages/nodes-base/nodes/FunctionItem.node.ts @@ -23,6 +23,10 @@ export class FunctionItem implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'json,binary', + }, properties: [ { displayName: 'Function', diff --git a/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts b/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts index 5b021b97a0..7bac6587e4 100644 --- a/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts +++ b/packages/nodes-base/nodes/GoogleSheets/GoogleSheets.node.ts @@ -27,6 +27,9 @@ export class GoogleSheets implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, credentials: [ { name: 'googleApi', diff --git a/packages/nodes-base/nodes/HttpRequest.node.ts b/packages/nodes-base/nodes/HttpRequest.node.ts index 5ec9250519..bfe5d6a05b 100644 --- a/packages/nodes-base/nodes/HttpRequest.node.ts +++ b/packages/nodes-base/nodes/HttpRequest.node.ts @@ -32,6 +32,9 @@ export class HttpRequest implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, credentials: [ { name: 'httpBasicAuth', diff --git a/packages/nodes-base/nodes/If.node.ts b/packages/nodes-base/nodes/If.node.ts index 34241a37ac..fa0f732f00 100644 --- a/packages/nodes-base/nodes/If.node.ts +++ b/packages/nodes-base/nodes/If.node.ts @@ -23,6 +23,9 @@ export class If implements INodeType { inputs: ['main'], outputs: ['main', 'main'], outputNames: ['true', 'false'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Conditions', diff --git a/packages/nodes-base/nodes/Interval.node.ts b/packages/nodes-base/nodes/Interval.node.ts index 328833f3f2..938479c9e2 100644 --- a/packages/nodes-base/nodes/Interval.node.ts +++ b/packages/nodes-base/nodes/Interval.node.ts @@ -20,6 +20,9 @@ export class Interval implements INodeType { }, inputs: [], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Interval', diff --git a/packages/nodes-base/nodes/Merge.node.ts b/packages/nodes-base/nodes/Merge.node.ts index 8262410db8..86189fe999 100644 --- a/packages/nodes-base/nodes/Merge.node.ts +++ b/packages/nodes-base/nodes/Merge.node.ts @@ -22,6 +22,10 @@ export class Merge implements INodeType { }, inputs: ['main', 'main'], outputs: ['main'], + changesIncomingData: { + value: '={{$parameter["mode"] === "merge"}}', + keys: 'json', + }, properties: [ { displayName: 'Mode', diff --git a/packages/nodes-base/nodes/NoOp.node.ts b/packages/nodes-base/nodes/NoOp.node.ts index 3c9a97af6a..9d1dc7293c 100644 --- a/packages/nodes-base/nodes/NoOp.node.ts +++ b/packages/nodes-base/nodes/NoOp.node.ts @@ -20,6 +20,9 @@ export class NoOp implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ ], }; diff --git a/packages/nodes-base/nodes/OpenWeatherMap.node.ts b/packages/nodes-base/nodes/OpenWeatherMap.node.ts index e12e384094..5d3ff90284 100644 --- a/packages/nodes-base/nodes/OpenWeatherMap.node.ts +++ b/packages/nodes-base/nodes/OpenWeatherMap.node.ts @@ -30,6 +30,9 @@ export class OpenWeatherMap implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Operation', diff --git a/packages/nodes-base/nodes/ReadBinaryFile.node.ts b/packages/nodes-base/nodes/ReadBinaryFile.node.ts index ced2a60b1e..bfcb21344e 100644 --- a/packages/nodes-base/nodes/ReadBinaryFile.node.ts +++ b/packages/nodes-base/nodes/ReadBinaryFile.node.ts @@ -27,6 +27,10 @@ export class ReadBinaryFile implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'binary', + }, properties: [ { displayName: 'File Path', diff --git a/packages/nodes-base/nodes/ReadBinaryFiles.node.ts b/packages/nodes-base/nodes/ReadBinaryFiles.node.ts index 072619f2f4..98db951f9e 100644 --- a/packages/nodes-base/nodes/ReadBinaryFiles.node.ts +++ b/packages/nodes-base/nodes/ReadBinaryFiles.node.ts @@ -29,6 +29,9 @@ export class ReadBinaryFiles implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'File Selector', diff --git a/packages/nodes-base/nodes/ReadFileFromUrl.node.ts b/packages/nodes-base/nodes/ReadFileFromUrl.node.ts index 3d31c56d34..c1c2dfc562 100644 --- a/packages/nodes-base/nodes/ReadFileFromUrl.node.ts +++ b/packages/nodes-base/nodes/ReadFileFromUrl.node.ts @@ -21,6 +21,10 @@ export class ReadFileFromUrl implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'binary', + }, properties: [ { displayName: 'URL', diff --git a/packages/nodes-base/nodes/ReadPdf.node.ts b/packages/nodes-base/nodes/ReadPdf.node.ts index c9ddfd6338..538c7e2d7d 100644 --- a/packages/nodes-base/nodes/ReadPdf.node.ts +++ b/packages/nodes-base/nodes/ReadPdf.node.ts @@ -25,6 +25,10 @@ export class ReadPdf implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'json', + }, properties: [ { displayName: 'Binary Property', diff --git a/packages/nodes-base/nodes/RenameKeys.node.ts b/packages/nodes-base/nodes/RenameKeys.node.ts index fa02b602e7..de05794ad6 100644 --- a/packages/nodes-base/nodes/RenameKeys.node.ts +++ b/packages/nodes-base/nodes/RenameKeys.node.ts @@ -30,6 +30,10 @@ export class RenameKeys implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'json', + }, properties: [ { displayName: 'Keys', diff --git a/packages/nodes-base/nodes/RssFeedRead.node.ts b/packages/nodes-base/nodes/RssFeedRead.node.ts index b96f3d6e0b..05d7e63821 100644 --- a/packages/nodes-base/nodes/RssFeedRead.node.ts +++ b/packages/nodes-base/nodes/RssFeedRead.node.ts @@ -22,6 +22,9 @@ export class RssFeedRead implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'URL', diff --git a/packages/nodes-base/nodes/Set.node.ts b/packages/nodes-base/nodes/Set.node.ts index 40f0698e7c..fc149822d6 100644 --- a/packages/nodes-base/nodes/Set.node.ts +++ b/packages/nodes-base/nodes/Set.node.ts @@ -20,6 +20,10 @@ export class Set implements INodeType { name: 'Set', color: '#0000FF', }, + changesIncomingData: { + value: true, + keys: 'json', + }, inputs: ['main'], outputs: ['main'], properties: [ diff --git a/packages/nodes-base/nodes/Slack/Slack.node.ts b/packages/nodes-base/nodes/Slack/Slack.node.ts index c20f8ba12b..ad2b73ba08 100644 --- a/packages/nodes-base/nodes/Slack/Slack.node.ts +++ b/packages/nodes-base/nodes/Slack/Slack.node.ts @@ -33,6 +33,9 @@ export class Slack implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Resource', diff --git a/packages/nodes-base/nodes/SplitInBatches.node.ts b/packages/nodes-base/nodes/SplitInBatches.node.ts index 55a6f5d34a..f1cad44f66 100644 --- a/packages/nodes-base/nodes/SplitInBatches.node.ts +++ b/packages/nodes-base/nodes/SplitInBatches.node.ts @@ -20,6 +20,10 @@ export class SplitInBatches implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: true, + keys: 'json', + }, properties: [ { displayName: 'Batch Size', diff --git a/packages/nodes-base/nodes/SpreadsheetFile.node.ts b/packages/nodes-base/nodes/SpreadsheetFile.node.ts index ac76a02e28..e8383d3ff7 100644 --- a/packages/nodes-base/nodes/SpreadsheetFile.node.ts +++ b/packages/nodes-base/nodes/SpreadsheetFile.node.ts @@ -58,6 +58,9 @@ export class SpreadsheetFile implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Operation', diff --git a/packages/nodes-base/nodes/Start.node.ts b/packages/nodes-base/nodes/Start.node.ts index 81e01892c5..b6c08013f2 100644 --- a/packages/nodes-base/nodes/Start.node.ts +++ b/packages/nodes-base/nodes/Start.node.ts @@ -21,6 +21,9 @@ export class Start implements INodeType { }, inputs: [], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ ], }; diff --git a/packages/nodes-base/nodes/Trello/Trello.node.ts b/packages/nodes-base/nodes/Trello/Trello.node.ts index 89b8079323..103e4dce12 100644 --- a/packages/nodes-base/nodes/Trello/Trello.node.ts +++ b/packages/nodes-base/nodes/Trello/Trello.node.ts @@ -33,6 +33,9 @@ export class Trello implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Resource', diff --git a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts index d32b3dee90..3461c2d4e3 100644 --- a/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts +++ b/packages/nodes-base/nodes/Trello/TrelloTrigger.node.ts @@ -37,6 +37,9 @@ export class TrelloTrigger implements INodeType { required: true, }, ], + changesIncomingData: { + value: false, + }, webhooks: [ { name: 'setup', diff --git a/packages/nodes-base/nodes/Twilio/Twilio.node.ts b/packages/nodes-base/nodes/Twilio/Twilio.node.ts index 479cb11e61..e965cd2366 100644 --- a/packages/nodes-base/nodes/Twilio/Twilio.node.ts +++ b/packages/nodes-base/nodes/Twilio/Twilio.node.ts @@ -33,6 +33,9 @@ export class Twilio implements INodeType { required: true, } ], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'Resource', diff --git a/packages/nodes-base/nodes/Webhook.node.ts b/packages/nodes-base/nodes/Webhook.node.ts index 58ed435f27..3bc80935e1 100644 --- a/packages/nodes-base/nodes/Webhook.node.ts +++ b/packages/nodes-base/nodes/Webhook.node.ts @@ -43,6 +43,9 @@ export class Webhook implements INodeType { }, inputs: [], outputs: ['main'], + changesIncomingData: { + value: false, + }, credentials: [ { name: 'httpBasicAuth', diff --git a/packages/nodes-base/nodes/WriteBinaryFile.node.ts b/packages/nodes-base/nodes/WriteBinaryFile.node.ts index 403c8d3a6a..89b86d025f 100644 --- a/packages/nodes-base/nodes/WriteBinaryFile.node.ts +++ b/packages/nodes-base/nodes/WriteBinaryFile.node.ts @@ -31,6 +31,9 @@ export class WriteBinaryFile implements INodeType { }, inputs: ['main'], outputs: ['main'], + changesIncomingData: { + value: false, + }, properties: [ { displayName: 'File Name', diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index e8a155cfdd..0e2fa90df7 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -394,6 +394,11 @@ export interface IWorfklowIssues { [key: string]: INodeIssues; } +export interface IChangesIncomingData { + value?: string | boolean; + keys?: string; +} + export interface INodeTypeDescription { displayName: string; name: string; @@ -409,6 +414,7 @@ export interface INodeTypeDescription { credentials?: INodeCredentialDescription[]; maxNodes?: number; // How many nodes of that type can be created in a workflow subtitle?: string; + changesIncomingData?: IChangesIncomingData; hooks?: { [key: string]: INodeHookDescription[] | undefined; activate?: INodeHookDescription[]; diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index 870699fdfe..14360e5535 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -1,33 +1,36 @@ import { + IChangesIncomingData, + IConnection, IConnections, + IDataObject, INode, - NodeHelpers, INodes, INodeExecuteFunctions, INodeExecutionData, INodeParameters, INodeIssues, - NodeParameterValue, INodeType, INodeTypes, - ObservableObject, + IObservableObject, IRunExecutionData, ITaskDataConnections, ITriggerResponse, IWebhookData, IWebhookResonseData, - WebhookSetupMethodNames, - WorkflowDataProxy, IWorfklowIssues, IWorkflowExecuteAdditionalData, - WorkflowExecuteMode, IWorkflowSettings, + NodeHelpers, + NodeParameterValue, + ObservableObject, + WebhookSetupMethodNames, + WorkflowDataProxy, + WorkflowExecuteMode, } from './'; // @ts-ignore import * as tmpl from 'riot-tmpl'; -import { IConnection, IDataObject, IObservableObject } from './Interfaces'; // Set it to use double curly brackets instead of single ones tmpl.brackets.set('{{ }}'); @@ -329,6 +332,77 @@ export class Workflow { } + /** + * Returns if the node with the given name changes the + * incoming data + * + * @param {INode} node The node to get the data of + * @returns {boolean} + * @memberof Workflow + */ + getNodeChangesData(node: INode): IChangesIncomingData { + const nodeType = this.nodeTypes.getByName(node.type); + if (nodeType === undefined) { + throw new Error(`The node type "${node.type}" of node "${node.name}" does not known.`); + } + + const returnData: IChangesIncomingData = { + value: true, + keys: 'binary,json', + }; + + if (nodeType.description.changesIncomingData === undefined) { + // If not specifially defined that it does not change the data + // assume that it does as it would mess up everything afterwards + // if it returns "false" and then would still change data. + return returnData; + } + + // Get the value for "value" + if (typeof nodeType.description.changesIncomingData.value === 'boolean') { + returnData.value = nodeType.description.changesIncomingData.value; + } else if (nodeType.description.changesIncomingData.value !== undefined) { + const changesIncomingDataValue = this.getSimpleParameterValue(node, nodeType.description.changesIncomingData.value, 'true') as boolean | string; + + if (typeof changesIncomingDataValue === 'boolean') { + returnData.value = changesIncomingDataValue; + } else { + returnData.value = !(changesIncomingDataValue.toString().toLowerCase() === 'false'); + } + } + + // Get the value for "keys" + if (returnData.value === true && nodeType.description.changesIncomingData.keys !== undefined) { + const changesIncomingDataKeys = this.getSimpleParameterValue(node, nodeType.description.changesIncomingData.keys, 'binary,json') as string; + + // Check if data is valid + if (typeof changesIncomingDataKeys !== 'string') { + throw new Error(`The data "${changesIncomingDataKeys}" for "changesIncomingData.keys" is not of type string.`); + } + + const dataKeys = changesIncomingDataKeys.split(','); + const validKeys = ['binary', 'json']; + for (const key of dataKeys) { + if (!validKeys.includes(key)) { + throw new Error(`The key "${key}" for "changesIncomingData.keys" is not valid. Only the following keys are allowed: ${validKeys.join(',')}`); + } + } + + // Data is valid so set it + returnData.keys = changesIncomingDataKeys; + } + + if (returnData.value === false) { + return { + value: false, + }; + } + + return returnData; + } + + + /** * Renames nodes in expressions * diff --git a/packages/workflow/test/Workflow.test.ts b/packages/workflow/test/Workflow.test.ts index ad9280f47d..f770f0b662 100644 --- a/packages/workflow/test/Workflow.test.ts +++ b/packages/workflow/test/Workflow.test.ts @@ -3,6 +3,9 @@ import { INode, INodeExecutionData, INodeParameters, + INodeType, + INodeTypes, + INodeTypesObject, IRunExecutionData, Workflow, } from '../src'; @@ -149,6 +152,238 @@ describe('Workflow', () => { }); + describe('getNodeChangesData', () => { + + const tests = [ + { + description: 'should return boolean false if boolean false is set', + input: { + nodeParameters: {}, + changesIncomingData: { + value: false, + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return boolean false if string false is set', + input: { + nodeParameters: {}, + changesIncomingData: { + value: 'false', + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return only boolean false if boolean false is set with keys', + input: { + nodeParameters: {}, + changesIncomingData: { + value: false, + keys: 'binary,json', + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return boolean true with all keys if boolean true is set', + input: { + nodeParameters: {}, + changesIncomingData: { + value: true, + }, + }, + output: { + value: true, + keys: 'binary,json', + }, + }, + { + description: 'should return boolean true with defined keys if boolean true is set', + input: { + nodeParameters: {}, + changesIncomingData: { + value: true, + keys: 'json', + }, + }, + output: { + value: true, + keys: 'json', + }, + }, + { + description: 'should return boolean true with all keys if string true is set', + input: { + nodeParameters: {}, + changesIncomingData: { + value: 'true', + }, + }, + output: { + value: true, + keys: 'binary,json', + }, + }, + { + description: 'should return boolean false when expression returns boolean false', + input: { + nodeParameters: {}, + changesIncomingData: { + value: '={{false}}', + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return boolean false when parameter-expression to boolean parameter returns boolean false', + input: { + nodeParameters: { + nodeBooleanParameter: false, + }, + changesIncomingData: { + value: '={{$parameter["nodeBooleanParameter"]}}', + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return boolean false when parameter-expression to boolean parameter returns boolean false', + input: { + nodeParameters: { + nodeBooleanParameter: true, + }, + changesIncomingData: { + value: '={{$parameter["nodeBooleanParameter"]}}', + }, + }, + output: { + value: true, + keys: 'binary,json', + }, + }, + { + description: 'should return boolean false when parameter-expression to string parameter returns string false', + input: { + nodeParameters: { + nodeStringParameter: 'false', + }, + changesIncomingData: { + value: '={{$parameter["nodeStringParameter"]}}', + }, + }, + output: { + value: false, + }, + }, + { + description: 'should return boolean true when parameter-expression to string parameter returns string true', + input: { + nodeParameters: { + nodeStringParameter: 'true', + }, + changesIncomingData: { + value: '={{$parameter["nodeStringParameter"]}}', + }, + }, + output: { + value: true, + keys: 'binary,json', + }, + }, + ]; + + + for (const testData of tests) { + test(testData.description, async () => { + + const node: INode = { + name: 'Test node', + parameters: {}, + type: 'test.set', + typeVersion: 1, + position: [ + 100, + 100, + ], + }; + + class NodeTypesClass implements INodeTypes { + nodeTypes: INodeTypesObject = {}; + + async init(nodeTypes: INodeTypesObject): Promise { + this.nodeTypes = nodeTypes; + } + + getAll(): INodeType[] { + return Object.values(this.nodeTypes); + } + + getByName(nodeType: string): INodeType { + return this.nodeTypes[nodeType]; + } + } + + const nodeTypeData: INodeType = { + description: { + displayName: 'Set', + name: 'set', + group: ['input'], + version: 1, + description: 'Sets a value', + defaults: { + name: 'Set', + color: '#0000FF', + }, + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Node String Parameter', + name: 'nodeStringParameter', + type: 'string', + default: 'default-value', + }, + { + displayName: 'Node Boolean Parameter', + name: 'nodeBooleanParameter', + type: 'boolean', + default: false, + }, + ] + } + }; + + Object.assign(nodeTypeData.description, { changesIncomingData: testData.input.changesIncomingData }); + Object.assign(node.parameters, testData.input.nodeParameters); + + const nodeTypesData: INodeTypesObject = { + 'test.set': nodeTypeData, + }; + + const nodeTypes = new NodeTypesClass(); + await nodeTypes.init(nodeTypesData); + + const workflow = new Workflow(undefined, [ node ], {}, false, nodeTypes); + const nodeChangesData = workflow.getNodeChangesData(node); + + expect(nodeChangesData).toEqual(testData.output); + }); + } + }); + + describe('renameNode', () => { const tests = [