Files
buzz/app/api/card/[sub]/handler.test.ts
T

96 lines
3.5 KiB
TypeScript

import { describe, expect, mock, test } from "bun:test";
import {
type CardCharacter,
type CardSubmission,
createCardHandler,
} from "./handler";
const context = (sub: string) => ({ params: Promise.resolve({ sub }) });
const request = new Request("https://buzz.test/api/card/sub-1");
function dependencies() {
return {
findSubmission: mock(
async (_id: string): Promise<CardSubmission | undefined> => ({
uid: "800000001",
char: "Furina",
}),
),
findImage: mock(
async (_id: string): Promise<Uint8Array<ArrayBuffer> | undefined> =>
undefined,
),
findCharacter: mock(
async (_name: string): Promise<CardCharacter | undefined> => ({
amber: "10000089-Furina",
}),
),
fetch: mock(
async (_input: RequestInfo | URL, _init?: RequestInit) =>
new Response(new Uint8Array([4, 5, 6])),
),
persistImage: mock(async (_id: string, _image: ArrayBuffer) => {}),
after: mock((task: () => Promise<void>) => void task()),
};
}
describe("card handler", () => {
test("returns a cached card without querying character services", async () => {
const deps = dependencies();
deps.findImage.mockResolvedValue(new Uint8Array([1, 2, 3]));
const response = await createCardHandler(deps)(request, context("cached"));
expect(new Uint8Array(await response.arrayBuffer())).toEqual(
new Uint8Array([1, 2, 3]),
);
expect(deps.findCharacter).not.toHaveBeenCalled();
expect(deps.fetch).not.toHaveBeenCalled();
});
test("identifies an unknown submission by the requested id", async () => {
const deps = dependencies();
deps.findSubmission.mockResolvedValue(undefined);
const response = await createCardHandler(deps)(request, context("missing"));
expect(response.status).toBe(404);
expect(await response.text()).toBe("Unknown submission: missing");
});
test("rejects submissions without a character", async () => {
const deps = dependencies();
deps.findSubmission.mockResolvedValue({ uid: "1", char: null });
const response = await createCardHandler(deps)(request, context("generic"));
expect(response.status).toBe(422);
expect(deps.findCharacter).not.toHaveBeenCalled();
});
test("reports a missing character record", async () => {
const deps = dependencies();
deps.findCharacter.mockResolvedValue(undefined);
const response = await createCardHandler(deps)(request, context("sub-1"));
expect(response.status).toBe(500);
expect(await response.text()).toBe("Unknown character: Furina");
});
test("returns upstream errors unchanged", async () => {
const deps = dependencies();
deps.fetch.mockResolvedValue(new Response("busy", { status: 503 }));
const response = await createCardHandler(deps)(request, context("sub-1"));
expect(response.status).toBe(503);
expect(await response.text()).toBe("busy");
expect(deps.persistImage).not.toHaveBeenCalled();
});
test("fetches and schedules persistence of a fresh card", async () => {
const deps = dependencies();
const response = await createCardHandler(deps)(request, context("sub-1"));
expect(deps.fetch.mock.calls[0]?.[0]).toBe(
"https://api.astrxl.dev/v1/card/genshin/800000001/10000089?lang=th&substat=true&quality=true",
);
expect(new Uint8Array(await response.arrayBuffer())).toEqual(
new Uint8Array([4, 5, 6]),
);
expect(deps.after).toHaveBeenCalledTimes(1);
expect(deps.persistImage).toHaveBeenCalledTimes(1);
expect(deps.persistImage.mock.calls[0]?.[0]).toBe("sub-1");
});
});