mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
260 lines
6.9 KiB
TypeScript
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);
|
|
});
|
|
});
|