Files
n8n/packages/testing/playwright/tests/e2e/ai/assistant-credential-help.spec.ts
alighasami 3d5eaf9445
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
first commit
2026-03-17 16:22:57 +03:30

163 lines
5.5 KiB
TypeScript

import {
aiEnabledRequirements,
aiEnabledWithSimpleChatRequirements,
} from '../../../config/ai-assistant-fixtures';
import {
GMAIL_NODE_NAME,
MANUAL_TRIGGER_NODE_NAME,
SCHEDULE_TRIGGER_NODE_NAME,
} from '../../../config/constants';
import { test, expect } from '../../../fixtures/base';
test.describe(
'AI Assistant::enabled',
{
annotation: [{ type: 'owner', description: 'AI' }],
},
() => {
test.describe('Credential Help', () => {
test('should start credential help from node credential', async ({
n8n,
setupRequirements,
}) => {
await setupRequirements(aiEnabledWithSimpleChatRequirements);
await n8n.page.goto('/workflow/new');
await n8n.canvas.addInitialNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
await n8n.ndv.clickBackToCanvasButton();
await n8n.canvas.addNode(GMAIL_NODE_NAME, { action: 'Get many messages', closeNDV: false });
await n8n.ndv.clickCreateNewCredential();
await expect(n8n.canvas.credentialModal.getModal()).toBeVisible();
const assistantButton = n8n.aiAssistant
.getCredentialEditAssistantButton()
.locator('button');
await expect(assistantButton).toBeVisible();
await assistantButton.click();
await expect(n8n.aiAssistant.getChatMessagesUser()).toHaveCount(1);
await expect(n8n.aiAssistant.getChatMessagesUser().first()).toContainText(
'How do I set up the credentials for Gmail OAuth2 API?',
);
await expect(n8n.aiAssistant.getChatMessagesAssistant().first()).toContainText(
'Hey, this is an assistant message',
);
await expect(assistantButton).toBeDisabled();
});
test('should start credential help from credential list', async ({
n8n,
setupRequirements,
}) => {
await setupRequirements(aiEnabledWithSimpleChatRequirements);
await n8n.navigate.toCredentials();
await n8n.workflows.addResource.credential();
await n8n.credentials.selectCredentialType('Notion API');
const assistantButton = n8n.aiAssistant
.getCredentialEditAssistantButton()
.locator('button');
await expect(assistantButton).toBeVisible();
await assistantButton.click();
await expect(n8n.aiAssistant.getChatMessagesUser()).toHaveCount(1);
await expect(n8n.aiAssistant.getChatMessagesUser().first()).toContainText(
'How do I set up the credentials for Notion API?',
);
await expect(n8n.aiAssistant.getChatMessagesAssistant().first()).toContainText(
'Hey, this is an assistant message',
);
await expect(assistantButton).toBeDisabled();
});
test('should not show assistant button if click to connect', async ({
n8n,
setupRequirements,
}) => {
await setupRequirements(aiEnabledRequirements);
await n8n.page.route('**/types/credentials.json', async (route) => {
const response = await route.fetch();
const credentials = (await response.json()) as Array<
{ name?: string } & Record<string, unknown>
>;
const index = credentials.findIndex((c) => c.name === 'slackOAuth2Api');
if (index >= 0) {
credentials[index] = {
...credentials[index],
__overwrittenProperties: ['clientId', 'clientSecret'],
};
}
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(credentials),
});
});
await n8n.page.goto('/workflow/new');
await n8n.canvas.addInitialNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
await n8n.canvas.addNode('Slack', { action: 'Get a channel' });
await n8n.ndv.clickCreateNewCredential();
// Default is managed OAuth (click to connect) — no assistant button
await expect(n8n.canvas.credentialModal.oauthConnectButton).toHaveCount(1);
await expect(n8n.canvas.credentialModal.getCredentialInputs()).toHaveCount(2);
await expect(n8n.aiAssistant.getCredentialEditAssistantButton()).toHaveCount(0);
// Switch to custom OAuth via dropdown — assistant button should appear
await n8n.canvas.credentialModal.selectAuthTypeFromDropdown('Custom OAuth2');
await expect(n8n.canvas.credentialModal.getCredentialInputs()).toHaveCount(4);
await expect(n8n.aiAssistant.getCredentialEditAssistantButton()).toHaveCount(1);
});
test('should not show assistant button when click to connect with some fields', async ({
n8n,
setupRequirements,
}) => {
await setupRequirements(aiEnabledRequirements);
await n8n.page.route('**/types/credentials.json', async (route) => {
const response = await route.fetch();
const credentials = (await response.json()) as Array<
{ name?: string } & Record<string, unknown>
>;
const index = credentials.findIndex((c) => c.name === 'microsoftOutlookOAuth2Api');
if (index >= 0) {
credentials[index] = {
...credentials[index],
__overwrittenProperties: [
'authUrl',
'accessTokenUrl',
'clientId',
'clientSecret',
'graphApiBaseUrl',
],
};
}
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(credentials),
});
});
await n8n.page.goto('/workflow/new');
await n8n.canvas.addInitialNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
await n8n.canvas.addNode('Microsoft Outlook', { action: 'Get a calendar' });
await n8n.ndv.clickCreateNewCredential();
await expect(n8n.canvas.credentialModal.oauthConnectButton).toHaveCount(1);
await expect(n8n.canvas.credentialModal.getCredentialInputs()).toHaveCount(2);
await expect(n8n.aiAssistant.getCredentialEditAssistantButton()).toHaveCount(0);
});
});
},
);