server.test.ts

1.8 KB · raw

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