Files
erika/lib/cdn-images.test.ts
T
2026-07-28 00:02:34 +07:00

54 lines
1.7 KiB
TypeScript

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<File, "name" | "type" | "size">> = {}
): Pick<File, "name" | "type" | "size"> {
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]);
});
});