import { act, createElement } from "react"; import { createRoot } from "react-dom/client"; import { SWRConfig } from "swr"; import { expect, it, vi } from "vitest"; import type { AgentApiClient, AgentTopic } from "@/features/agent"; import { useAgentTopics } from "./use-agent-topics"; import { WorkbenchSessionProvider } from "./workbench-session-provider"; it("reuses theme reads and keeps a late project result out of the personal theme list", async () => { const topic = (id: string): AgentTopic => ({ id, name: id, createdAt: "2026-10-22T01:00:00Z", updatedAt: "2026-10-22T01:00:00Z" }); let finish!: (topics: AgentTopic[]) => void; const projectRead = vi.fn(() => new Promise((resolve) => { finish = resolve; })); const personalRead = vi.fn(async () => [topic("personal-theme")]); const clients = { project: { listTopics: projectRead }, personal: { listTopics: personalRead } } as unknown as Record<"project" | "personal", AgentApiClient>; const root = createRoot(document.createElement("div")); const cache = new Map(); let topics!: ReturnType; function Probe({ scope }: { scope: "project" | "personal" }) { topics = useAgentTopics(clients[scope], scope); return null; } const render = (scope: "project" | "personal") => root.render(createElement(WorkbenchSessionProvider, null, createElement(SWRConfig, { value: { provider: () => cache, dedupingInterval: 0 } }, createElement(Probe, { scope })))); try { await act(async () => render("project")); let pending!: Promise; await act(async () => { pending = topics.ensure(); }); await act(async () => render("personal")); await act(async () => { finish([topic("project-theme")]); await pending; }); expect(topics.topics.map((entry) => entry.id)).toEqual(["personal-theme"]); for (let i = 0; i < 10; i++) await act(async () => { await topics.ensure(); }); expect(projectRead).toHaveBeenCalledTimes(1); expect(personalRead).toHaveBeenCalledTimes(1); } finally { await act(async () => root.unmount()); } }); it("keeps a newly created topic selectable when the open menu's older read finishes later", async () => { const topic = (id: string): AgentTopic => ({ id, name: id, createdAt: "2026-10-22T01:00:00Z", updatedAt: "2026-10-22T01:00:00Z" }); let finish!: (topics: AgentTopic[]) => void; const client = { listTopics: vi.fn(() => new Promise((resolve) => { finish = resolve; })), createTopic: vi.fn(async () => topic("new-topic")), } as unknown as AgentApiClient; let topics!: ReturnType; function Probe() { topics = useAgentTopics(client, "project:slow-read"); return null; } const root = createRoot(document.createElement("div")); const cache = new Map(); try { await act(async () => root.render(createElement(WorkbenchSessionProvider, null, createElement(SWRConfig, { value: { provider: () => cache, dedupingInterval: 0 } }, createElement(Probe))))); let reading!: Promise; let creating!: Promise; await act(async () => { reading = topics.ensure(); }); await act(async () => { creating = topics.create("new-topic"); }); await act(async () => { finish([topic("existing-topic")]); await reading; await creating; }); expect(topics.topics.map((entry) => entry.id)).toEqual(["existing-topic", "new-topic"]); await act(async () => { await topics.ensure(); }); expect(topics.topics.map((entry) => entry.id)).toEqual(["existing-topic", "new-topic"]); expect(client.listTopics).toHaveBeenCalledTimes(1); } finally { await act(async () => root.unmount()); } });