From 281e943dcce5bfa1ffffe5dec6b1285ade5ec977 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Fri, 9 Aug 2019 12:19:28 +0200 Subject: [PATCH] :heavy_check_mark: Fix tests --- packages/core/src/Interfaces.ts | 1 - packages/core/src/NodeExecuteFunctions.ts | 2 - packages/core/test/Helpers.ts | 353 +++++++++++---------- packages/core/test/WorkflowExecute.test.ts | 7 +- packages/workflow/test/Helpers.ts | 158 ++++----- 5 files changed, 274 insertions(+), 247 deletions(-) diff --git a/packages/core/src/Interfaces.ts b/packages/core/src/Interfaces.ts index 1b5274ee6f..76b6eea932 100644 --- a/packages/core/src/Interfaces.ts +++ b/packages/core/src/Interfaces.ts @@ -11,7 +11,6 @@ import { ITriggerFunctions as ITriggerFunctionsBase, IWebhookFunctions as IWebhookFunctionsBase, IWorkflowSettings as IWorkflowSettingsWorkflow, - WorkflowExecuteMode, } from 'n8n-workflow'; diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 306c32ff83..379344c328 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -3,7 +3,6 @@ import { IHookFunctions, ILoadOptionsFunctions, IWorkflowSettings, - WorkflowExecute, BINARY_ENCODING, } from './'; @@ -12,7 +11,6 @@ import { IContextObject, ICredentialDataDecryptedObject, IDataObject, - IExecuteData, IExecuteFunctions, IExecuteSingleFunctions, INode, diff --git a/packages/core/test/Helpers.ts b/packages/core/test/Helpers.ts index 2ca59e7915..d7d9e8617f 100644 --- a/packages/core/test/Helpers.ts +++ b/packages/core/test/Helpers.ts @@ -5,7 +5,7 @@ import { INodeParameters, INodeType, INodeTypes, - INodeTypesObject, + INodeTypeData, IRun, ITaskData, IWorkflowExecuteAdditionalData, @@ -19,201 +19,218 @@ import { class NodeTypesClass implements INodeTypes { - nodeTypes: INodeTypesObject = { + nodeTypes: INodeTypeData = { 'n8n-nodes-base.merge': { - description: { - displayName: 'Merge', - name: 'merge', - icon: 'fa:clone', - group: ['transform'], - version: 1, - description: 'Merges data of multiple streams once data of both is available', - defaults: { - name: 'Merge', - color: '#00cc22', - }, - inputs: ['main', 'main'], - outputs: ['main'], - properties: [ - { - displayName: 'Mode', - name: 'mode', - type: 'options', - options: [ - { - name: 'Append', - value: 'append', - description: 'Combines data of both inputs. The output will contain items of input 1 and input 2.', - }, - { - name: 'Pass-through', - value: 'passThrough', - description: 'Passes through data of one input. The output will conain only items of the defined input.', - }, - { - name: 'Wait', - value: 'wait', - description: 'Waits till data of both inputs is available and will then output a single empty item.', - }, - ], - default: 'append', - description: 'How data should be merged. If it should simply
be appended or merged depending on a property.', + sourcePath: '', + type: { + description: { + displayName: 'Merge', + name: 'merge', + icon: 'fa:clone', + group: ['transform'], + version: 1, + description: 'Merges data of multiple streams once data of both is available', + defaults: { + name: 'Merge', + color: '#00cc22', }, - { - displayName: 'Output Data', - name: 'output', - type: 'options', - displayOptions: { - show: { - mode: [ - 'passThrough' - ], - }, + inputs: ['main', 'main'], + outputs: ['main'], + properties: [ + { + displayName: 'Mode', + name: 'mode', + type: 'options', + options: [ + { + name: 'Append', + value: 'append', + description: 'Combines data of both inputs. The output will contain items of input 1 and input 2.', + }, + { + name: 'Pass-through', + value: 'passThrough', + description: 'Passes through data of one input. The output will conain only items of the defined input.', + }, + { + name: 'Wait', + value: 'wait', + description: 'Waits till data of both inputs is available and will then output a single empty item.', + }, + ], + default: 'append', + description: 'How data should be merged. If it should simply
be appended or merged depending on a property.', }, - options: [ - { - name: 'Input 1', - value: 'input1', + { + displayName: 'Output Data', + name: 'output', + type: 'options', + displayOptions: { + show: { + mode: [ + 'passThrough' + ], + }, }, - { - name: 'Input 2', - value: 'input2', - }, - ], - default: 'input1', - description: 'Defines of which input the data should be used as output of node.', - }, - ] - }, - async execute(this: IExecuteFunctions): Promise { - // const itemsInput2 = this.getInputData(1); + options: [ + { + name: 'Input 1', + value: 'input1', + }, + { + name: 'Input 2', + value: 'input2', + }, + ], + default: 'input1', + description: 'Defines of which input the data should be used as output of node.', + }, + ] + }, + async execute(this: IExecuteFunctions): Promise { + // const itemsInput2 = this.getInputData(1); - const returnData: INodeExecutionData[] = []; + const returnData: INodeExecutionData[] = []; - const mode = this.getNodeParameter('mode', 0) as string; + const mode = this.getNodeParameter('mode', 0) as string; - if (mode === 'append') { - // Simply appends the data - for (let i = 0; i < 2; i++) { - returnData.push.apply(returnData, this.getInputData(i)); + if (mode === 'append') { + // Simply appends the data + for (let i = 0; i < 2; i++) { + returnData.push.apply(returnData, this.getInputData(i)); + } + } else if (mode === 'passThrough') { + const output = this.getNodeParameter('output', 0) as string; + + if (output === 'input1') { + returnData.push.apply(returnData, this.getInputData(0)); + } else { + returnData.push.apply(returnData, this.getInputData(1)); + } + } else if (mode === 'wait') { + returnData.push({ json: {} }); } - } else if (mode === 'passThrough') { - const output = this.getNodeParameter('output', 0) as string; - if (output === 'input1') { - returnData.push.apply(returnData, this.getInputData(0)); - } else { - returnData.push.apply(returnData, this.getInputData(1)); - } - } else if (mode === 'wait') { - returnData.push({ json: {} }); + return [returnData]; } - - return [returnData]; - } + }, }, 'n8n-nodes-base.set': { - description: { - displayName: 'Set', - name: 'set', - group: ['input'], - version: 1, - description: 'Sets a value', - defaults: { - name: 'Set', - color: '#0000FF', - }, - inputs: ['main'], - outputs: ['main'], - properties: [ - { - displayName: 'Keep Only Set', - name: 'keepOnlySet', - type: 'boolean', - default: false, - description: 'If only the values set on this node should be
kept and all others removed.', + sourcePath: '', + type: { + description: { + displayName: 'Set', + name: 'set', + group: ['input'], + version: 1, + description: 'Sets a value', + defaults: { + name: 'Set', + color: '#0000FF', }, - { - displayName: 'Values to Set', - name: 'values', - placeholder: 'Add Value', - type: 'fixedCollection', - typeOptions: { - multipleValues: true, + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Keep Only Set', + name: 'keepOnlySet', + type: 'boolean', + default: false, + description: 'If only the values set on this node should be
kept and all others removed.', }, - description: 'The value to set.', - default: {}, - options: [ - { - name: 'number', - displayName: 'Number', - values: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: 'propertyName', - description: 'Name of the property to write data to.
Supports dot-notation.
Example: "data.person[0].name"', - }, - { - displayName: 'Value', - name: 'value', - type: 'number', - default: 0, - description: 'The number value to write in the property.', - }, - ] + { + displayName: 'Values to Set', + name: 'values', + placeholder: 'Add Value', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, }, - ], - }, - ] - }, - execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); + description: 'The value to set.', + default: {}, + options: [ + { + name: 'number', + displayName: 'Number', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: 'propertyName', + description: 'Name of the property to write data to.
Supports dot-notation.
Example: "data.person[0].name"', + }, + { + displayName: 'Value', + name: 'value', + type: 'number', + default: 0, + description: 'The number value to write in the property.', + }, + ] + }, + ], + }, + ] + }, + execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); - let item: INodeExecutionData; - for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { - item = items[itemIndex]; - // Add number values - (this.getNodeParameter('values.number', itemIndex, []) as INodeParameters[]).forEach((setItem) => { - set(item.json, setItem.name as string, setItem.value); - }); + const returnData: INodeExecutionData[] = []; + let item: INodeExecutionData; + for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { + item = items[itemIndex]; + + const newItem: INodeExecutionData = { + json: JSON.parse(JSON.stringify(item.json)), + }; + + // Add number values + (this.getNodeParameter('values.number', itemIndex, []) as INodeParameters[]).forEach((setItem) => { + set(newItem.json, setItem.name as string, setItem.value); + }); + + returnData.push(newItem); + } + + return this.prepareOutputData(returnData); } - - return this.prepareOutputData(items); - } + }, }, 'n8n-nodes-base.start': { - description: { - displayName: 'Start', - name: 'start', - group: ['input'], - version: 1, - description: 'Starts the workflow execution from this node', - defaults: { - name: 'Start', - color: '#553399', + sourcePath: '', + type: { + description: { + displayName: 'Start', + name: 'start', + group: ['input'], + version: 1, + description: 'Starts the workflow execution from this node', + defaults: { + name: 'Start', + color: '#553399', + }, + inputs: [], + outputs: ['main'], + properties: [] }, - inputs: [], - outputs: ['main'], - properties: [] - }, - execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); + execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); - return this.prepareOutputData(items); + return this.prepareOutputData(items); + }, }, }, }; - async init(nodeTypes: INodeTypesObject): Promise { } + async init(nodeTypes: INodeTypeData): Promise { } getAll(): INodeType[] { - return Object.values(this.nodeTypes); + return Object.values(this.nodeTypes).map((data) => data.type); } getByName(nodeType: string): INodeType { - return this.nodeTypes[nodeType]; + return this.nodeTypes[nodeType].type; } } @@ -235,12 +252,12 @@ export function WorkflowExecuteAdditionalData(waitPromise: IDeferredPromise => { + async (nodeName: string, data: ITaskData): Promise => { nodeExecutionOrder.push(nodeName); }, ], workflowExecuteAfter: [ - async (fullRunData: IRun, executionId: string): Promise => { + async (fullRunData: IRun): Promise => { waitPromise.resolve(fullRunData); }, ], diff --git a/packages/core/test/WorkflowExecute.test.ts b/packages/core/test/WorkflowExecute.test.ts index 387d1b36f5..9083252c6c 100644 --- a/packages/core/test/WorkflowExecute.test.ts +++ b/packages/core/test/WorkflowExecute.test.ts @@ -587,11 +587,14 @@ describe('WorkflowExecute', () => { const workflowExecute = new WorkflowExecute(additionalData, executionMode); - const executionId = await workflowExecute.run(workflowInstance, undefined); - expect(executionId).toBeDefined(); + const executionData = await workflowExecute.run(workflowInstance, undefined); 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) { diff --git a/packages/workflow/test/Helpers.ts b/packages/workflow/test/Helpers.ts index da51347419..8b5cb3d2aa 100644 --- a/packages/workflow/test/Helpers.ts +++ b/packages/workflow/test/Helpers.ts @@ -1,99 +1,109 @@ import { INodeType, INodeTypes, - INodeTypesObject, + INodeTypeData, } from '../src'; +export interface INodeTypesObject { + [key: string]: INodeType; +} + class NodeTypesClass implements INodeTypes { - nodeTypes: INodeTypesObject = { + nodeTypes: INodeTypeData = { 'test.set': { - description: { - displayName: 'Set', - name: 'set', - group: ['input'], - version: 1, - description: 'Sets a value', - defaults: { - name: 'Set', - color: '#0000FF', - }, - inputs: ['main'], - outputs: ['main'], - properties: [ - { - displayName: 'Value1', - name: 'value1', - type: 'string', - default: 'default-value1', + sourcePath: '', + type: { + description: { + displayName: 'Set', + name: 'set', + group: ['input'], + version: 1, + description: 'Sets a value', + defaults: { + name: 'Set', + color: '#0000FF', }, - { - displayName: 'Value2', - name: 'value2', - type: 'string', - default: 'default-value2', - } - ] + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Value1', + name: 'value1', + type: 'string', + default: 'default-value1', + }, + { + displayName: 'Value2', + name: 'value2', + type: 'string', + default: 'default-value2', + } + ] + } } }, 'test.setMulti': { - description: { - displayName: 'Set Multi', - name: 'setMulti', - group: ['input'], - version: 1, - description: 'Sets multiple values', - defaults: { - name: 'Set Multi', - color: '#0000FF', - }, - inputs: ['main'], - outputs: ['main'], - properties: [ - { - displayName: 'Values', - name: 'values', - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - default: {}, - options: [ - { - name: 'string', - displayName: 'String', - values: [ - { - displayName: 'Name', - name: 'name', - type: 'string', - default: 'propertyName', - placeholder: 'Name of the property to write data to.', - }, - { - displayName: 'Value', - name: 'value', - type: 'string', - default: '', - placeholder: 'The string value to write in the property.', - }, - ] - }, - ], + sourcePath: '', + type: { + description: { + displayName: 'Set Multi', + name: 'setMulti', + group: ['input'], + version: 1, + description: 'Sets multiple values', + defaults: { + name: 'Set Multi', + color: '#0000FF', }, - ] + inputs: ['main'], + outputs: ['main'], + properties: [ + { + displayName: 'Values', + name: 'values', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'string', + displayName: 'String', + values: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: 'propertyName', + placeholder: 'Name of the property to write data to.', + }, + { + displayName: 'Value', + name: 'value', + type: 'string', + default: '', + placeholder: 'The string value to write in the property.', + }, + ] + }, + ], + }, + ] + } } }, }; - async init(nodeTypes: INodeTypesObject): Promise { } + async init(nodeTypes: INodeTypeData): Promise { } getAll(): INodeType[] { - return Object.values(this.nodeTypes); + return Object.values(this.nodeTypes).map((data) => data.type); } getByName(nodeType: string): INodeType { - return this.nodeTypes[nodeType]; + return this.nodeTypes[nodeType].type; } }