import { expect, test } from "bun:test"; import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; process.env.FORGE_APP_DATA = mkdtempSync(join(tmpdir(), "app-")); process.env.PORT = "0"; const { server } = await import("./server.ts"); const base = `http://${server.hostname}:${server.port}`; test("serves the page", async () => { const response = await fetch(base + "/"); expect(response.status).toBe(200); expect(await response.text()).toContain("

"); }); test("keeps a note", async () => { const form = new FormData(); form.set("body", "hello from a test"); const posted = await fetch(base + "/notes", { method: "POST", body: form, redirect: "manual" }); expect(posted.status).toBe(303); expect(await (await fetch(base + "/")).text()).toContain("hello from a test"); }); test("stands on the security floor", async () => { const response = await fetch(base + "/"); expect(response.headers.get("content-security-policy")).toContain("default-src 'self'"); expect(response.headers.get("x-content-type-options")).toBe("nosniff"); }); test("a bug answers with the floor, not the runtime's page", async () => { // A percent-escape that is not one makes the search params throw. const response = await fetch(base + "/notes", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: "body=%E0%A4%A", }); expect(response.status).toBe(200); expect(response.headers.get("content-security-policy")).toContain("default-src 'self'"); }); test("a body is capped by the bytes read, whatever it claims", async () => { // The cap counts bytes as they arrive and never reads Content-Length, so // a chunked body with no length is refused the same way this one is. const response = await fetch(base + "/notes", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: "body=" + "x".repeat(1024 * 1024), }); expect(response.status).toBe(413); }); test("HEAD sees the app up", async () => { const response = await server.fetch(new Request(base + "/", { method: "HEAD" })); expect(response.status).toBe(200); expect(await response.text()).toBe(""); }); test("refuses a cross-site post", async () => { const form = new FormData(); form.set("body", "from another site"); const posted = await fetch(base + "/notes", { method: "POST", body: form, redirect: "manual", headers: { origin: "https://evil.example", "sec-fetch-site": "cross-site" }, }); expect(posted.status).toBe(403); expect(await (await fetch(base + "/")).text()).not.toContain("from another site"); });