import { beforeEach, describe, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => { type Handler = (...args: unknown[]) => void; class SimpleEmitter { private listeners = new Map(); on(event: string, handler: Handler) { const current = this.listeners.get(event) ?? []; current.push(handler); this.listeners.set(event, current); return this; } once(event: string, handler: Handler) { const wrapped: Handler = (...args) => { this.removeListener(event, wrapped); handler(...args); }; return this.on(event, wrapped); } removeListener(event: string, handler: Handler) { const current = this.listeners.get(event) ?? []; this.listeners.set(event, current.filter((item) => item !== handler)); return this; } emit(event: string, ...args: unknown[]) { const current = this.listeners.get(event) ?? []; for (const handler of current) { handler(...args); } } } const store = { init: vi.fn(async () => undefined), watch: vi.fn(async () => undefined), close: vi.fn(), }; class TaskStore { constructor(_rootDir: string) {} init = store.init; watch = store.watch; close = store.close; } const server = Object.assign(new SimpleEmitter(), { address: vi.fn(() => ({ port: 4545 })), close: vi.fn((cb: () => void) => cb()), }); const listen = vi.fn(() => { queueMicrotask(() => server.emit("listening")); return server; }); const createServer = vi.fn(() => ({ listen })); return { TaskStore, createServer, store, listen }; }); vi.mock("@fusion/core", () => ({ TaskStore: mocks.TaskStore })); vi.mock("@fusion/dashboard", () => ({ createServer: mocks.createServer })); describe("DesktopLocalServerManager", () => { beforeEach(() => { vi.clearAllMocks(); }); it("starts local runtime and exposes port", async () => { const { DesktopLocalServerManager } = await import("../local-server.ts"); const manager = new DesktopLocalServerManager("/repo"); const runtime = await manager.start(); expect(runtime.port).toBe(4545); expect(manager.getPort()).toBe(4545); expect(manager.getState().status).toBe("ready"); }); it("stops local runtime and resets state", async () => { const { DesktopLocalServerManager } = await import("../local-server.ts"); const manager = new DesktopLocalServerManager("/repo"); await manager.start(); await manager.stop(); expect(mocks.store.close).toHaveBeenCalled(); expect(manager.getState().status).toBe("idle"); expect(manager.getPort()).toBeUndefined(); }); it("sets error state when startup fails", async () => { mocks.store.init.mockRejectedValueOnce(new Error("init failed")); const { DesktopLocalServerManager } = await import("../local-server.ts"); const manager = new DesktopLocalServerManager("/repo"); await expect(manager.start()).rejects.toThrow("init failed"); expect(manager.getState()).toMatchObject({ status: "error", error: "init failed" }); }); it("returns existing runtime when start is called twice", async () => { const { DesktopLocalServerManager } = await import("../local-server.ts"); const manager = new DesktopLocalServerManager("/repo"); const first = await manager.start(); const second = await manager.start(); expect(first).toBe(second); expect(mocks.listen).toHaveBeenCalledTimes(1); }); });