import { beforeEach, describe, expect, it, vi } from "vitest" import { createActor } from "xstate" import { chatMachine } from "../../services/chat-machine" import { ChatMessage } from "../../types/chat" describe("ChatMachine", () => { beforeEach(() => { vi.clearAllMocks() }) it("should have correct initial context", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем начальный контекст expect(snapshot.context).toEqual({ chatMessages: [], selectedAgentId: "claude-4-sonnet", isProcessing: false, error: null, currentSessionId: null, sessions: [], isCreatingNewChat: false, }) // Проверяем начальное состояние expect(snapshot.value).toBe("idle") // Останавливаем актора actor.stop() }) it("should handle SEND_CHAT_MESSAGE event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Отправляем событие SEND_CHAT_MESSAGE actor.send({ type: "SEND_CHAT_MESSAGE", message: "Hello, AI!" }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что состояние изменилось на processing expect(snapshot.value).toBe("processing") // Проверяем, что сообщение добавилось в контекст expect(snapshot.context.chatMessages).toHaveLength(1) expect(snapshot.context.chatMessages[0].content).toBe("Hello, AI!") expect(snapshot.context.chatMessages[0].role).toBe("user") expect(snapshot.context.isProcessing).toBe(true) // Останавливаем актора actor.stop() }) it("should handle RECEIVE_CHAT_MESSAGE event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Сначала отправляем сообщение пользователя actor.send({ type: "SEND_CHAT_MESSAGE", message: "Hello, AI!" }) // Создаем сообщение от агента const agentMessage: ChatMessage = { id: "agent-msg-1", content: "Hello! How can I help you?", role: "assistant", agent: "claude-4-sonnet", timestamp: new Date(), } // Отправляем событие RECEIVE_CHAT_MESSAGE actor.send({ type: "RECEIVE_CHAT_MESSAGE", message: agentMessage }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что состояние вернулось в idle expect(snapshot.value).toBe("idle") // Проверяем, что сообщение добавилось в контекст expect(snapshot.context.chatMessages).toHaveLength(2) expect(snapshot.context.chatMessages[1]).toEqual(agentMessage) expect(snapshot.context.isProcessing).toBe(false) // Останавливаем актора actor.stop() }) it("should handle SELECT_AGENT event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Отправляем событие SELECT_AGENT actor.send({ type: "SELECT_AGENT", agentId: "claude-4-opus" }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что агент выбран expect(snapshot.context.selectedAgentId).toBe("claude-4-opus") // Останавливаем актора actor.stop() }) it("should handle CLEAR_MESSAGES event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Добавляем первое сообщение actor.send({ type: "SEND_CHAT_MESSAGE", message: "Message 1" }) // Симулируем получение ответа, чтобы вернуться в idle const agentMessage: ChatMessage = { id: "agent-msg-1", content: "Response 1", role: "assistant", timestamp: new Date(), } actor.send({ type: "RECEIVE_CHAT_MESSAGE", message: agentMessage }) // Добавляем второе сообщение actor.send({ type: "SEND_CHAT_MESSAGE", message: "Message 2" }) // Симулируем получение второго ответа const agentMessage2: ChatMessage = { id: "agent-msg-2", content: "Response 2", role: "assistant", timestamp: new Date(), } actor.send({ type: "RECEIVE_CHAT_MESSAGE", message: agentMessage2 }) // Проверяем, что сообщения добавились (2 пользователя + 2 агента = 4) let snapshot = actor.getSnapshot() expect(snapshot.context.chatMessages).toHaveLength(4) // Очищаем сообщения (теперь в состоянии idle) actor.send({ type: "CLEAR_MESSAGES" }) // Получаем снимок состояния snapshot = actor.getSnapshot() // Проверяем, что сообщения очистились expect(snapshot.context.chatMessages).toHaveLength(0) expect(snapshot.context.error).toBeNull() // Останавливаем актора actor.stop() }) it("should handle REMOVE_MESSAGE event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Добавляем сообщение actor.send({ type: "SEND_CHAT_MESSAGE", message: "Test message" }) // Симулируем получение ответа, чтобы вернуться в idle const agentMessage: ChatMessage = { id: "agent-msg-1", content: "Response", role: "assistant", timestamp: new Date(), } actor.send({ type: "RECEIVE_CHAT_MESSAGE", message: agentMessage }) // Получаем ID первого сообщения (пользователя) let snapshot = actor.getSnapshot() const messageId = snapshot.context.chatMessages[0].id // Удаляем сообщение (теперь в состоянии idle) actor.send({ type: "REMOVE_MESSAGE", messageId }) // Получаем снимок состояния snapshot = actor.getSnapshot() // Проверяем, что сообщение пользователя удалилось, осталось только сообщение агента expect(snapshot.context.chatMessages).toHaveLength(1) expect(snapshot.context.chatMessages[0].role).toBe("assistant") // Останавливаем актора actor.stop() }) it("should handle SET_ERROR event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Переводим в состояние processing actor.send({ type: "SEND_CHAT_MESSAGE", message: "Test" }) // Отправляем ошибку actor.send({ type: "SET_ERROR", error: "API Error" }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что ошибка установлена и состояние вернулось в idle expect(snapshot.value).toBe("idle") expect(snapshot.context.error).toBe("API Error") expect(snapshot.context.isProcessing).toBe(false) // Останавливаем актора actor.stop() }) it("should handle SET_PROCESSING event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Переводим в состояние processing actor.send({ type: "SEND_CHAT_MESSAGE", message: "Test" }) // Изменяем состояние обработки actor.send({ type: "SET_PROCESSING", isProcessing: false }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что состояние обработки изменилось expect(snapshot.context.isProcessing).toBe(false) // Останавливаем актора actor.stop() }) it("should handle SWITCH_SESSION event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Добавляем сообщение и симулируем получение ответа, чтобы быть в состоянии idle actor.send({ type: "SEND_CHAT_MESSAGE", message: "Test message" }) const agentMessage: ChatMessage = { id: "agent-msg-1", content: "Response", role: "assistant", timestamp: new Date(), } actor.send({ type: "RECEIVE_CHAT_MESSAGE", message: agentMessage }) // Переключаем сессию (теперь в состоянии idle) actor.send({ type: "SWITCH_SESSION", sessionId: "session-1" }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что сессия переключилась и сообщения очистились expect(snapshot.context.currentSessionId).toBe("session-1") expect(snapshot.context.chatMessages).toHaveLength(0) expect(snapshot.context.error).toBeNull() // Останавливаем актора actor.stop() }) it("should handle LOAD_SESSION_MESSAGES event", () => { // Создаем актора из машины состояний const actor = createActor(chatMachine) // Запускаем актора actor.start() // Создаем тестовые сообщения const sessionMessages: ChatMessage[] = [ { id: "msg-1", content: "User message", role: "user", timestamp: new Date(), }, { id: "msg-2", content: "Assistant response", role: "assistant", timestamp: new Date(), agent: "claude-4-sonnet", }, ] // Загружаем сообщения сессии actor.send({ type: "LOAD_SESSION_MESSAGES", messages: sessionMessages }) // Получаем снимок состояния const snapshot = actor.getSnapshot() // Проверяем, что сообщения загрузились expect(snapshot.context.chatMessages).toHaveLength(2) expect(snapshot.context.chatMessages).toEqual(sessionMessages) expect(snapshot.context.error).toBeNull() // Останавливаем актора actor.stop() }) })