WFDASH-WEBAPP/src/lib/quote-assistant-counts-client.test.ts
Dave fa854060c4 feat(quote-assistant): AI x/y badge on quotes board
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:01:43 +02:00

70 lines
2.4 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@/lib/pocketbase", () => ({
default: () => ({ authStore: { token: "tok-123" } }),
}));
import { fetchAiCounts } from "./quote-assistant-counts-client";
function jsonResponse(body: unknown, status = 200): Response {
return new Response(JSON.stringify(body), {
status,
headers: { "content-type": "application/json" },
});
}
describe("fetchAiCounts", () => {
const fetchMock = vi.fn();
beforeEach(() => {
fetchMock.mockReset();
vi.stubGlobal("fetch", fetchMock);
});
afterEach(() => {
vi.unstubAllGlobals();
});
it("returns {} for no ids without calling fetch", async () => {
expect(await fetchAiCounts([])).toEqual({});
expect(fetchMock).not.toHaveBeenCalled();
});
it("calls the counts route with the ids and a Bearer token", async () => {
fetchMock.mockResolvedValueOnce(jsonResponse({ a: { pending: 2, total: 5 } }));
const out = await fetchAiCounts(["a", "b"]);
expect(out).toEqual({ a: { pending: 2, total: 5 } });
const [url, init] = fetchMock.mock.calls[0];
expect(url).toBe("/api/v1/quotes/assistant/counts?ids=a%2Cb");
expect(init.headers.Authorization).toBe("Bearer tok-123");
});
it("splits more than 500 ids into chunks and merges the results", async () => {
const ids = Array.from({ length: 1001 }, (_, i) => `q${i}`);
fetchMock.mockImplementation(async (url: string) => {
const list = (new URL(url, "http://x").searchParams.get("ids") ?? "").split(",");
return jsonResponse({ [list[0]]: { pending: 1, total: list.length } });
});
const out = await fetchAiCounts(ids);
expect(fetchMock).toHaveBeenCalledTimes(3);
expect(out).toEqual({
q0: { pending: 1, total: 500 },
q500: { pending: 1, total: 500 },
q1000: { pending: 1, total: 1 },
});
});
it("returns {} on a non-ok response", async () => {
fetchMock.mockResolvedValueOnce(jsonResponse({ error: "nope" }, 500));
expect(await fetchAiCounts(["a"])).toEqual({});
});
it("returns {} when fetch throws", async () => {
fetchMock.mockRejectedValueOnce(new Error("network"));
expect(await fetchAiCounts(["a"])).toEqual({});
});
it("returns {} when the body is not an object", async () => {
fetchMock.mockResolvedValueOnce(jsonResponse(null));
expect(await fetchAiCounts(["a"])).toEqual({});
});
});