import { describe, test, expect, beforeEach } from "bun:test"; import { mcpClientManager, setMCPWebSocketConnection, } from "../src/lib/server/mcp-client"; import { updateEditorContent, observeConsoleTool, } from "../src/lib/server/tools"; import { consoleBuffer } from "../src/lib/server/console-buffer"; import type { WebSocket } from "ws"; describe("MCP Editor Tools", () => { const defaultContent = ` `; let tools: ReturnType; beforeEach(async () => { updateEditorContent(defaultContent); consoleBuffer.clear(); await mcpClientManager.initialize(); tools = mcpClientManager.getTools(); }); test("reads complete editor content", async () => { const readTool = tools.find((t) => t.name === "read_editor"); expect(readTool).toBeDefined(); const result = await readTool!.func({}); expect(result).toContain("game-canvas"); expect(result).toContain("static-part"); }); test("reads specific lines from editor", async () => { const readLinesTool = tools.find((t) => t.name === "read_editor_lines"); expect(readLinesTool).toBeDefined(); const result = await readLinesTool!.func({ startLine: 2, endLine: 3 }); expect(result).toContain("Lines 2-3"); expect(result).toContain("world"); expect(result).toContain("static-part"); }); test("handles line reading out of bounds", async () => { const readLinesTool = tools.find((t) => t.name === "read_editor_lines"); const result = await readLinesTool!.func({ startLine: 999 }); expect(result).toContain("Error:"); expect(result).toContain("exceeds total lines"); }); test("searches for text in editor", async () => { const searchTool = tools.find((t) => t.name === "search_editor"); expect(searchTool).toBeDefined(); const result = await searchTool!.func({ query: "canvas" }); expect(result).toContain("Found"); expect(result).toContain("canvas"); expect(result).toContain("game-canvas"); }); test("handles search with no results", async () => { const searchTool = tools.find((t) => t.name === "search_editor"); const result = await searchTool!.func({ query: "nonexistent" }); expect(result).toContain("No matches found"); }); test("edits existing content", async () => { const editTool = tools.find((t) => t.name === "edit_editor"); const readTool = tools.find((t) => t.name === "read_editor"); expect(editTool).toBeDefined(); await editTool!.func({ oldText: 'shape="box"', newText: 'shape="sphere"', }); const content = await readTool!.func({}); expect(content).toContain("sphere"); expect(content).not.toContain('shape="box"'); }); test("handles edit with non-matching text", async () => { const editTool = tools.find((t) => t.name === "edit_editor"); const result = await editTool!.func({ oldText: "nonexistent", newText: "replacement", }); expect(result).toContain("Error"); }); test("writes complete new content", async () => { const writeTool = tools.find((t) => t.name === "write_editor"); const readTool = tools.find((t) => t.name === "read_editor"); expect(writeTool).toBeDefined(); const newContent = "
New content
"; await writeTool!.func({ content: newContent }); const result = await readTool!.func({}); expect(result).toContain("New content"); expect(result).not.toContain("game-canvas"); }); }); describe("Console Tool", () => { beforeEach(() => { consoleBuffer.clear(); }); test("observes empty console", async () => { const result = await observeConsoleTool.func(""); expect(result).toContain("No new console messages"); }); test("observes console messages", async () => { consoleBuffer.addMessage({ id: "1", type: "log", message: "Test message", timestamp: Date.now(), }); const result = await observeConsoleTool.func(""); expect(result).toContain("Test message"); expect(result).toContain("[log]"); }); test("marks messages as read", async () => { consoleBuffer.addMessage({ id: "1", type: "error", message: "Error occurred", timestamp: Date.now(), }); await observeConsoleTool.func(""); const secondRead = await observeConsoleTool.func(""); expect(secondRead).toContain("No new console messages"); }); test("detects game state from console", async () => { consoleBuffer.addMessage({ id: "1", type: "log", message: "🎮 Starting game", timestamp: Date.now(), }); const result = await observeConsoleTool.func(""); expect(result).toContain("Loading: true"); consoleBuffer.addMessage({ id: "2", type: "log", message: "✅ Game started", timestamp: Date.now() + 100, }); const result2 = await observeConsoleTool.func(""); expect(result2).toContain("Ready: true"); }); }); describe("MCP WebSocket Connection", () => { test("sets WebSocket connection for MCP client", () => { const mockWs = { readyState: 1, // OPEN OPEN: 1, send: (data: string) => { const message = JSON.parse(data); expect(message.type).toBeDefined(); expect(message.payload).toBeDefined(); }, } as unknown as WebSocket; setMCPWebSocketConnection(mockWs); }); });