import "@/test-utils/named-admin-session"; import { getCurrentUser } from "@/lib/auth/session"; import { describe, it, expect, vi, beforeEach } from "vitest"; const getFullListUsersMock = vi.fn(); const getFullListThreadsMock = vi.fn(); const createThreadMock = vi.fn(); const filterMock = vi.fn((expr: string, params: Record) => { let out = expr; for (const [k, v] of Object.entries(params)) out = out.replace(`{:${k}}`, String(v)); return out; }); vi.mock("@/lib/pb", () => ({ pbAdmin: vi.fn(async () => ({ filter: filterMock, collection: (name: string) => { if (name === "users") return { getFullList: getFullListUsersMock }; if (name === "ask_threads") { return { getFullList: getFullListThreadsMock, create: createThreadMock }; } throw new Error(`unexpected collection in test: ${name}`); }, })), })); import { GET, POST } from "./route"; function req(method: string, headers: Record = {}, body?: unknown): Request { return new Request("http://x/api/chat/threads", { method, headers, ...(body !== undefined ? { body: JSON.stringify(body) } : {}), }); } describe("/api/chat/threads", () => { beforeEach(() => { getFullListUsersMock.mockReset(); getFullListThreadsMock.mockReset(); createThreadMock.mockReset(); getFullListUsersMock.mockResolvedValue([{ id: "u1", name: "Dashboard" }]); }); it("GET requires a named admin session", async () => { vi.mocked(getCurrentUser).mockResolvedValueOnce(null); const res = await GET(req("GET")); expect(res.status).toBe(403); }); it("GET lists the actor's threads newest first", async () => { getFullListThreadsMock.mockResolvedValue([{ id: "t1", title: "Hi" }]); const res = await GET(req("GET", { "x-ask-user": "u1" })); expect(await res.json()).toEqual({ threads: [{ id: "t1", title: "Hi" }] }); expect(getFullListThreadsMock.mock.calls[0][0]).toMatchObject({ filter: "owner = u1", sort: "-last_message_at,-created", }); }); it("POST creates a thread owned by the actor", async () => { createThreadMock.mockResolvedValue({ id: "t9", title: "New thread" }); const res = await POST(req("POST", { "x-ask-user": "u1" })); expect(await res.json()).toEqual({ id: "t9", title: "New thread" }); expect(createThreadMock.mock.calls[0][0]).toMatchObject({ owner: "u1", archived: false }); }); it("POST uses a supplied title", async () => { createThreadMock.mockResolvedValue({ id: "t9", title: "Fuel report" }); const res = await POST(req("POST", { "x-ask-user": "u1" }, { title: "Fuel report" })); expect((await res.json()).title).toBe("Fuel report"); }); });