54 lines
1.7 KiB
TypeScript
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]);
|
|
});
|
|
});
|