import { describe, expect, it, vi } from "vitest"; async function loadApi(apiUrl = "") { vi.resetModules(); vi.stubEnv("VITE_API_URL", apiUrl); vi.stubEnv("VITE_API_PREFIX", ""); return import("./api"); } function jsonResponse(body: unknown, init?: ResponseInit) { return new Response(JSON.stringify(body), { status: 200, headers: { "Content-Type": "application/json" }, ...init, }); } describe("api helpers", () => { it("normalizes nullish API arrays", async () => { const { itemsOrEmpty } = await loadApi(); expect(itemsOrEmpty(null)).toEqual([]); expect(itemsOrEmpty(undefined)).toEqual([]); expect(itemsOrEmpty(["a"])).toEqual(["a"]); }); it("builds asset URLs from API base while preserving absolute URLs", async () => { const { assetUrl } = await loadApi("https://api.example.com"); expect(assetUrl("/uploads/file.png")).toBe( "https://api.example.com/uploads/file.png", ); expect(assetUrl("https://cdn.example.com/file.png")).toBe( "https://cdn.example.com/file.png", ); expect(assetUrl(undefined)).toBe(""); }); it("fetches JSON with API base and throws response text on failure", async () => { const { getJSON } = await loadApi("https://api.example.com"); const fetchMock = vi .fn() .mockResolvedValueOnce(jsonResponse({ ok: true })) .mockResolvedValueOnce(new Response("boom", { status: 500 })); vi.stubGlobal("fetch", fetchMock); await expect(getJSON("/api/resources")).resolves.toEqual({ ok: true }); expect(fetchMock).toHaveBeenCalledWith( "https://api.example.com/api/resources", ); await expect(getJSON("/api/fail")).rejects.toThrow("boom"); }); it("posts JSON with optional bearer token", async () => { const { postJSON } = await loadApi(); const fetchMock = vi.fn().mockResolvedValue(jsonResponse({ id: 1 })); vi.stubGlobal("fetch", fetchMock); await expect( postJSON("/api/admin/resources", { title: "Demo" }, "token-123"), ).resolves.toEqual({ id: 1 }); expect(fetchMock).toHaveBeenCalledWith("/api/admin/resources", { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer token-123", }, body: JSON.stringify({ title: "Demo" }), }); }); });