From a8127dfc05ea207f6d918f81fed18004ba7f4037 Mon Sep 17 00:00:00 2001 From: freya Date: Wed, 14 Sep 2022 09:19:44 +0100 Subject: [PATCH] test(core): WorkflowCredentials Test Suite --- .../cli/test/unit/WorkflowCredentials.test.ts | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 packages/cli/test/unit/WorkflowCredentials.test.ts diff --git a/packages/cli/test/unit/WorkflowCredentials.test.ts b/packages/cli/test/unit/WorkflowCredentials.test.ts new file mode 100644 index 0000000000..22185b8003 --- /dev/null +++ b/packages/cli/test/unit/WorkflowCredentials.test.ts @@ -0,0 +1,150 @@ +import { WorkflowCredentials, Db } from '../../src'; +import { mocked } from 'jest-mock'; +import type { IRun, INode, IWorkflowCredentials, IDataObject } from 'n8n-workflow'; + +// Define a function used to mock the findOne function +async function mockFind({ id, type }): Promise { + // Simple statement that maps a return value based on the `id` paremeter + if (id === notFoundNode.credentials!!.test.id) { + return null; + } + // Otherwise just build some kind of credential object and return it + return { + [type]: { + [id]: { + id: id, + name: type, + type: type, + nodesAccess: [], + data: '', + }, + }, + }; +} + +jest.mock('../../src/Db', () => { + return { + collections: { + Credentials: { + findOne: jest.fn(mockFind), + }, + }, + }; +}); + +// Create an array of Nodes with info that pass or fail the checks as required. +// DB returns an object of type { [id: string]: ICredentialsEncrypted } but as it isn't checked +// All the mock will need to return is some form of Object when successful + +describe('WorkflowCredentials', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + test('Should return an error if any node has no credential ID', () => { + const credentials = noIdNode.credentials!!.test; + const expectedError = new Error( + `Credentials with name "${credentials.name}" for type "test" miss an ID.`, + ); + expect(WorkflowCredentials([noIdNode])).rejects.toEqual(expectedError); + expect(mocked(Db.collections.Credentials.findOne)).toHaveBeenCalledTimes(0); + }); + + test('Should return an error if credentials cannot be found in the DB', () => { + const credentials = notFoundNode.credentials!!.test; + const expectedError = new Error( + `Could not find credentials for type "test" with ID "${credentials.id}".`, + ); + expect(WorkflowCredentials([notFoundNode])).rejects.toEqual(expectedError); + expect(mocked(Db.collections.Credentials.findOne)).toHaveBeenCalledTimes(1); + }); + + test('Should ignore duplicates', async () => { + const response = await WorkflowCredentials([validNode, validNode, validNode]); + expect(Object.keys(response)).toEqual(['test']); + }); + + test('Should ignore Nodes with no credentials set', async () => { + const response = await WorkflowCredentials([validNode, noCredentialsNode]); + expect(Object.keys(response)).toEqual(['test']); + }); + + test('Should work for Nodes with multiple credentials', async () => { + const response = await WorkflowCredentials([multiCredNode]); + expect(Object.keys(response)).toEqual(['mcTest', 'mcTest2']); + }); +}); + +const validNode: INode = { + id: '1', + name: 'Node with Valid Credentials', + typeVersion: 1, + type: '', + position: [0, 0], + credentials: { + test: { + id: 'cred#1', + name: 'Test Credentials', + }, + }, + parameters: {}, +}; + +const noIdNode: INode = { + id: '2', + name: 'Node with no Credential ID', + typeVersion: 1, + type: '', + position: [0, 0], + credentials: { + test: { + id: null, + name: 'NOFIND', + }, + }, + parameters: {}, +}; + +const notFoundNode: INode = { + id: '3', + name: 'Node that will not be found in the DB', + typeVersion: 1, + type: '', + position: [0, 0], + credentials: { + test: { + id: 'noDB', + name: 'Not in Database', + }, + }, + parameters: {}, +}; + +const noCredentialsNode: INode = { + id: '4', + name: 'Node that has no credentials', + typeVersion: 1, + type: '', + position: [0, 0], + parameters: {}, +}; + +// Reference this as a DataObject so I can provide a null credential for testing +const multiCredNode: INode = { + id: '5', + name: 'Node that has mutliple credential elements', + typeVersion: 1, + type: '', + position: [0, 0], + credentials: { + mcTest: { + id: 'multicred#1', + name: 'First of Multiple Credentials', + }, + mcTest2: { + id: 'multicred#2', + name: 'Second of Multiple Credentials', + }, + }, + parameters: {}, +};