2023-11-10 06:04:26 -08:00
|
|
|
import type { FindOptionsWhere } from 'typeorm';
|
|
|
|
import type { INode } from 'n8n-workflow';
|
2022-11-09 06:25:00 -08:00
|
|
|
import { WorkflowCredentials } from '@/WorkflowCredentials';
|
2023-11-10 06:04:26 -08:00
|
|
|
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
|
|
|
import { CredentialsRepository } from '@db/repositories/credentials.repository';
|
|
|
|
import { mockInstance } from '../shared/mocking';
|
2022-09-14 01:19:44 -07:00
|
|
|
|
2023-11-10 06:04:26 -08:00
|
|
|
const credentialsRepository = mockInstance(CredentialsRepository);
|
|
|
|
credentialsRepository.findOneBy.mockImplementation(
|
|
|
|
async (where: FindOptionsWhere<CredentialsEntity>) => {
|
|
|
|
const { id, type } = where as {
|
|
|
|
id: string;
|
|
|
|
type: string;
|
|
|
|
};
|
|
|
|
// Simple statement that maps a return value based on the `id` parameter
|
|
|
|
if (id === notFoundNode.credentials!.test.id) {
|
|
|
|
return null;
|
|
|
|
}
|
2022-09-14 01:19:44 -07:00
|
|
|
|
2023-11-10 06:04:26 -08:00
|
|
|
// Otherwise just build some kind of credential object and return it
|
|
|
|
return {
|
|
|
|
[type]: {
|
|
|
|
[id]: {
|
|
|
|
id,
|
|
|
|
name: type,
|
|
|
|
type,
|
|
|
|
nodesAccess: [],
|
|
|
|
data: '',
|
|
|
|
},
|
2022-09-14 01:19:44 -07:00
|
|
|
},
|
2023-11-10 06:04:26 -08:00
|
|
|
} as unknown as CredentialsEntity;
|
|
|
|
},
|
|
|
|
);
|
2022-09-14 01:19:44 -07:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
});
|
|
|
|
|
2023-05-23 17:01:45 -07:00
|
|
|
test('Should return an error if any node has no credential ID', async () => {
|
2023-05-02 01:37:19 -07:00
|
|
|
const credentials = noIdNode.credentials!.test;
|
2022-09-14 01:19:44 -07:00
|
|
|
const expectedError = new Error(
|
|
|
|
`Credentials with name "${credentials.name}" for type "test" miss an ID.`,
|
|
|
|
);
|
2023-05-23 17:01:45 -07:00
|
|
|
await expect(WorkflowCredentials([noIdNode])).rejects.toEqual(expectedError);
|
2023-11-10 06:04:26 -08:00
|
|
|
expect(credentialsRepository.findOneBy).toHaveBeenCalledTimes(0);
|
2022-09-14 01:19:44 -07:00
|
|
|
});
|
|
|
|
|
2023-05-23 17:01:45 -07:00
|
|
|
test('Should return an error if credentials cannot be found in the DB', async () => {
|
2023-11-29 03:25:10 -08:00
|
|
|
const expectedError = new Error('Could not find credential.');
|
2023-05-23 17:01:45 -07:00
|
|
|
await expect(WorkflowCredentials([notFoundNode])).rejects.toEqual(expectedError);
|
2023-11-10 06:04:26 -08:00
|
|
|
expect(credentialsRepository.findOneBy).toHaveBeenCalledTimes(1);
|
2022-09-14 01:19:44 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
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: {},
|
|
|
|
};
|