From 0f6ca3c3b510c47d504320cdf2780e49f9907049 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 17 Dec 2024 00:33:40 +0800 Subject: [PATCH] test: add test --- .github/workflows/integration_test.yml | 29 ++ jest.config.js | 6 +- lib/types/ai.ts | 19 +- lib/types/response.ts | 4 + tests/services/chat_message.test.ts | 217 ++++++++++++ tests/services/create_chat.test.ts | 171 ++++++++++ tests/services/http_service.test.ts | 314 ------------------ .../{mock.ts => mock_http_service.ts} | 29 +- 8 files changed, 466 insertions(+), 323 deletions(-) create mode 100644 .github/workflows/integration_test.yml create mode 100644 tests/services/chat_message.test.ts create mode 100644 tests/services/create_chat.test.ts delete mode 100644 tests/services/http_service.test.ts rename tests/services/{mock.ts => mock_http_service.ts} (91%) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml new file mode 100644 index 0000000..fdd81c3 --- /dev/null +++ b/.github/workflows/integration_test.yml @@ -0,0 +1,29 @@ + +name: Integration Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: pnpm install + + - name: Run tests + run: pnpm test \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 12e9d2a..000a48e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,4 +5,8 @@ export default { "^.+.tsx?$": ["ts-jest",{}], }, testMatch: ['**/*.test.ts', '**/*.test.tsx'], -}; \ No newline at end of file + moduleDirectories: ['node_modules', 'lib'], + moduleNameMapper: { + '^@appflowy-chat/(.*)$': '/lib/$1', + }, +}; diff --git a/lib/types/ai.ts b/lib/types/ai.ts index ad072a8..0b86f15 100644 --- a/lib/types/ai.ts +++ b/lib/types/ai.ts @@ -1,4 +1,4 @@ -import { ChatError, ResponseError } from "./error"; +import { ChatError } from "./error"; export const STREAM_METADATA_KEY: string = "0"; export const STREAM_ANSWER_KEY: string = "1"; @@ -95,10 +95,11 @@ interface QuestionStreamValue { type: "Answer" | "Metadata"; value: JSONValue; } + export class QuestionStream { - private stream: AsyncIterableIterator; + private stream: AsyncIterableIterator; - constructor(stream: AsyncIterableIterator) { + constructor(stream: AsyncIterableIterator) { this.stream = stream; } @@ -108,13 +109,13 @@ export class QuestionStream { } // Processes the next item in the stream - async next(): Promise { + async next(): Promise { const result = await this.stream.next(); if (result.done) return null; const value = result.value; - if ((value as ResponseError).message) { - return value as ResponseError; + if ((value as ChatError).message) { + return value as ChatError; } const jsonValue = value as Record; @@ -130,7 +131,11 @@ export class QuestionStream { } // Invalid format case - return { message: "Invalid streaming value", code: -1 } as ResponseError; + return { message: "Invalid streaming value", code: -1 } as ChatError; + } + + [Symbol.asyncIterator]() { + return this.stream; } } diff --git a/lib/types/response.ts b/lib/types/response.ts index 773c93e..18e4902 100644 --- a/lib/types/response.ts +++ b/lib/types/response.ts @@ -20,5 +20,9 @@ export class Response { isSuccess(): boolean { return this.error === null; } + + isError(): boolean { + return this.error !== null; + } } diff --git a/tests/services/chat_message.test.ts b/tests/services/chat_message.test.ts new file mode 100644 index 0000000..0048c1a --- /dev/null +++ b/tests/services/chat_message.test.ts @@ -0,0 +1,217 @@ +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ +import { MockChatHttpService } from './mock_http_service'; +import { + ChatMessageType, + CreateChatMessageParams, + MessageCursor, + QuestionStream, + RepeatedChatMessage, +} from '@appflowy-chat/types/ai'; +import { beforeEach, describe, expect, test } from '@jest/globals'; + +describe('MockChatHttpService - Create and Get Messages', () => { + let chatService: MockChatHttpService; + + beforeEach(() => { + chatService = new MockChatHttpService(); + // Create a test chat and add some messages + const chatParams = { + chat_id: 'chat1', + name: 'Test Chat', + rag_ids: [], + }; + chatService.createChat('workspace1', chatParams); + + // Add 5 messages to the chat with message type + for (let i = 0; i < 5; i++) { + const params = { + content: `Message ${i + 1}`, + message_type: ChatMessageType.User, // Adding message_type as User + } as CreateChatMessageParams; + chatService.sendMessage('workspace1', 'chat1', params); + } + }); + + // --- Test 1: Create Message --- + test('should create a new message with message_type and add it to the chat', async () => { + const params: CreateChatMessageParams = { + content: 'Hello, world!', + message_type: ChatMessageType.User, + }; + const response = await chatService.sendMessage( + 'workspace1', + 'chat1', + params + ); + + expect(response.isSuccess()).toBe(true); + expect(response.data).toBeTruthy(); + expect(response.data?.content).toBe('Hello, world!'); + + const chat = chatService['chatMap'].get('chat1'); + expect(chat?.messages.length).toBe(6); // There should be 6 messages now + expect(chat?.messages[5].content).toBe('Hello, world!'); + }); + + test('should return error when creating a message for a non-existent chat', async () => { + const params: CreateChatMessageParams = { + content: 'This should fail!', + message_type: ChatMessageType.User, + }; + const response = await chatService.sendMessage( + 'workspace1', + 'nonexistent_chat', + params + ); + + expect(response.isError()).toBe(true); + expect(response.error?.message).toBe('Chat not found'); + }); + + // --- Test 2: Get Messages (Offset Cursor) --- + test('should get messages successfully with offset cursor', async () => { + const cursor: MessageCursor = { type: 'Offset', value: 0 }; + const limit = 3; + const response = await chatService.getChatMessages( + 'workspace1', + 'chat1', + cursor, + limit + ); + + expect(response.isSuccess()).toBe(true); + const repeatedChatMessage: RepeatedChatMessage | null = response.data; + expect(repeatedChatMessage?.messages.length).toBe(limit); + expect(repeatedChatMessage?.messages[0].content).toBe('Message 1'); + expect(repeatedChatMessage?.has_more).toBe(true); // There are more messages to fetch + expect(repeatedChatMessage?.total).toBe(5); // Total number of messages in the chat + }); + + // --- Test 3: Get Messages (AfterMessageId Cursor) --- + test('should get messages successfully with AfterMessageId cursor', async () => { + const chat = chatService['chatMap'].get('chat1'); + const cursor: MessageCursor = { + type: 'AfterMessageId', + value: chat?.messages[2].message_id!, + }; // After message 3 + const limit = 2; + const response = await chatService.getChatMessages( + 'workspace1', + 'chat1', + cursor, + limit + ); + + expect(response.isSuccess()).toBe(true); + const repeatedChatMessage: RepeatedChatMessage | null = response.data; + expect(repeatedChatMessage?.messages.length).toBe(limit); + expect(repeatedChatMessage?.messages[0].content).toBe('Message 4'); + expect(repeatedChatMessage?.messages[1].content).toBe('Message 5'); + expect(repeatedChatMessage?.has_more).toBe(false); // No more messages after this + expect(repeatedChatMessage?.total).toBe(5); // Total number of messages in the chat + }); + + // --- Test 4: Get Messages (BeforeMessageId Cursor) --- + test('should get messages successfully with BeforeMessageId cursor', async () => { + const chat = chatService['chatMap'].get('chat1'); + const cursor: MessageCursor = { + type: 'BeforeMessageId', + value: chat?.messages[3].message_id!, + }; // Before message 4 + const limit = 3; + const response = await chatService.getChatMessages( + 'workspace1', + 'chat1', + cursor, + limit + ); + + expect(response.isSuccess()).toBe(true); + const repeatedChatMessage: RepeatedChatMessage | null = response.data; + expect(repeatedChatMessage?.messages.length).toBe(limit); + expect(repeatedChatMessage?.messages[0].content).toBe('Message 1'); + expect(repeatedChatMessage?.messages[1].content).toBe('Message 2'); + expect(repeatedChatMessage?.messages[2].content).toBe('Message 3'); + expect(repeatedChatMessage?.has_more).toBe(true); // There are more messages before this + expect(repeatedChatMessage?.total).toBe(5); // Total number of messages in the chat + }); + + // --- Test 5: Get Messages (Invalid Cursor Type) --- + test('should return error when using an unsupported cursor type', async () => { + const cursor: MessageCursor = { type: 'NextBack' }; + const limit = 3; + const response = await chatService.getChatMessages( + 'workspace1', + 'chat1', + cursor, + limit + ); + + expect(response.isError()).toBe(true); + expect(response.error?.message).toBe( + 'NextBack cursor type is not fully implemented' + ); + }); + + // --- Test 6: Get Messages (Chat Not Found) --- + test('should return error when trying to get messages for a non-existent chat', async () => { + const cursor: MessageCursor = { type: 'Offset', value: 0 }; + const limit = 3; + const response = await chatService.getChatMessages( + 'workspace1', + 'nonexistent_chat', + cursor, + limit + ); + + expect(response.isError()).toBe(true); + expect(response.error?.message).toBe('Chat not found'); + }); + + // --- Test 7: Get Messages (Message Not Found in AfterMessageId Cursor) --- + test('should return error if message id not found in AfterMessageId cursor', async () => { + const cursor: MessageCursor = { type: 'AfterMessageId', value: 9999 }; // Invalid message ID + const limit = 3; + const response = await chatService.getChatMessages( + 'workspace1', + 'chat1', + cursor, + limit + ); + + expect(response.isError()).toBe(true); + expect(response.error?.message).toBe('Message not found'); + }); + + // --- Test 8: Stream Message Response --- + test('should stream a message response successfully', async () => { + const chat = chatService['chatMap'].get('chat1'); + const message = chat?.messages[1]; // Message with ID 1 + if (!message) { + throw new Error('Message not found'); + } + + const response = await chatService.streamMessageResponse( + 'workspace1', + 'chat1', + message.message_id + ); + + expect(response.isSuccess()).toBe(true); + expect(response.data).toBeInstanceOf(QuestionStream); + const streamData = []; + for await (const chunk of response.data!) { + streamData.push(chunk); + } + expect(streamData.length).toBeGreaterThan(0); // Ensure there are chunks in the stream + const expectedStreamData = [ + { '1': 'Streamed answer for message 1' }, + { '0': { meta: 'Metadata for message 1' } }, + { '1': 'Another streamed answer for message 1' }, + { '0': { meta: 'Additional metadata for message 1' } }, + ]; + + // Ensure the stream data matches the expected structure + expect(streamData).toEqual(expectedStreamData); + }); +}); diff --git a/tests/services/create_chat.test.ts b/tests/services/create_chat.test.ts new file mode 100644 index 0000000..30ebba3 --- /dev/null +++ b/tests/services/create_chat.test.ts @@ -0,0 +1,171 @@ +import { MockChatHttpService } from './mock_http_service'; +import { CreateChatParams, UpdateChatParams } from '@appflowy-chat/types/ai'; +import { ErrorCode } from '@appflowy-chat/types/error'; +import { beforeEach, describe, expect, test } from '@jest/globals'; +describe('MockChatHttpService - Chat Management', () => { + let chatService: MockChatHttpService; + + beforeEach(() => { + chatService = new MockChatHttpService(); + }); + + describe('createChat', () => { + test('should create a new chat successfully', async () => { + const params: CreateChatParams = { + chat_id: 'chat1', + name: 'New Chat', + rag_ids: [], + }; + const response = await chatService.createChat('workspace1', params); + expect(response.isSuccess()).toBe(true); + + // Verify that chat was created in the service's chat map + const chatSettingsResponse = await chatService.getChatSettings( + 'workspace1', + 'chat1' + ); + expect(chatSettingsResponse.isSuccess()).toBe(true); + expect(chatSettingsResponse.data?.name).toBe('New Chat'); + }); + + test('should fail to create a chat if chat_id is missing', async () => { + const params: CreateChatParams = { + chat_id: '', + name: 'Invalid Chat', + rag_ids: [], + }; + const response = await chatService.createChat('workspace1', params); + expect(response.isSuccess()).toBe(false); + expect(response.error?.code).toBe(ErrorCode.InvalidRequest); + }); + }); + + describe('deleteChat', () => { + test('should delete an existing chat successfully', async () => { + const createParams: CreateChatParams = { + chat_id: 'chat1', + name: 'Chat to Delete', + rag_ids: [], + }; + await chatService.createChat('workspace1', createParams); + + const deleteResponse = await chatService.deleteChat( + 'workspace1', + 'chat1' + ); + expect(deleteResponse.isSuccess()).toBe(true); + + // Verify that the chat has been deleted + const getSettingsResponse = await chatService.getChatSettings( + 'workspace1', + 'chat1' + ); + expect(getSettingsResponse.isSuccess()).toBe(false); + expect(getSettingsResponse.error?.code).toBe(ErrorCode.RecordNotFound); + }); + + test('should return error when deleting a non-existent chat', async () => { + const deleteResponse = await chatService.deleteChat( + 'workspace1', + 'non_existing_chat' + ); + expect(deleteResponse.isSuccess()).toBe(false); + expect(deleteResponse.error?.code).toBe(ErrorCode.RecordNotFound); + }); + }); + + describe('updateChatSettings', () => { + test('should update the chat settings successfully', async () => { + const createParams: CreateChatParams = { + chat_id: 'chat1', + name: 'Old Chat', + rag_ids: [], + }; + await chatService.createChat('workspace1', createParams); + + const updateParams: UpdateChatParams = { + name: 'Updated Chat', + rag_ids: ['rag1'], + metadata: { key: 'value' }, + }; + const updateResponse = await chatService.updateChatSettings( + 'workspace1', + 'chat1', + updateParams + ); + expect(updateResponse.isSuccess()).toBe(true); + + const getSettingsResponse = await chatService.getChatSettings( + 'workspace1', + 'chat1' + ); + expect(getSettingsResponse.isSuccess()).toBe(true); + expect(getSettingsResponse.data?.name).toBe('Updated Chat'); + expect(getSettingsResponse.data?.rag_ids).toEqual(['rag1']); + }); + + test('should fail to update settings for a non-existing chat', async () => { + const updateParams: UpdateChatParams = { + name: 'Updated Chat', + rag_ids: ['rag1'], + metadata: { key: 'value' }, + }; + const updateResponse = await chatService.updateChatSettings( + 'workspace1', + 'non_existing_chat', + updateParams + ); + expect(updateResponse.isSuccess()).toBe(false); + expect(updateResponse.error?.code).toBe(ErrorCode.RecordNotFound); + }); + + test('should fail to update chat settings with invalid data', async () => { + const createParams: CreateChatParams = { + chat_id: 'chat1', + name: 'Old Chat', + rag_ids: [], + }; + await chatService.createChat('workspace1', createParams); + + const updateParams: UpdateChatParams = { + name: null, + rag_ids: null, + metadata: null, + }; // Invalid update + const updateResponse = await chatService.updateChatSettings( + 'workspace1', + 'chat1', + updateParams + ); + expect(updateResponse.isSuccess()).toBe(false); + expect(updateResponse.error?.code).toBe(ErrorCode.InvalidRequest); + }); + }); + + describe('getChatSettings', () => { + test('should retrieve the chat settings successfully', async () => { + const createParams: CreateChatParams = { + chat_id: 'chat1', + name: 'New Chat', + rag_ids: [], + }; + await chatService.createChat('workspace1', createParams); + + const getSettingsResponse = await chatService.getChatSettings( + 'workspace1', + 'chat1' + ); + expect(getSettingsResponse.isSuccess()).toBe(true); + expect(getSettingsResponse.data?.name).toBe('New Chat'); + }); + + test('should return error if chat does not exist', async () => { + const getSettingsResponse = await chatService.getChatSettings( + 'workspace1', + 'non_existing_chat' + ); + expect(getSettingsResponse.isSuccess()).toBe(false); + expect(getSettingsResponse.error?.code).toBe(ErrorCode.RecordNotFound); + }); + }); +}); diff --git a/tests/services/http_service.test.ts b/tests/services/http_service.test.ts deleted file mode 100644 index dab241a..0000000 --- a/tests/services/http_service.test.ts +++ /dev/null @@ -1,314 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { Response } from '@appflowy-chat/types/response'; -import { - ChatSettings, - CreateChatParams, - UpdateChatParams, - CreateChatMessageParams, - ChatMessage, - QuestionStream, - RelatedQuestion, - MessageCursor, - RepeatedChatMessage, - ChatAuthor, - ChatAuthorType, - JSONValue, - STREAM_ANSWER_KEY, - STREAM_METADATA_KEY, -} from '@appflowy-chat/types/ai'; -import { ChatHttpService } from '@appflowy-chat/services/http_service'; -import { beforeEach, describe, expect, test } from '@jest/globals'; -import { ChatError } from '@appflowy-chat/types/error'; -import { ErrorCode } from '@appflowy-chat/types/error'; - -class MockChat { - settings: ChatSettings; - messages: ChatMessage[]; - - constructor(settings: ChatSettings, messages: ChatMessage[]) { - this.settings = settings; - this.messages = messages; - } -} - -// Create a mock implementation of the ChatHttpService -class MockChatHttpService extends ChatHttpService { - message_id_counter: number = 0; - // create a map to store the chat id and chat object - private chatMap: Map = new Map(); - - nextMessageId(): number { - return this.message_id_counter++; - } - - createChat( - _workspace_id: string, - params: CreateChatParams - ): Promise> { - const settings = { - chat_id: params.chat_id, - name: params.name, - rag_ids: params.rag_ids, - metadata: {}, - } as ChatSettings; - this.chatMap.set(params.chat_id, new MockChat(settings, [])); - return Promise.resolve(Response.fromSuccess(undefined)); - } - - deleteChat(_workspace_id: string, chat_id: string): Promise> { - this.chatMap.delete(chat_id); - return Promise.resolve(Response.fromSuccess(undefined)); - } - - updateChatSettings( - _workspace_id: string, - chat_id: string, - params: UpdateChatParams - ): Promise> { - const chatSettings = this.chatMap.get(chat_id); - if (!chatSettings) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Chat not found') - ) - ); - } - - if (params.name !== null) { - chatSettings.settings.name = params.name; - } - if (params.rag_ids !== null) { - chatSettings.settings.rag_ids = params.rag_ids; - } - if (params.metadata !== null) { - chatSettings.settings.metadata = params.metadata; - } - - return Promise.resolve(Response.fromSuccess(undefined)); - } - - getChatSettings( - _workspace_id: string, - chat_id: string - ): Promise> { - const chatSettings = this.chatMap.get(chat_id); - if (!chatSettings) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Chat not found') - ) - ); - } - return Promise.resolve(Response.fromSuccess(chatSettings.settings)); - } - - getChatMessages( - _workspace_id: string, - chat_id: string, - cursor: MessageCursor, - limit: number - ): Promise> { - const chat = this.chatMap.get(chat_id); - if (!chat) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Chat not found') - ) - ); - } - - let startIndex: number | null = null; - let endIndex: number | null = null; - - switch (cursor.type) { - case 'Offset': - // Return messages starting from the specified offset - startIndex = cursor.value; - endIndex = startIndex + limit; - break; - - case 'AfterMessageId': - // Find the message with the specified ID and return messages after it - startIndex = chat.messages.findIndex( - (msg) => msg.message_id === cursor.value - ); - if (startIndex === -1) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Message not found') - ) - ); - } - startIndex += 1; // Start after the given message ID - endIndex = startIndex + limit; - break; - - case 'BeforeMessageId': - // Find the message with the specified ID and return messages before it - startIndex = chat.messages.findIndex( - (msg) => msg.message_id === cursor.value - ); - if (startIndex === -1) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Message not found') - ) - ); - } - endIndex = startIndex; // End at the specified message ID - startIndex = Math.max(0, endIndex - limit); // Ensure we don't go out of bounds - break; - - case 'NextBack': - // Assuming "NextBack" indicates pagination and we don't have enough context to infer the direction - return Promise.resolve( - Response.fromError( - new ChatError( - ErrorCode.InvalidRequest, - 'NextBack cursor type is not fully implemented' - ) - ) - ); - } - - // Slice the messages array based on calculated indices - const messagesToReturn = chat.messages.slice(startIndex, endIndex); - - // Check if there are more messages available after this slice - const hasMore = endIndex < chat.messages.length; - - // Return the response in the format of RepeatedChatMessage - const repeatedChatMessage: RepeatedChatMessage = { - messages: messagesToReturn, - has_more: hasMore, - total: chat.messages.length, // Total number of messages - }; - - return Promise.resolve(Response.fromSuccess(repeatedChatMessage)); - } - - sendMessage( - _workspace_id: string, - chat_id: string, - params: CreateChatMessageParams - ): Promise> { - const chat = this.chatMap.get(chat_id); - if (!chat) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Chat not found') - ) - ); - } - - const author = { - author_id: 1, - author_type: ChatAuthorType.Human, - } as ChatAuthor; - - const message = { - author: author, - message_id: this.nextMessageId(), - content: params.content, - created_at: new Date(), - meta_data: {}, - reply_message_id: null, - } as ChatMessage; - chat.messages.push(message); - return Promise.resolve(Response.fromSuccess(message)); - } - - streamMessageResponse( - _workspace_id: string, - chat_id: string, - message_id: number - ): Promise> { - const chat = this.chatMap.get(chat_id); - if (!chat) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Chat not found') - ) - ); - } - - // Find the message that corresponds to the given message_id - const message = chat.messages.find((msg) => msg.message_id === message_id); - if (!message) { - return Promise.resolve( - Response.fromError( - new ChatError(ErrorCode.RecordNotFound, 'Message not found') - ) - ); - } - - // Simulate streaming by generating an AsyncIterableIterator - const stream = this.createStream(message_id); - - // Create and return the stream wrapped in a Response object - return QuestionStream.fromStream(stream).then((questionStream) => { - return Response.fromSuccess(questionStream); - }); - } - - // Helper function to create an AsyncIterableIterator for the stream - - getRelatedQuestions( - _workspace_id: string, - _chat_id: string, - _message_id: number - ): Promise> { - const questions = [ - { content: 'Related question', metadata: {} }, - { content: 'Related question 2', metadata: {} }, - { content: 'Related question 3', metadata: {} }, - ] as RelatedQuestion[]; - return Promise.resolve(Response.fromSuccess(questions)); - } - - private async *createStream( - message_id: number - ): AsyncIterableIterator { - const streamData = [ - { [STREAM_ANSWER_KEY]: `Streamed answer for message ${message_id}` }, - { [STREAM_METADATA_KEY]: { meta: 'Metadata for message ' + message_id } }, - { - [STREAM_ANSWER_KEY]: `Another streamed answer for message ${message_id}`, - }, - { - [STREAM_METADATA_KEY]: { - meta: 'Additional metadata for message ' + message_id, - }, - }, - ]; - - for (const chunk of streamData) { - // Simulate a small delay for streaming - await new Promise((resolve) => setTimeout(resolve, 100)); - - // Yield the chunk (either answer or metadata) - yield chunk; - } - - return null; - } -} - -// Jest test suite -describe('ChatHttpService', () => { - let chatService: MockChatHttpService; - - beforeEach(() => { - chatService = new MockChatHttpService(); - }); - - test('should create a new chat', async () => { - const params = { - chat_id: 'chat1', - name: 'New Chat', - rag_ids: [], - } as CreateChatParams; - const response = await chatService.createChat('workspace1', params); - expect(response.isSuccess()).toBe(true); - }); -}); diff --git a/tests/services/mock.ts b/tests/services/mock_http_service.ts similarity index 91% rename from tests/services/mock.ts rename to tests/services/mock_http_service.ts index f8a86cf..2bd3714 100644 --- a/tests/services/mock.ts +++ b/tests/services/mock_http_service.ts @@ -44,6 +44,13 @@ export class MockChatHttpService extends ChatHttpService { _workspace_id: string, params: CreateChatParams ): Promise> { + if (!params.chat_id) { + return Promise.resolve( + Response.fromError( + new ChatError(ErrorCode.InvalidRequest, 'Chat ID is required') + ) + ); + } const settings = { chat_id: params.chat_id, name: params.name, @@ -55,6 +62,13 @@ export class MockChatHttpService extends ChatHttpService { } deleteChat(_workspace_id: string, chat_id: string): Promise> { + if (!this.chatMap.has(chat_id)) { + return Promise.resolve( + Response.fromError( + new ChatError(ErrorCode.RecordNotFound, 'Chat not found') + ) + ); + } this.chatMap.delete(chat_id); return Promise.resolve(Response.fromSuccess(undefined)); } @@ -73,6 +87,19 @@ export class MockChatHttpService extends ChatHttpService { ); } + // return error if all params are null + if ( + params.name === null && + params.rag_ids === null && + params.metadata === null + ) { + return Promise.resolve( + Response.fromError( + new ChatError(ErrorCode.InvalidRequest, 'All parameters are null') + ) + ); + } + if (params.name !== null) { chatSettings.settings.name = params.name; } @@ -242,7 +269,7 @@ export class MockChatHttpService extends ChatHttpService { } // Simulate streaming by generating an AsyncIterableIterator - const stream = this.createStream(message_id); + const stream = this.createStream(message_id); // This should return an async iterator // Create and return the stream wrapped in a Response object return QuestionStream.fromStream(stream).then((questionStream) => {