import { expect, test } from "@playwright/test"; // The exact figure that regressed in production: the game client appends a // trailing `.` segment that the renderer ignores, but the previous // validation regex rejected with a 400. const FIGURE = "hr-11782-40-40.hd-180-7-14.ch-11592-66.lg-10726-79-1408.sh-11764-1408.ha-11958-70-1408.wa-2007-0.0"; const avatarPath = (params: Record = {}) => `/api/imaging/avatar?${new URLSearchParams({ figure: FIGURE, ...params })}`; function countBytes(haystack: Buffer, needle: Buffer): number { let count = 0; for ( let index = haystack.indexOf(needle); index !== -1; index = haystack.indexOf(needle, index + needle.length) ) { count += 1; } return count; } test("renders an animated APNG for a figure with an effect", async ({ request, }) => { const response = await request.get( avatarPath({ img_format: "apng", effect: "14" }), ); expect(response.status()).toBe(200); expect(response.headers()["content-type"]).toContain("image/"); // `unavailable` means the placeholder was served, i.e. no real render. expect(response.headers()["x-imager-source"]).not.toBe("unavailable"); const body = await response.body(); expect(body.length).toBeGreaterThan(1000); // APNG signature chunks: `acTL` announces the animation, `fcTL` marks frames. expect(body.includes(Buffer.from("acTL"))).toBe(true); expect(countBytes(body, Buffer.from("fcTL"))).toBeGreaterThan(1); }); test("serves a static PNG when no animation is requested", async ({ request, }) => { const response = await request.get(avatarPath({ img_format: "png" })); expect(response.status()).toBe(200); expect(response.headers()["content-type"]).toContain("image/png"); const body = await response.body(); expect(body.subarray(1, 4).toString("ascii")).toBe("PNG"); }); test("answers conditional requests with 304", async ({ request }) => { const first = await request.get(avatarPath({ img_format: "png" })); expect(first.status()).toBe(200); const etag = first.headers()["etag"]; expect(etag).toBeTruthy(); const second = await request.get(avatarPath({ img_format: "png" }), { headers: { "if-none-match": etag as string }, }); expect(second.status()).toBe(304); expect(second.headers()["etag"]).toBe(etag); }); test("rejects a malformed figure with 400", async ({ request }) => { const response = await request.get(avatarPath({ figure: "../bad" })); expect(response.status()).toBe(400); }); test("the default /imaging endpoint serves a PNG", async ({ request }) => { const response = await request.get( `/imaging?${new URLSearchParams({ figure: FIGURE, img_format: "png" })}`, ); expect(response.status()).toBe(200); expect(response.headers()["content-type"]).toContain("image/png"); }); test("the badge endpoint serves an image and revalidates", async ({ request, }) => { const first = await request.get("/api/imaging/badge?code=ADM"); expect(first.status()).toBe(200); expect(first.headers()["content-type"]).toContain("image/"); const etag = first.headers()["etag"]; expect(etag).toBeTruthy(); const second = await request.get("/api/imaging/badge?code=ADM", { headers: { "if-none-match": etag as string }, }); expect(second.status()).toBe(304); });