Files
next-tjwater-frontend/src/features/workbench/hooks/use-agent-topics.test.ts
T
jiang 2d8506fea0
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s
feat: add project-aware agent workspace
2026-10-22 18:52:18 +08:00

59 lines
3.6 KiB
TypeScript

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<AgentTopic[]>((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<typeof useAgentTopics>;
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<void>;
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<AgentTopic[]>((resolve) => { finish = resolve; })),
createTopic: vi.fn(async () => topic("new-topic")),
} as unknown as AgentApiClient;
let topics!: ReturnType<typeof useAgentTopics>;
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<void>;
let creating!: Promise<AgentTopic>;
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()); }
});