server.test.ts

1.7 KB · raw

1import { expect, test } from "bun:test";2import { createApp } from "../src/server/app.ts";3import type { Config } from "../src/server/config.ts";45const config: Config = {6	domain: "kepr.example",7	dataDir: "data",8	adminPasswordHash: "$argon2id$x",9	bucket: {10		kind: "s3",11		endpoint: "https://s3.fr-par.scw.cloud",12		name: "koh",13		region: "fr-par",14		accessKeyId: "read",15		secretAccessKey: "only",16	},17};1819test("every route the app registers is listed in docs/routes.txt", async () => {20	const listed = new Set(21		(await Bun.file("docs/routes.txt").text())22			.split("\n")23			.filter((line) => line.trim() !== "" && !line.startsWith("#")),24	);25	const registered = createApp(config)26		.routes.filter((route) => !(route.method === "ALL" && route.path === "/*"))27		.map((route) => `${route.method} ${route.path}`);28	expect(registered.filter((route) => !listed.has(route))).toEqual([]);29});3031test("responses carry the §25 content security policy", async () => {32	const response = await createApp(config).request("/");33	const csp = response.headers.get("content-security-policy") ?? "";34	expect(csp).toContain("script-src 'self'");35	expect(csp).not.toContain("unsafe-inline");36	expect(csp).toContain("img-src 'self' https://s3.fr-par.scw.cloud");37	expect(csp).toContain("frame-ancestors 'none'");38	expect(response.headers.get("x-content-type-options")).toBe("nosniff");39});4041test("request bodies over 64 KB are refused", async () => {42	const app = createApp(config);43	app.post("/echo", async (c) => c.text(String((await c.req.text()).length)));44	const post = (bytes: number) => app.request("/echo", { method: "POST", body: "x".repeat(bytes) });45	expect((await post(64 * 1024)).status).toBe(200);46	expect((await post(64 * 1024 + 1)).status).toBe(413);47});