import { describe, it, expect } from "vitest"; import { mapMessageToState, extractTextFromMessage, extractToolInfo } from "./stateMapper"; import type { ClaudeStreamMessage } from "$lib/types/messages"; describe("stateMapper", () => { describe("mapMessageToState", () => { it("returns idle for system init message", () => { const message: ClaudeStreamMessage = { type: "system", subtype: "init", session_id: "test-session", cwd: "/home/test", tools: ["Read", "Write", "Edit"], }; expect(mapMessageToState(message)).toBe("idle"); }); it("returns null for non-init system messages", () => { const message: ClaudeStreamMessage = { type: "system", subtype: "compact_boundary", }; expect(mapMessageToState(message)).toBeNull(); }); it("returns searching for Read tool", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "Read", input: { file_path: "/test/file.txt" }, }, ], model: "claude-3", stop_reason: "tool_use", }, }; expect(mapMessageToState(message)).toBe("searching"); }); it("returns coding for Edit tool", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "Edit", input: { file_path: "/test/file.txt", old_string: "foo", new_string: "bar" }, }, ], model: "claude-3", stop_reason: "tool_use", }, }; expect(mapMessageToState(message)).toBe("coding"); }); it("returns mcp for mcp__ prefixed tools", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "mcp__github__list_repos", input: {}, }, ], model: "claude-3", stop_reason: "tool_use", }, }; expect(mapMessageToState(message)).toBe("mcp"); }); it("returns thinking for Task tool", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "Task", input: { prompt: "test task" }, }, ], model: "claude-3", stop_reason: "tool_use", }, }; expect(mapMessageToState(message)).toBe("thinking"); }); it("returns typing for text content", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [{ type: "text", text: "Hello, Naomi!" }], model: "claude-3", stop_reason: "end_turn", }, }; expect(mapMessageToState(message)).toBe("typing"); }); it("returns success for result success message", () => { const message: ClaudeStreamMessage = { type: "result", subtype: "success", result: "Task completed", }; expect(mapMessageToState(message)).toBe("success"); }); it("returns error for result error message", () => { const message: ClaudeStreamMessage = { type: "result", subtype: "error_max_turns", }; expect(mapMessageToState(message)).toBe("error"); }); it("returns null for user messages", () => { const message: ClaudeStreamMessage = { type: "user", message: { content: [{ type: "text", text: "Hello" }] }, }; expect(mapMessageToState(message)).toBeNull(); }); }); describe("extractTextFromMessage", () => { it("extracts text from assistant message", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "text", text: "Hello!" }, { type: "text", text: "How are you?" }, ], model: "claude-3", stop_reason: "end_turn", }, }; expect(extractTextFromMessage(message)).toBe("Hello!\nHow are you?"); }); it("returns null for assistant message without text", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "Read", input: { file_path: "/test/file.txt" }, }, ], model: "claude-3", stop_reason: "tool_use", }, }; expect(extractTextFromMessage(message)).toBeNull(); }); it("extracts text from stream_event delta", () => { const message: ClaudeStreamMessage = { type: "stream_event", event: { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "streaming text" }, }, }; expect(extractTextFromMessage(message)).toBe("streaming text"); }); it("extracts result from result message", () => { const message: ClaudeStreamMessage = { type: "result", subtype: "success", result: "Completed successfully", }; expect(extractTextFromMessage(message)).toBe("Completed successfully"); }); }); describe("extractToolInfo", () => { it("extracts tool info from assistant message", () => { const message: ClaudeStreamMessage = { type: "assistant", message: { content: [ { type: "tool_use", id: "tool-1", name: "Read", input: { file_path: "/test/file.txt" }, }, { type: "tool_use", id: "tool-2", name: "Edit", input: { file_path: "/test/file.txt", old_string: "a", new_string: "b" }, }, ], model: "claude-3", stop_reason: "tool_use", }, }; const tools = extractToolInfo(message); expect(tools).toHaveLength(2); expect(tools[0]).toEqual({ name: "Read", input: { file_path: "/test/file.txt" }, }); expect(tools[1]).toEqual({ name: "Edit", input: { file_path: "/test/file.txt", old_string: "a", new_string: "b" }, }); }); it("returns empty array for non-assistant messages", () => { const message: ClaudeStreamMessage = { type: "user", message: { content: [{ type: "text", text: "Hello" }] }, }; expect(extractToolInfo(message)).toEqual([]); }); }); });