| | import type { |
| | AiAskRequestDto, |
| | AiApplySuggestionRequestDto, |
| | AiChatRequestDto, |
| | } from '@n8n/api-types'; |
| | import type { AiAssistantSDK } from '@n8n_io/ai-assistant-sdk'; |
| | import { mock } from 'jest-mock-extended'; |
| |
|
| | import { InternalServerError } from '@/errors/response-errors/internal-server.error'; |
| | import type { AuthenticatedRequest } from '@/requests'; |
| | import type { WorkflowBuilderService } from '@/services/ai-workflow-builder.service'; |
| | import type { AiService } from '@/services/ai.service'; |
| |
|
| | import { AiController, type FlushableResponse } from '../ai.controller'; |
| |
|
| | describe('AiController', () => { |
| | const aiService = mock<AiService>(); |
| | const workflowBuilderService = mock<WorkflowBuilderService>(); |
| | const controller = new AiController(aiService, workflowBuilderService, mock(), mock()); |
| |
|
| | const request = mock<AuthenticatedRequest>({ |
| | user: { id: 'user123' }, |
| | }); |
| | const response = mock<FlushableResponse>(); |
| |
|
| | beforeEach(() => { |
| | jest.clearAllMocks(); |
| |
|
| | response.header.mockReturnThis(); |
| | }); |
| |
|
| | describe('chat', () => { |
| | const payload = mock<AiChatRequestDto>(); |
| |
|
| | it('should handle chat request successfully', async () => { |
| | aiService.chat.mockResolvedValue( |
| | mock<Response>({ |
| | body: mock({ |
| | pipeTo: jest.fn().mockImplementation(async (writableStream) => { |
| | |
| | const writer = writableStream.getWriter(); |
| | await writer.write(JSON.stringify({ message: 'test response' })); |
| | await writer.close(); |
| | }), |
| | }), |
| | }), |
| | ); |
| |
|
| | await controller.chat(request, response, payload); |
| |
|
| | expect(aiService.chat).toHaveBeenCalledWith(payload, request.user); |
| | expect(response.header).toHaveBeenCalledWith('Content-type', 'application/json-lines'); |
| | expect(response.flush).toHaveBeenCalled(); |
| | expect(response.end).toHaveBeenCalled(); |
| | }); |
| |
|
| | it('should throw InternalServerError if chat fails', async () => { |
| | const mockError = new Error('Chat failed'); |
| |
|
| | aiService.chat.mockRejectedValue(mockError); |
| |
|
| | await expect(controller.chat(request, response, payload)).rejects.toThrow( |
| | InternalServerError, |
| | ); |
| | }); |
| | }); |
| |
|
| | describe('applySuggestion', () => { |
| | const payload = mock<AiApplySuggestionRequestDto>(); |
| |
|
| | it('should apply suggestion successfully', async () => { |
| | const clientResponse = mock<AiAssistantSDK.ApplySuggestionResponse>(); |
| | aiService.applySuggestion.mockResolvedValue(clientResponse); |
| |
|
| | const result = await controller.applySuggestion(request, response, payload); |
| |
|
| | expect(aiService.applySuggestion).toHaveBeenCalledWith(payload, request.user); |
| | expect(result).toEqual(clientResponse); |
| | }); |
| |
|
| | it('should throw InternalServerError if applying suggestion fails', async () => { |
| | const mockError = new Error('Apply suggestion failed'); |
| | aiService.applySuggestion.mockRejectedValue(mockError); |
| |
|
| | await expect(controller.applySuggestion(request, response, payload)).rejects.toThrow( |
| | InternalServerError, |
| | ); |
| | }); |
| | }); |
| |
|
| | describe('askAi method', () => { |
| | const payload = mock<AiAskRequestDto>(); |
| |
|
| | it('should ask AI successfully', async () => { |
| | const clientResponse = mock<AiAssistantSDK.AskAiResponsePayload>(); |
| | aiService.askAi.mockResolvedValue(clientResponse); |
| |
|
| | const result = await controller.askAi(request, response, payload); |
| |
|
| | expect(aiService.askAi).toHaveBeenCalledWith(payload, request.user); |
| | expect(result).toEqual(clientResponse); |
| | }); |
| |
|
| | it('should throw InternalServerError if asking AI fails', async () => { |
| | const mockError = new Error('Ask AI failed'); |
| | aiService.askAi.mockRejectedValue(mockError); |
| |
|
| | await expect(controller.askAi(request, response, payload)).rejects.toThrow( |
| | InternalServerError, |
| | ); |
| | }); |
| | }); |
| | }); |
| |
|