fabro/apps/fabro-web/app/api.test.ts
Bryan Helmkamp cfd0005319
fix(web): handle 404 and 501 gracefully in API loaders
Demo mode returns 404 for unimplemented endpoints instead of 501.
Rename isNotImplemented to isNotAvailable covering both status codes,
and use apiJsonOrNull in workflow-runs loader.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 07:54:11 -04:00

63 lines
1.8 KiB
TypeScript

import { afterEach, describe, expect, mock, test } from "bun:test";
import { getAuthConfig, isNotAvailable, loginDevToken } from "./api";
afterEach(() => {
mock.restore();
});
describe("isNotAvailable", () => {
test("returns true for 501 status", () => {
expect(isNotAvailable(501)).toBe(true);
});
test("returns true for 404 status", () => {
expect(isNotAvailable(404)).toBe(true);
});
test("returns false for 200 status", () => {
expect(isNotAvailable(200)).toBe(false);
});
});
describe("auth helpers", () => {
test("getAuthConfig fetches auth methods without triggering auth redirect behavior", async () => {
const fetchMock = mock(() =>
Promise.resolve(
new Response(JSON.stringify({ methods: ["dev-token"] }), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
),
);
globalThis.fetch = fetchMock as typeof fetch;
const result = await getAuthConfig();
expect(result).toEqual({ methods: ["dev-token"] });
expect(fetchMock).toHaveBeenCalledWith("/api/v1/auth/config", {
credentials: "include",
});
});
test("loginDevToken posts the token payload", async () => {
const fetchMock = mock(() =>
Promise.resolve(
new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
),
);
globalThis.fetch = fetchMock as typeof fetch;
const result = await loginDevToken("fabro_dev_token");
expect(result).toEqual({ ok: true });
expect(fetchMock).toHaveBeenCalledWith("/auth/login/dev-token", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: "fabro_dev_token" }),
});
});
});