import { simpleAssistantResponse, aiEnabledWithCodeSnippetRequirements, aiEnabledWithHttpWorkflowRequirements, } from '../../../config/ai-assistant-fixtures'; import { HTTP_REQUEST_NODE_NAME } from '../../../config/constants'; import { test, expect } from '../../../fixtures/base'; type ChatRequestBody = { payload?: { type?: string; text?: string; question?: string; context?: Record; }; }; test.describe('AI Assistant::enabled', { annotation: [ { type: 'owner', description: 'AI' }, ], }, () => { test.describe('Support Chat', () => { test('assistant returns code snippet', async ({ n8n, setupRequirements }) => { await setupRequirements(aiEnabledWithCodeSnippetRequirements); await n8n.page.goto('/workflow/new'); await expect(n8n.aiAssistant.getAskAssistantCanvasActionButton()).toBeVisible(); await n8n.aiAssistant.getAskAssistantCanvasActionButton().click(); await expect(n8n.aiAssistant.getAskAssistantChat()).toBeVisible(); await n8n.aiAssistant.sendMessage('Show me an expression'); await expect(n8n.aiAssistant.getChatMessagesAll()).toHaveCount(3); await expect(n8n.aiAssistant.getChatMessagesUser().first()).toContainText( 'Show me an expression', ); await expect(n8n.aiAssistant.getChatMessagesAssistant().first()).toContainText( 'To use expressions in n8n, follow these steps:', ); await expect(n8n.aiAssistant.getChatMessagesAssistant().first()).toContainText('New York'); await expect(n8n.aiAssistant.getCodeSnippet()).toHaveText('{{$json.body.city}}'); }); test('should send current context to support chat', async ({ n8n, setupRequirements }) => { await setupRequirements(aiEnabledWithHttpWorkflowRequirements); const chatRequests: ChatRequestBody[] = []; await n8n.page.route('**/rest/ai/chat', async (route) => { const body = route.request().postDataJSON() as ChatRequestBody; chatRequests.push(body); await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(simpleAssistantResponse), }); }); await n8n.aiAssistant.getAskAssistantCanvasActionButton().click(); await n8n.aiAssistant.sendMessage('What is wrong with this workflow?'); const supportRequest = chatRequests.find( (request) => request.payload?.question === 'What is wrong with this workflow?', ); expect(supportRequest).toBeDefined(); const supportContext = supportRequest?.payload?.context; expect(supportContext).toBeDefined(); expect(supportContext?.currentView).toBeDefined(); expect(supportContext?.currentWorkflow).toBeDefined(); }); test('should not send workflow context if nothing changed', async ({ n8n, setupRequirements, }) => { await setupRequirements(aiEnabledWithHttpWorkflowRequirements); const chatRequests: ChatRequestBody[] = []; await n8n.page.route('**/rest/ai/chat', async (route) => { const body = route.request().postDataJSON() as ChatRequestBody; chatRequests.push(body); await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(simpleAssistantResponse), }); }); await n8n.aiAssistant.getAskAssistantCanvasActionButton().click(); await n8n.aiAssistant.sendMessage('What is wrong with this workflow?', 'enter-key'); // Wait for message to be processed await expect(n8n.aiAssistant.getChatMessagesAssistant()).toHaveCount(1); await n8n.aiAssistant.sendMessage('And now?', 'enter-key'); await expect(n8n.aiAssistant.getChatMessagesAssistant()).toHaveCount(2); const secondRequest = chatRequests.find((request) => request.payload?.text === 'And now?'); const secondContext = secondRequest?.payload?.context; expect(secondContext?.currentWorkflow).toBeUndefined(); await n8n.canvas.openNode(HTTP_REQUEST_NODE_NAME); await n8n.ndv.setParameterInputValue('url', 'https://example.com'); await n8n.ndv.close(); await n8n.canvas.clickExecuteWorkflowButton(); await n8n.aiAssistant.sendMessage('What about now?', 'enter-key'); await expect(n8n.aiAssistant.getChatMessagesAssistant()).toHaveCount(3); const thirdRequest = chatRequests.find( (request) => request.payload?.text === 'What about now?', ); const thirdContext = thirdRequest?.payload?.context; expect(thirdContext?.currentWorkflow).toBeTruthy(); expect(thirdContext?.executionData).toBeTruthy(); }); }); });