fabro/apps/fabro-web/app/api-client.test.ts
Bryan Helmkamp 3a6ec9b9ef Rename Arc to Fabro in TypeScript/JavaScript
Rename directories (arc-web → fabro-web, arc-api-client → fabro-api-client),
update package names, import paths, TS-only identifiers (theme key, session
cookie, demo cookie, OAuth state, db filename, mock data), and supporting
files (Dockerfile, docker-compose, entrypoint, CI workflow, CLAUDE.md).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:13:18 -04:00

60 lines
1.7 KiB
TypeScript

import { describe, test, expect, beforeEach, mock } from "bun:test";
import { apiJson } from "./api-client";
const originalFetch = globalThis.fetch;
beforeEach(() => {
globalThis.fetch = originalFetch;
});
describe("apiJson", () => {
test("returns parsed JSON on 200", async () => {
globalThis.fetch = mock(() =>
Promise.resolve(new Response(JSON.stringify({ id: 1, name: "test" }), {
status: 200,
headers: { "Content-Type": "application/json" },
}))
);
const result = await apiJson<{ id: number; name: string }>("/items/1");
expect(result).toEqual({ id: 1, name: "test" });
});
test("throws Response with status 404 and null body on not found", async () => {
globalThis.fetch = mock(() =>
Promise.resolve(new Response("Not Found: /items/999", { status: 404 }))
);
try {
await apiJson("/items/999");
expect.unreachable("should have thrown");
} catch (thrown) {
expect(thrown).toBeInstanceOf(Response);
const res = thrown as Response;
expect(res.status).toBe(404);
expect(res.body).toBeNull();
}
});
test("throws Response with status 500 and null body, stripping sensitive details", async () => {
globalThis.fetch = mock(() =>
Promise.resolve(
new Response(
"Internal error: database connection string is postgres://admin:secret@db.internal:5432/prod",
{ status: 500 }
)
)
);
try {
await apiJson("/items/1");
expect.unreachable("should have thrown");
} catch (thrown) {
expect(thrown).toBeInstanceOf(Response);
const res = thrown as Response;
expect(res.status).toBe(500);
expect(res.body).toBeNull();
}
});
});