n8n/packages/editor-ui/src/components/NodeCredentials.test.ts

260 lines
6.9 KiB
TypeScript

import { describe, it } from 'vitest';
import { screen } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { createTestingPinia } from '@pinia/testing';
import NodeCredentials from './NodeCredentials.vue';
import type { RenderOptions } from '@/__tests__/render';
import { createComponentRenderer } from '@/__tests__/render';
import { useCredentialsStore } from '@/stores/credentials.store';
import { mockedStore } from '@/__tests__/utils';
import type { INodeUi } from '@/Interface';
import { useNDVStore } from '@/stores/ndv.store';
import { useUIStore } from '../stores/ui.store';
const httpNode: INodeUi = {
parameters: {
curlImport: '',
method: 'GET',
url: '',
authentication: 'predefinedCredentialType',
nodeCredentialType: 'openAiApi',
provideSslCertificates: false,
sendQuery: false,
sendHeaders: false,
sendBody: false,
options: {},
infoMessage: '',
},
type: 'n8n-nodes-base.httpRequest',
typeVersion: 4.2,
position: [-200, -160],
id: '416988b5-e994-42c7-8576-6ef28a7619b2',
name: 'HTTP Request',
credentials: { openAiApi: { id: 'c8vqdPpPClh4TgIO', name: 'OpenAi account 2' } },
issues: { parameters: { url: ['Parameter "URL" is required.'] } },
};
const openAiNode: INodeUi = {
parameters: {
resource: 'text',
operation: 'message',
modelId: { __rl: true, mode: 'list', value: '' },
messages: { values: [{ content: '', role: 'user' }] },
simplify: true,
jsonOutput: false,
options: {},
},
type: '@n8n/n8n-nodes-langchain.openAi',
typeVersion: 1.8,
position: [440, 0],
id: '17241295-a277-4cdf-8c46-6c3f85b335e9',
name: 'OpenAI',
credentials: { openAiApi: { id: 'byDFnd7vN5GzMVD2', name: 'n8n free OpenAI API credits' } },
issues: { parameters: { modelId: ['Parameter "Model" is required.'] } },
};
describe('NodeCredentials', () => {
const defaultRenderOptions: RenderOptions = {
pinia: createTestingPinia(),
props: {
overrideCredType: 'openAiApi',
node: httpNode,
readonly: false,
showAll: false,
hideIssues: false,
},
};
const renderComponent = createComponentRenderer(NodeCredentials, defaultRenderOptions);
const credentialsStore = mockedStore(useCredentialsStore);
const ndvStore = mockedStore(useNDVStore);
const uiStore = mockedStore(useUIStore);
beforeAll(() => {
credentialsStore.state.credentialTypes = {
openAiApi: {
name: 'openAiApi',
displayName: 'OpenAi',
documentationUrl: 'openAi',
properties: [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string',
typeOptions: { password: true },
required: true,
default: '',
},
],
authenticate: {
type: 'generic',
properties: {
headers: {
Authorization: '=Bearer {{$credentials.apiKey}}',
'OpenAI-Organization': '={{$credentials.organizationId}}',
},
},
},
test: { request: { baseURL: '={{$credentials?.url}}', url: '/models' } },
supportedNodes: ['openAi'],
iconUrl: {
light: 'icons/n8n-nodes-base/dist/nodes/OpenAi/openAi.svg',
dark: 'icons/n8n-nodes-base/dist/nodes/OpenAi/openAi.dark.svg',
},
},
};
});
it('should display available credentials in the dropdown', async () => {
ndvStore.activeNode = httpNode;
credentialsStore.state.credentials = {
c8vqdPpPClh4TgIO: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
};
renderComponent();
const credentialsSelect = screen.getByTestId('node-credentials-select');
await userEvent.click(credentialsSelect);
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
});
it('should ignore managed credentials in the dropdown if active node is the HTTP node', async () => {
ndvStore.activeNode = httpNode;
credentialsStore.state.credentials = {
c8vqdPpPClh4TgIO: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
SkXM3oUkQvvYS31c: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account 2',
type: 'openAiApi',
isManaged: true,
createdAt: '',
updatedAt: '',
},
};
renderComponent();
const credentialsSelect = screen.getByTestId('node-credentials-select');
await userEvent.click(credentialsSelect);
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
expect(screen.queryByText('OpenAi account 2')).not.toBeInTheDocument();
});
it('should not ignored managed credentials in the dropdown if active node is not the HTTP node', async () => {
ndvStore.activeNode = openAiNode;
credentialsStore.state.credentials = {
c8vqdPpPClh4TgIO: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
SkXM3oUkQvvYS31c: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account 2',
type: 'openAiApi',
isManaged: true,
createdAt: '',
updatedAt: '',
},
};
renderComponent(
{
props: {
node: openAiNode,
},
},
{ merge: true },
);
const credentialsSelect = screen.getByTestId('node-credentials-select');
await userEvent.click(credentialsSelect);
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
expect(screen.queryByText('OpenAi account 2')).toBeInTheDocument();
});
it('should filter available credentials in the dropdown', async () => {
ndvStore.activeNode = httpNode;
credentialsStore.state.credentials = {
c8vqdPpPClh4TgIO: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
test: {
id: 'test',
name: 'Test OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
};
renderComponent();
const credentialsSelect = screen.getByTestId('node-credentials-select');
await userEvent.click(credentialsSelect);
expect(screen.queryByText('OpenAi account')).toBeInTheDocument();
expect(screen.queryByText('Test OpenAi account')).toBeInTheDocument();
const credentialSearch = credentialsSelect.querySelector('input') as HTMLElement;
await userEvent.type(credentialSearch, 'test');
expect(screen.queryByText('OpenAi account')).not.toBeInTheDocument();
expect(screen.queryByText('Test OpenAi account')).toBeInTheDocument();
});
it('should open the new credential modal when clicked', async () => {
ndvStore.activeNode = httpNode;
credentialsStore.state.credentials = {
c8vqdPpPClh4TgIO: {
id: 'c8vqdPpPClh4TgIO',
name: 'OpenAi account',
type: 'openAiApi',
isManaged: false,
createdAt: '',
updatedAt: '',
},
};
renderComponent();
const credentialsSelect = screen.getByTestId('node-credentials-select');
await userEvent.click(credentialsSelect);
await userEvent.click(screen.getByTestId('node-credentials-select-item-new'));
expect(uiStore.openNewCredential).toHaveBeenCalledWith('openAiApi', true);
});
});