// @vitest-environment jsdom // // The log console's query strings. The console's DOM tests mock this slice, so nothing else in the // suite looks at the URL that goes out — and a multi-level group is the case that breaks quietly: // `levels` must repeat, or FastAPI's list reads only the last one. import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { adminApi } from "./admin"; const fetchMock = vi.fn(); beforeEach(() => { fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200, headers: new Headers({ "content-type": "application/json" }), json: async () => ({}), text: async () => "{}", }); vi.stubGlobal("fetch", fetchMock); }); afterEach(() => vi.unstubAllGlobals()); const lastQuery = (): URLSearchParams => { const calls = fetchMock.mock.calls; return new URL(String(calls[calls.length - 1]?.[0]), "http://x").searchParams; }; describe("adminApi log query strings", () => { it("repeats the list filters and sends every single one it is given", async () => { await adminApi.adminLogs( { levels: ["ERROR", "CRITICAL"], sources: ["api", "worker"], user: "none", event: "sync.rss.failed", request_id: "req-abcdef12", job_id: 42, q: "100% done", since: "2026-09-19T11:00:00.000Z", }, "cursor-1", ); const p = lastQuery(); expect(p.getAll("levels")).toEqual(["ERROR", "CRITICAL"]); expect(p.getAll("sources")).toEqual(["api", "worker"]); expect(Object.fromEntries([...p].filter(([k]) => k !== "levels" && k !== "sources"))).toEqual({ user: "none", event: "sync.rss.failed", request_id: "req-abcdef12", job_id: "42", q: "100% done", since: "2026-09-19T11:00:00.000Z", before: "cursor-1", }); }); it("leaves out what is not set, and the facets carry no cursor", async () => { await adminApi.adminLogs({ q: "", user: undefined }, null); expect(String(fetchMock.mock.calls[0]?.[0])).toBe("/api/admin/logs"); await adminApi.adminLogFacets({ levels: ["WARNING"], since: "2026-09-19T11:00:00.000Z" }); expect([...lastQuery().keys()]).toEqual(["levels", "since"]); }); });