diff --git a/packages/core/test/helpers/index.ts b/packages/core/test/helpers/index.ts index fc0717188b..5f935ef850 100644 --- a/packages/core/test/helpers/index.ts +++ b/packages/core/test/helpers/index.ts @@ -4,14 +4,8 @@ import { readdirSync, readFileSync } from 'fs'; const BASE_DIR = path.resolve(__dirname, '../../..'); import type { - ICredentialDataDecryptedObject, IDataObject, IDeferredPromise, - IExecuteWorkflowInfo, - IHttpRequestHelper, - IHttpRequestOptions, - INode, - INodeCredentialsDetails, INodeType, INodeTypes, IRun, @@ -24,66 +18,13 @@ import type { INodeTypeData, } from 'n8n-workflow'; -import { ApplicationError, ICredentialsHelper, NodeHelpers, WorkflowHooks } from 'n8n-workflow'; -import { Credentials } from '@/Credentials'; +import { ApplicationError, NodeHelpers, WorkflowHooks } from 'n8n-workflow'; import { predefinedNodesTypes } from './constants'; - -export class CredentialsHelper extends ICredentialsHelper { - async authenticate( - credentials: ICredentialDataDecryptedObject, - typeName: string, - requestParams: IHttpRequestOptions, - ): Promise { - return requestParams; - } - - async preAuthentication( - helpers: IHttpRequestHelper, - credentials: ICredentialDataDecryptedObject, - typeName: string, - node: INode, - credentialsExpired: boolean, - ): Promise { - return undefined; - } - - getParentTypes(name: string): string[] { - return []; - } - - async getDecrypted( - additionalData: IWorkflowExecuteAdditionalData, - nodeCredentials: INodeCredentialsDetails, - type: string, - ): Promise { - return {}; - } - - async getCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, - ): Promise { - return new Credentials({ id: null, name: '' }, '', [], ''); - } - - async updateCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, - data: ICredentialDataDecryptedObject, - ): Promise {} -} +import { mock } from 'jest-mock-extended'; class NodeTypesClass implements INodeTypes { - nodeTypes: INodeTypeData; - - constructor(nodeTypes?: INodeTypeData) { - if (nodeTypes) { - this.nodeTypes = nodeTypes; - } else { - this.nodeTypes = predefinedNodesTypes; - } - } + constructor(private nodeTypes: INodeTypeData = predefinedNodesTypes) {} getByName(nodeType: string): INodeType | IVersionedNodeType { return this.nodeTypes[nodeType].type; @@ -92,11 +33,15 @@ class NodeTypesClass implements INodeTypes { getByNameAndVersion(nodeType: string, version?: number): INodeType { return NodeHelpers.getVersionedNodeType(this.nodeTypes[nodeType].type, version); } + + getKnownTypes(): IDataObject { + throw new Error('Method not implemented.'); + } } let nodeTypesInstance: NodeTypesClass | undefined; -export function NodeTypes(nodeTypes?: INodeTypeData): NodeTypesClass { +export function NodeTypes(nodeTypes?: INodeTypeData): INodeTypes { if (nodeTypesInstance === undefined || nodeTypes !== undefined) { nodeTypesInstance = new NodeTypesClass(nodeTypes); } @@ -110,7 +55,7 @@ export function WorkflowExecuteAdditionalData( ): IWorkflowExecuteAdditionalData { const hookFunctions = { nodeExecuteAfter: [ - async (nodeName: string, data: ITaskData): Promise => { + async (nodeName: string, _data: ITaskData): Promise => { nodeExecutionOrder.push(nodeName); }, ], @@ -121,26 +66,9 @@ export function WorkflowExecuteAdditionalData( ], }; - const workflowData: IWorkflowBase = { - name: '', - createdAt: new Date(), - updatedAt: new Date(), - active: true, - nodes: [], - connections: {}, - }; - - return { - credentialsHelper: new CredentialsHelper(), - hooks: new WorkflowHooks(hookFunctions, 'trigger', '1', workflowData), - executeWorkflow: async (workflowInfo: IExecuteWorkflowInfo) => {}, - sendDataToUI: (message: string) => {}, - restApiUrl: '', - webhookBaseUrl: 'webhook', - webhookWaitingBaseUrl: 'webhook-waiting', - webhookTestBaseUrl: 'webhook-test', - userId: '123', - }; + return mock({ + hooks: new WorkflowHooks(hookFunctions, 'trigger', '1', mock()), + }); } const preparePinData = (pinData: IDataObject) => { diff --git a/packages/nodes-base/test/nodes/ExecuteWorkflow.ts b/packages/nodes-base/test/nodes/ExecuteWorkflow.ts index 528eca40a9..5975d14071 100644 --- a/packages/nodes-base/test/nodes/ExecuteWorkflow.ts +++ b/packages/nodes-base/test/nodes/ExecuteWorkflow.ts @@ -10,6 +10,7 @@ export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INo const { baseUrl, mocks } = testData.nock; const agent = nock(baseUrl); mocks.forEach(({ method, path, statusCode, responseBody }) => + // @ts-expect-error agent[method](path).reply(statusCode, responseBody), ); } @@ -24,11 +25,7 @@ export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INo }); const waitPromise = await createDeferredPromise(); const nodeExecutionOrder: string[] = []; - const additionalData = Helpers.WorkflowExecuteAdditionalData( - waitPromise, - nodeExecutionOrder, - testData, - ); + const additionalData = Helpers.WorkflowExecuteAdditionalData(waitPromise, nodeExecutionOrder); let executionData: IRun; const runExecutionData: IRunExecutionData = { @@ -36,6 +33,7 @@ export async function executeWorkflow(testData: WorkflowTestData, nodeTypes: INo runData: {}, }, executionData: { + metadata: {}, contextData: {}, waitingExecution: {}, waitingExecutionSource: null, diff --git a/packages/nodes-base/test/nodes/Helpers.ts b/packages/nodes-base/test/nodes/Helpers.ts index b5c6714280..063fa6f3d9 100644 --- a/packages/nodes-base/test/nodes/Helpers.ts +++ b/packages/nodes-base/test/nodes/Helpers.ts @@ -6,6 +6,7 @@ import { isEmpty } from 'lodash'; import { get } from 'lodash'; import { BinaryDataService, Credentials, constructExecutionMetaData } from 'n8n-core'; import { Container } from 'typedi'; +import { mock } from 'jest-mock-extended'; import type { CredentialLoadingDetails, ICredentialDataDecryptedObject, @@ -15,7 +16,6 @@ import type { IDataObject, IDeferredPromise, IExecuteFunctions, - IExecuteWorkflowInfo, IGetNodeParameterOptions, IHttpRequestHelper, IHttpRequestOptions, @@ -87,22 +87,20 @@ class CredentialType implements ICredentialTypes { return knownCredentials[type]?.supportedNodes ?? []; } - getParentTypes(typeName: string): string[] { + getParentTypes(_typeName: string): string[] { return []; } } -export class CredentialsHelper extends ICredentialsHelper { - constructor(private credentialTypes: ICredentialTypes) { - super(''); - } +const credentialTypes = new CredentialType(); +class CredentialsHelper extends ICredentialsHelper { async authenticate( credentials: ICredentialDataDecryptedObject, typeName: string, requestParams: IHttpRequestOptions, ): Promise { - const credentialType = this.credentialTypes.getByName(typeName); + const credentialType = credentialTypes.getByName(typeName); if (typeof credentialType.authenticate === 'function') { return await credentialType.authenticate(credentials, requestParams); } @@ -110,21 +108,21 @@ export class CredentialsHelper extends ICredentialsHelper { } async preAuthentication( - helpers: IHttpRequestHelper, - credentials: ICredentialDataDecryptedObject, - typeName: string, - node: INode, - credentialsExpired: boolean, + _helpers: IHttpRequestHelper, + _credentials: ICredentialDataDecryptedObject, + _typeName: string, + _node: INode, + _credentialsExpired: boolean, ): Promise { return undefined; } - getParentTypes(name: string): string[] { + getParentTypes(_name: string): string[] { return []; } async getDecrypted( - additionalData: IWorkflowExecuteAdditionalData, + _additionalData: IWorkflowExecuteAdditionalData, nodeCredentials: INodeCredentialsDetails, type: string, ): Promise { @@ -132,27 +130,26 @@ export class CredentialsHelper extends ICredentialsHelper { } async getCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, + _nodeCredentials: INodeCredentialsDetails, + _type: string, ): Promise { - return new Credentials({ id: null, name: '' }, '', [], ''); + return new Credentials({ id: null, name: '' }, '', ''); } async updateCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, - data: ICredentialDataDecryptedObject, + _nodeCredentials: INodeCredentialsDetails, + _type: string, + _data: ICredentialDataDecryptedObject, ): Promise {} } export function WorkflowExecuteAdditionalData( waitPromise: IDeferredPromise, nodeExecutionOrder: string[], - workflowTestData?: WorkflowTestData, ): IWorkflowExecuteAdditionalData { const hookFunctions = { nodeExecuteAfter: [ - async (nodeName: string, data: ITaskData): Promise => { + async (nodeName: string, _data: ITaskData): Promise => { nodeExecutionOrder.push(nodeName); }, ], @@ -163,27 +160,10 @@ export function WorkflowExecuteAdditionalData( ], }; - const workflowData: IWorkflowBase = { - name: '', - createdAt: new Date(), - updatedAt: new Date(), - active: true, - nodes: [], - connections: {}, - }; - return { - credentialsHelper: new CredentialsHelper(credentialTypes), - hooks: new WorkflowHooks(hookFunctions, 'trigger', '1', workflowData), - executeWorkflow: async (workflowInfo: IExecuteWorkflowInfo): Promise => {}, - sendDataToUI: (message: string) => {}, - restApiUrl: '', - webhookBaseUrl: 'webhook', - webhookWaitingBaseUrl: 'webhook-waiting', - webhookTestBaseUrl: 'webhook-test', - userId: '123', - variables: {}, - instanceBaseUrl: '', - }; + return mock({ + credentialsHelper: new CredentialsHelper(), + hooks: new WorkflowHooks(hookFunctions, 'trigger', '1', mock()), + }); } class NodeTypes implements INodeTypes { @@ -209,6 +189,10 @@ class NodeTypes implements INodeTypes { getByNameAndVersion(nodeType: string, version?: number): INodeType { return NodeHelpers.getVersionedNodeType(this.nodeTypes[nodeType].type, version); } + + getKnownTypes(): IDataObject { + throw new Error('Method not implemented.'); + } } export function createTemporaryDir(prefix = 'n8n') { @@ -225,8 +209,6 @@ export async function initBinaryDataService(mode: 'default' | 'filesystem' = 'de Container.set(BinaryDataService, binaryDataService); } -const credentialTypes = new CredentialType(); - export function setup(testData: WorkflowTestData[] | WorkflowTestData) { if (!Array.isArray(testData)) { testData = [testData]; diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index f3a4264edc..dd1c15b92b 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -2060,21 +2060,23 @@ export const eventNamesAiNodes = [ export type EventNamesAiNodesType = (typeof eventNamesAiNodes)[number]; +export interface ExecuteWorkflowOptions { + node?: INode; + parentWorkflowId: string; + inputData?: INodeExecutionData[]; + parentExecutionId?: string; + loadedWorkflowData?: IWorkflowBase; + loadedRunData?: any; + parentWorkflowSettings?: IWorkflowSettings; + parentCallbackManager?: CallbackManager; +} + export interface IWorkflowExecuteAdditionalData { credentialsHelper: ICredentialsHelper; executeWorkflow: ( workflowInfo: IExecuteWorkflowInfo, additionalData: IWorkflowExecuteAdditionalData, - options: { - node?: INode; - parentWorkflowId: string; - inputData?: INodeExecutionData[]; - parentExecutionId?: string; - loadedWorkflowData?: IWorkflowBase; - loadedRunData?: any; - parentWorkflowSettings?: IWorkflowSettings; - parentCallbackManager?: CallbackManager; - }, + options: ExecuteWorkflowOptions, ) => Promise; executionId?: string; restartExecutionId?: string; diff --git a/packages/workflow/test/Helpers.ts b/packages/workflow/test/Helpers.ts index 8b07f3d6aa..c618f5fd0c 100644 --- a/packages/workflow/test/Helpers.ts +++ b/packages/workflow/test/Helpers.ts @@ -1,531 +1,65 @@ +import { readFileSync } from 'fs'; +import path from 'path'; +import { mock } from 'jest-mock-extended'; import get from 'lodash/get'; + import type { - IAdditionalCredentialOptions, - IAllExecuteFunctions, - IContextObject, - ICredentialDataDecryptedObject, - ICredentialsEncrypted, - IDataObject, - IExecuteData, - IExecuteFunctions, - IExecuteResponsePromiseData, IExecuteSingleFunctions, - IExecuteWorkflowInfo, - IHttpRequestHelper, IHttpRequestOptions, IN8nHttpFullResponse, IN8nHttpResponse, INode, - INodeCredentialsDetails, - INodeExecutionData, - INodeParameters, - INodeType, + INodeTypes, IRunExecutionData, - ITaskDataConnections, - IWorkflowBase, - IWorkflowDataProxyAdditionalKeys, - IWorkflowDataProxyData, - IWorkflowExecuteAdditionalData, - NodeParameterValue, - WorkflowExecuteMode, } from '@/Interfaces'; -import { ICredentials, ICredentialsHelper } from '@/Interfaces'; import type { Workflow } from '@/Workflow'; -import { WorkflowDataProxy } from '@/WorkflowDataProxy'; -import { WorkflowHooks } from '@/WorkflowHooks'; -import * as NodeHelpers from '@/NodeHelpers'; -import { deepCopy } from '@/utils'; -import { getGlobalState } from '@/GlobalState'; -import { ApplicationError } from '@/errors/application.error'; import { NodeTypes as NodeTypesClass } from './NodeTypes'; -import { readFileSync } from 'fs'; -import path from 'path'; - -export interface INodeTypesObject { - [key: string]: INodeType; -} - -export class Credentials extends ICredentials { - setData(data: ICredentialDataDecryptedObject) { - this.data = JSON.stringify(data); - } - - getData(): ICredentialDataDecryptedObject { - if (this.data === undefined) { - throw new ApplicationError('No data is set so nothing can be returned'); - } - return JSON.parse(this.data); - } - - getDataToSave(): ICredentialsEncrypted { - if (this.data === undefined) { - throw new ApplicationError('No credentials were set to save'); - } - - return { - id: this.id, - name: this.name, - type: this.type, - data: this.data, - }; - } -} - -export class CredentialsHelper extends ICredentialsHelper { - async authenticate( - credentials: ICredentialDataDecryptedObject, - typeName: string, - requestParams: IHttpRequestOptions, - ): Promise { - return requestParams; - } - - async preAuthentication( - helpers: IHttpRequestHelper, - credentials: ICredentialDataDecryptedObject, - typeName: string, - node: INode, - credentialsExpired: boolean, - ): Promise<{ updatedCredentials: boolean; data: ICredentialDataDecryptedObject }> { - return { updatedCredentials: false, data: {} }; - } - - getParentTypes(name: string): string[] { - return []; - } - - async getDecrypted( - additionalData: IWorkflowExecuteAdditionalData, - nodeCredentials: INodeCredentialsDetails, - type: string, - ): Promise { - return {}; - } - - async getCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, - ): Promise { - return new Credentials({ id: null, name: '' }, '', [], ''); - } - - async updateCredentials( - nodeCredentials: INodeCredentialsDetails, - type: string, - data: ICredentialDataDecryptedObject, - ): Promise {} -} - -export function getNodeParameter( - workflow: Workflow, - runExecutionData: IRunExecutionData | null, - runIndex: number, - connectionInputData: INodeExecutionData[], - node: INode, - parameterName: string, - itemIndex: number, - mode: WorkflowExecuteMode, - additionalKeys: IWorkflowDataProxyAdditionalKeys, - executeData: IExecuteData, - fallbackValue?: any, -): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object { - const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion); - if (nodeType === undefined) { - throw new ApplicationError('Node type is unknown so cannot return parameter value', { - tags: { nodeType: node.type }, - }); - } - - const value = get(node.parameters, parameterName, fallbackValue); - - if (value === undefined) { - throw new ApplicationError('Could not get parameter', { extra: { parameterName } }); - } - - let returnData; - try { - returnData = workflow.expression.getParameterValue( - value, - runExecutionData, - runIndex, - itemIndex, - node.name, - connectionInputData, - mode, - additionalKeys, - ); - } catch (e) { - e.message += ` [Error in parameter: "${parameterName}"]`; - throw e; - } - - return returnData; -} - -export function getExecuteFunctions( - workflow: Workflow, - runExecutionData: IRunExecutionData, - runIndex: number, - connectionInputData: INodeExecutionData[], - inputData: ITaskDataConnections, - node: INode, - itemIndex: number, - additionalData: IWorkflowExecuteAdditionalData, - executeData: IExecuteData, - mode: WorkflowExecuteMode, -): IExecuteFunctions { - return ((workflow, runExecutionData, connectionInputData, inputData, node) => { - return { - continueOnFail: () => { - return false; - }, - evaluateExpression: (expression: string, itemIndex: number) => { - return expression; - }, - async executeWorkflow( - workflowInfo: IExecuteWorkflowInfo, - inputData?: INodeExecutionData[], - ): Promise { - return await additionalData.executeWorkflow(workflowInfo, additionalData, { inputData }); - }, - getContext(type: string): IContextObject { - return NodeHelpers.getContext(runExecutionData, type, node); - }, - async getCredentials( - type: string, - itemIndex?: number, - ): Promise { - return { - apiKey: '12345', - }; - }, - getExecutionId: (): string => { - return additionalData.executionId!; - }, - getInputData: (inputIndex = 0, inputName = 'main') => { - if (!inputData.hasOwnProperty(inputName)) { - // Return empty array because else it would throw error when nothing is connected to input - return []; - } - - if (inputData[inputName].length < inputIndex) { - throw new ApplicationError('Could not get input index', { - extra: { inputIndex, inputName }, - }); - } - - if (inputData[inputName][inputIndex] === null) { - throw new ApplicationError('Value of input did not get set', { - extra: { inputIndex, inputName }, - }); - } - - return inputData[inputName][inputIndex] as INodeExecutionData[]; - }, - getNodeParameter: ( - parameterName: string, - itemIndex: number, - fallbackValue?: any, - ): - | NodeParameterValue - | INodeParameters - | NodeParameterValue[] - | INodeParameters[] - | object => { - return getNodeParameter( - workflow, - runExecutionData, - runIndex, - connectionInputData, - node, - parameterName, - itemIndex, - mode, - {}, - fallbackValue, - ); - }, - getMode: (): WorkflowExecuteMode => { - return mode; - }, - getNode: () => { - return deepCopy(node); - }, - getRestApiUrl: (): string => { - return additionalData.restApiUrl; - }, - getTimezone: (): string => { - return workflow.settings.timezone ?? getGlobalState().defaultTimezone; - }, - getExecuteData: (): IExecuteData => { - return executeData; - }, - getWorkflow: () => { - return { - id: workflow.id, - name: workflow.name, - active: workflow.active, - }; - }, - getWorkflowDataProxy: (itemIndex: number): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy( - workflow, - runExecutionData, - runIndex, - itemIndex, - node.name, - connectionInputData, - {}, - mode, - {}, - executeData, - ); - return dataProxy.getDataProxy(); - }, - getWorkflowStaticData(type: string): IDataObject { - return workflow.getStaticData(type, node); - }, - prepareOutputData: NodeHelpers.prepareOutputData, - async putExecutionToWait(waitTill: Date): Promise { - runExecutionData.waitTill = waitTill; - }, - sendMessageToUI(...args: any[]): void { - if (mode !== 'manual') { - return; - } - try { - if (additionalData.sendMessageToUI) { - additionalData.sendMessageToUI(node.name, args); - } - } catch (error) { - console.error(`There was a problem sending message to UI: ${error.message}`); - } - }, - async sendResponse(response: IExecuteResponsePromiseData): Promise { - await additionalData.hooks?.executeHookFunctions('sendResponse', [response]); - }, - helpers: { - async httpRequest( - requestOptions: IHttpRequestOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - requestOptions, - }, - }; - }, - async requestWithAuthentication( - this: IAllExecuteFunctions, - credentialsType: string, - requestOptions: IHttpRequestOptions, - additionalCredentialOptions?: IAdditionalCredentialOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - credentialsType, - requestOptions, - additionalCredentialOptions, - }, - }; - }, - async httpRequestWithAuthentication( - this: IAllExecuteFunctions, - credentialsType: string, - requestOptions: IHttpRequestOptions, - additionalCredentialOptions?: IAdditionalCredentialOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - credentialsType, - requestOptions, - additionalCredentialOptions, - }, - }; - }, - }, - }; - })(workflow, runExecutionData, connectionInputData, inputData, node); -} export function getExecuteSingleFunctions( workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, - connectionInputData: INodeExecutionData[], - inputData: ITaskDataConnections, node: INode, itemIndex: number, - additionalData: IWorkflowExecuteAdditionalData, - executeData: IExecuteData, - mode: WorkflowExecuteMode, ): IExecuteSingleFunctions { - return ((workflow, runExecutionData, connectionInputData, inputData, node, itemIndex) => { - return { - continueOnFail: () => { - return false; - }, - evaluateExpression: (expression: string, evaluateItemIndex: number | undefined) => { - return expression; - }, - getContext(type: string): IContextObject { - return NodeHelpers.getContext(runExecutionData, type, node); - }, - async getCredentials(type: string): Promise { + return mock({ + getItemIndex: () => itemIndex, + getNodeParameter: (parameterName: string) => { + return workflow.expression.getParameterValue( + get(node.parameters, parameterName), + runExecutionData, + runIndex, + itemIndex, + node.name, + [], + 'internal', + {}, + ); + }, + getWorkflow: () => ({ + id: workflow.id, + name: workflow.name, + active: workflow.active, + }), + helpers: mock({ + async httpRequest( + requestOptions: IHttpRequestOptions, + ): Promise { return { - apiKey: '12345', + body: { + headers: {}, + statusCode: 200, + requestOptions, + }, }; }, - getInputData: (inputIndex = 0, inputName = 'main') => { - if (!inputData.hasOwnProperty(inputName)) { - // Return empty array because else it would throw error when nothing is connected to input - return { json: {} }; - } - - if (inputData[inputName].length < inputIndex) { - throw new ApplicationError('Could not get input index', { - extra: { inputIndex, inputName }, - }); - } - - const allItems = inputData[inputName][inputIndex]; - - if (allItems === null) { - throw new ApplicationError('Value of input did not get set', { - extra: { inputIndex, inputName }, - }); - } - - if (allItems[itemIndex] === null) { - throw new ApplicationError('Value of input with item index did not get set', { - extra: { inputIndex, inputName, itemIndex }, - }); - } - - return allItems[itemIndex]; - }, - getItemIndex: () => { - return itemIndex; - }, - getMode: (): WorkflowExecuteMode => { - return mode; - }, - getNode: () => { - return deepCopy(node); - }, - getRestApiUrl: (): string => { - return additionalData.restApiUrl; - }, - getTimezone: (): string => { - return workflow.settings.timezone ?? getGlobalState().defaultTimezone; - }, - getExecuteData: (): IExecuteData => { - return executeData; - }, - getNodeParameter: ( - parameterName: string, - fallbackValue?: any, - ): - | NodeParameterValue - | INodeParameters - | NodeParameterValue[] - | INodeParameters[] - | object => { - return getNodeParameter( - workflow, - runExecutionData, - runIndex, - connectionInputData, - node, - parameterName, - itemIndex, - mode, - {}, - fallbackValue, - ); - }, - getWorkflow: () => { - return { - id: workflow.id, - name: workflow.name, - active: workflow.active, - }; - }, - getWorkflowDataProxy: (): IWorkflowDataProxyData => { - const dataProxy = new WorkflowDataProxy( - workflow, - runExecutionData, - runIndex, - itemIndex, - node.name, - connectionInputData, - {}, - mode, - {}, - executeData, - ); - return dataProxy.getDataProxy(); - }, - getWorkflowStaticData(type: string): IDataObject { - return workflow.getStaticData(type, node); - }, - helpers: { - async httpRequest( - requestOptions: IHttpRequestOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - requestOptions, - }, - }; - }, - async requestWithAuthentication( - this: IAllExecuteFunctions, - credentialsType: string, - requestOptions: IHttpRequestOptions, - additionalCredentialOptions?: IAdditionalCredentialOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - credentialsType, - requestOptions, - additionalCredentialOptions, - }, - }; - }, - async httpRequestWithAuthentication( - this: IAllExecuteFunctions, - credentialsType: string, - requestOptions: IHttpRequestOptions, - additionalCredentialOptions?: IAdditionalCredentialOptions, - ): Promise { - return { - body: { - headers: {}, - statusCode: 200, - credentialsType, - requestOptions, - additionalCredentialOptions, - }, - }; - }, - }, - }; - })(workflow, runExecutionData, connectionInputData, inputData, node, itemIndex); + }), + }); } let nodeTypesInstance: NodeTypesClass | undefined; -export function NodeTypes(): NodeTypesClass { +export function NodeTypes(): INodeTypes { if (nodeTypesInstance === undefined) { nodeTypesInstance = new NodeTypesClass(); } @@ -533,29 +67,6 @@ export function NodeTypes(): NodeTypesClass { return nodeTypesInstance; } -export function WorkflowExecuteAdditionalData(): IWorkflowExecuteAdditionalData { - const workflowData: IWorkflowBase = { - name: '', - createdAt: new Date(), - updatedAt: new Date(), - active: true, - nodes: [], - connections: {}, - }; - - return { - credentialsHelper: new CredentialsHelper(), - hooks: new WorkflowHooks({}, 'trigger', '1', workflowData), - executeWorkflow: async (workflowInfo: IExecuteWorkflowInfo): Promise => {}, - sendDataToUI: (message: string) => {}, - restApiUrl: '', - webhookBaseUrl: 'webhook', - webhookWaitingBaseUrl: 'webhook-waiting', - webhookTestBaseUrl: 'webhook-test', - userId: '123', - }; -} - const BASE_DIR = path.resolve(__dirname, '..'); export const readJsonFileSync = (filePath: string) => JSON.parse(readFileSync(path.join(BASE_DIR, filePath), 'utf-8')) as T; diff --git a/packages/workflow/test/NodeTypes.ts b/packages/workflow/test/NodeTypes.ts index 3adbe32109..101ec534c2 100644 --- a/packages/workflow/test/NodeTypes.ts +++ b/packages/workflow/test/NodeTypes.ts @@ -1,11 +1,13 @@ -import { - NodeHelpers, - type INodeType, - type INodeTypeData, - type INodeTypes, - type IVersionedNodeType, - type LoadedClass, -} from '@/index'; +import { mock } from 'jest-mock-extended'; +import type { + IDataObject, + INodeType, + INodeTypeData, + INodeTypes, + IVersionedNodeType, + LoadedClass, +} from '@/Interfaces'; +import * as NodeHelpers from '@/NodeHelpers'; const stickyNode: LoadedClass = { type: { @@ -626,39 +628,6 @@ export class NodeTypes implements INodeTypes { }, }, }, - 'test.switch': { - sourcePath: '', - type: { - description: { - displayName: 'Set', - name: 'set', - group: ['input'], - version: 1, - description: 'Switches', - defaults: { - name: 'Switch', - color: '#0000FF', - }, - inputs: ['main'], - outputs: ['main', 'main', 'main', 'main'], - outputNames: ['0', '1', '2', '3'], - properties: [ - { - displayName: 'Value1', - name: 'value1', - type: 'string', - default: 'default-value1', - }, - { - displayName: 'Value2', - name: 'value2', - type: 'string', - default: 'default-value2', - }, - ], - }, - }, - }, }; getByName(nodeType: string): INodeType | IVersionedNodeType { @@ -669,5 +638,14 @@ export class NodeTypes implements INodeTypes { if (this.nodeTypes[nodeType]?.type) { return NodeHelpers.getVersionedNodeType(this.nodeTypes[nodeType]?.type, version); } + return mock({ + description: { + properties: [], + }, + }); + } + + getKnownTypes(): IDataObject { + throw new Error('Method not implemented.'); } } diff --git a/packages/workflow/test/RoutingNode.test.ts b/packages/workflow/test/RoutingNode.test.ts index 9496e84d6a..4b0ac4a5e4 100644 --- a/packages/workflow/test/RoutingNode.test.ts +++ b/packages/workflow/test/RoutingNode.test.ts @@ -7,23 +7,24 @@ import type { INodeProperties, IExecuteSingleFunctions, IHttpRequestOptions, - IN8nHttpFullResponse, ITaskDataConnections, INodeExecuteFunctions, IN8nRequestOperations, INodeCredentialDescription, IExecuteData, INodeTypeDescription, + IWorkflowExecuteAdditionalData, + IExecuteFunctions, } from '@/Interfaces'; import { RoutingNode } from '@/RoutingNode'; import { Workflow } from '@/Workflow'; import * as Helpers from './Helpers'; +import { mock } from 'jest-mock-extended'; const postReceiveFunction1 = async function ( this: IExecuteSingleFunctions, items: INodeExecutionData[], - response: IN8nHttpFullResponse, ): Promise { items.forEach((item) => (item.json1 = { success: true })); return items; @@ -39,6 +40,8 @@ const preSendFunction1 = async function ( }; describe('RoutingNode', () => { + const additionalData = mock(); + describe('getRequestOptionsFromParameters', () => { const tests: Array<{ description: string; @@ -659,7 +662,6 @@ describe('RoutingNode', () => { const itemIndex = 0; const connectionInputData: INodeExecutionData[] = []; const runExecutionData: IRunExecutionData = { resultData: { runData: {} } }; - const additionalData = Helpers.WorkflowExecuteAdditionalData(); const path = ''; const nodeType = nodeTypes.getByNameAndVersion(node.type); @@ -693,17 +695,8 @@ describe('RoutingNode', () => { workflow, runExecutionData, runIndex, - connectionInputData, - {}, node, itemIndex, - additionalData, - { - node, - data: {}, - source: null, - }, - mode, ); const result = routingNode.getRequestOptionsFromParameters( @@ -1704,7 +1697,6 @@ describe('RoutingNode', () => { const itemIndex = 0; const connectionInputData: INodeExecutionData[] = []; const runExecutionData: IRunExecutionData = { resultData: { runData: {} } }; - const additionalData = Helpers.WorkflowExecuteAdditionalData(); const nodeType = nodeTypes.getByNameAndVersion(baseNode.type); const inputData: ITaskDataConnections = { @@ -1751,34 +1743,15 @@ describe('RoutingNode', () => { } as IExecuteData; const nodeExecuteFunctions: Partial = { - getExecuteFunctions: () => { - return Helpers.getExecuteFunctions( + getExecuteFunctions: () => mock(), + getExecuteSingleFunctions: () => + Helpers.getExecuteSingleFunctions( workflow, runExecutionData, runIndex, - connectionInputData, - {}, node, itemIndex, - additionalData, - executeData, - mode, - ); - }, - getExecuteSingleFunctions: () => { - return Helpers.getExecuteSingleFunctions( - workflow, - runExecutionData, - runIndex, - connectionInputData, - {}, - node, - itemIndex, - additionalData, - executeData, - mode, - ); - }, + ), }; const result = await routingNode.runNode( @@ -1870,7 +1843,6 @@ describe('RoutingNode', () => { const itemIndex = 0; const connectionInputData: INodeExecutionData[] = []; const runExecutionData: IRunExecutionData = { resultData: { runData: {} } }; - const additionalData = Helpers.WorkflowExecuteAdditionalData(); const nodeType = nodeTypes.getByNameAndVersion(baseNode.type); const inputData: ITaskDataConnections = { @@ -1925,32 +1897,13 @@ describe('RoutingNode', () => { let currentItemIndex = 0; for (let iteration = 0; iteration < inputData.main[0]!.length; iteration++) { const nodeExecuteFunctions: Partial = { - getExecuteFunctions: () => { - return Helpers.getExecuteFunctions( - workflow, - runExecutionData, - runIndex, - connectionInputData, - {}, - node, - itemIndex + iteration, - additionalData, - executeData, - mode, - ); - }, getExecuteSingleFunctions: () => { return Helpers.getExecuteSingleFunctions( workflow, runExecutionData, runIndex, - connectionInputData, - {}, node, itemIndex + iteration, - additionalData, - executeData, - mode, ); }, };