import { describe, expect, test } from "bun:test"; import { cdnImageResponse } from "@/lib/cdn-response"; import { MAX_FORM_ANSWER_IMAGE_BYTES, validateImageUploadFile, } from "@/lib/cdn-images"; function fileLike( overrides: Partial> = {} ): Pick { return { name: "answer.png", type: "image/png", size: 1024, ...overrides, }; } describe("form answer image uploads", () => { test("accepts supported images", () => { expect(() => validateImageUploadFile(fileLike())).not.toThrow(); }); test("rejects non-images, invalid extensions, and over-50MB files", () => { expect(() => validateImageUploadFile(fileLike({ type: "text/plain", name: "answer.txt" })) ).toThrow("Only PNG, JPG, WebP, and GIF images are allowed"); expect(() => validateImageUploadFile(fileLike({ name: "answer.svg" })) ).toThrow("Invalid image extension"); expect(() => validateImageUploadFile(fileLike({ size: MAX_FORM_ANSWER_IMAGE_BYTES + 1 })) ).toThrow("Image must be 50MB or smaller"); }); }); describe("CDN image responses", () => { test("returns stored bytes with immutable image headers", async () => { const response = cdnImageResponse({ data: Buffer.from([1, 2, 3]), type: "image/png", size: 3, }); expect(response.headers.get("Content-Type")).toBe("image/png"); expect(response.headers.get("Content-Length")).toBe("3"); expect(response.headers.get("Cache-Control")).toBe( "public, max-age=31536000, immutable" ); expect(response.headers.get("X-Content-Type-Options")).toBe("nosniff"); expect([...new Uint8Array(await response.arrayBuffer())]).toEqual([1, 2, 3]); }); });