import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { defaultStudioSettings, sanitizeStudioSettings } from "@/lib/studio/settings"; import { StudioSettingsCoordinator } from "@/lib/studio/coordinator"; describe("StudioSettingsCoordinator", () => { const createResponse = () => ({ settings: sanitizeStudioSettings(defaultStudioSettings()), }); beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); it("coalesces multiple scheduled patches into one update", async () => { const fetchSettings = vi.fn(async () => createResponse()); const updateSettings = vi.fn(async () => createResponse()); const coordinator = new StudioSettingsCoordinator({ fetchSettings, updateSettings }, 300); coordinator.schedulePatch({ gateway: { url: "ws://localhost:18789", token: "abc" }, }); coordinator.schedulePatch({ focused: { "ws://localhost:18789": { mode: "focused", filter: "running", selectedAgentId: null, }, }, }); await vi.advanceTimersByTimeAsync(300); expect(updateSettings).toHaveBeenCalledTimes(1); expect(updateSettings).toHaveBeenCalledWith({ gateway: { url: "ws://localhost:18789", token: "abc" }, focused: { "ws://localhost:18789": { mode: "focused", filter: "running", selectedAgentId: null, }, }, }); coordinator.dispose(); }); it("flushPending persists queued patch immediately", async () => { const fetchSettings = vi.fn(async () => createResponse()); const updateSettings = vi.fn(async () => createResponse()); const coordinator = new StudioSettingsCoordinator({ fetchSettings, updateSettings }, 1000); coordinator.schedulePatch({ gateway: { url: "ws://localhost:18789", token: "session-a" }, }); await coordinator.flushPending(); expect(updateSettings).toHaveBeenCalledTimes(1); expect(updateSettings).toHaveBeenCalledWith({ gateway: { url: "ws://localhost:18789", token: "session-a" }, }); await vi.advanceTimersByTimeAsync(2000); expect(updateSettings).toHaveBeenCalledTimes(1); coordinator.dispose(); }); it("dispose clears pending timer without writing", async () => { const fetchSettings = vi.fn(async () => createResponse()); const updateSettings = vi.fn(async () => createResponse()); const coordinator = new StudioSettingsCoordinator({ fetchSettings, updateSettings }, 200); coordinator.schedulePatch({ focused: { "ws://localhost:18789": { mode: "focused", filter: "approvals", selectedAgentId: null, }, }, }); coordinator.dispose(); await vi.advanceTimersByTimeAsync(500); expect(updateSettings).not.toHaveBeenCalled(); }); });