import { env } from "cloudflare:workers"; import { afterEach, describe, expect, it, vi } from "vitest"; import worker, { type WebAppInit } from "../src/index.js"; type TestEnv = { WEBAPP_DO: DurableObjectNamespace; MAP_STORE_DO: DurableObjectNamespace; }; const testEnv = env as unknown as TestEnv; const URL_ = "https://site.example/app/export/7/data"; type Seen = { url: string; redirect?: string; contentType: string | null; form: Record }; /** each outbound fetch, its form fields read back; answers with `res()` */ function spyForms(res: () => Response): Seen[] { const seen: Seen[] = []; vi.spyOn(globalThis, "fetch").mockImplementation(async (input, init) => { const req = new Request(input as string, init as RequestInit); const form = Object.fromEntries([...(await req.formData()).entries()].map(([k, v]) => [k, String(v)])); seen.push({ url: req.url, redirect: init?.redirect, contentType: req.headers.get("content-type"), form }); return res(); }); return seen; } afterEach(() => { vi.restoreAllMocks(); }); const mint = async (init: WebAppInit) => { const res = await worker.fetch( new Request("https://webapp.example/", { method: "POST", body: JSON.stringify(init), headers: { "content-type": "application/json" }, }), testEnv, ); const { id, storeId } = (await res.json()) as { id: string; storeId: string }; return { id, storeId, instance: testEnv.WEBAPP_DO.get(testEnv.WEBAPP_DO.idFromString(id)) }; }; /** the failure of a call: what it threw; "" if it succeeds */ async function errorOf(p: Promise): Promise { try { await p; return ""; } catch (err) { return String(err); } } describe("postForm", () => { it("echoes a cookie from the header store into a form field; the holder never sees it", async () => { const seen = spyForms( () => new Response("col1,col2", { headers: { "content-type": "text/csv", "content-disposition": 'attachment;filename="x.csv"', "set-cookie": "sess=next; HttpOnly", }, }), ); const { instance } = await mint({ url: URL_, headers: { cookie: "a=1; tok=s3cret; b=2" } }); using app = await instance.handle(); const reply = await app.query({ since: "2026-07-13\x1f" }).postForm({ kind: "all" }, { csrf: "tok" }); expect(seen).toEqual([ { url: `${URL_}?since=2026-07-13%1F`, redirect: "manual", contentType: expect.stringMatching(/^multipart\/form-data; boundary=/), form: { kind: "all", csrf: "s3cret" }, }, ]); expect(reply).toEqual({ status: 200, contentType: "text/csv", contentDisposition: 'attachment;filename="x.csv"', body: new TextEncoder().encode("col1,col2"), }); }); it("does not follow a redirect: the 3xx comes back, location query-stripped", async () => { spyForms(() => new Response(null, { status: 302, headers: { location: "/login?next=s3cret#x" } })); const { instance } = await mint({ url: URL_, headers: { cookie: "tok=t" } }); using app = await instance.handle(); const reply = await app.postForm({}, { csrf: "tok" }); expect(reply).toEqual({ status: 302, contentType: "", location: "https://site.example/login", body: new Uint8Array() }); }); it("refuses, naming no values: a missing cookie, a field set twice, a content-type header", async () => { spyForms(() => new Response("ok")); const { instance } = await mint({ url: URL_, headers: { cookie: "tok=s3cret" } }); using app = await instance.handle(); expect(await errorOf(app.postForm({}, { csrf: "nope" }))).toMatch(/no nope cookie to echo/); const twice = await errorOf(app.postForm({ csrf: "mine" }, { csrf: "tok" })); expect(twice).toMatch(/contradicts on csrf/); expect(twice).not.toMatch(/s3cret|mine/); const typed = app.withHeader("content-type", "text/plain"); expect(await errorOf(typed.postForm())).toMatch(/content-type is set by the form/); }); it("rotating the store's cookie changes what is echoed", async () => { const seen = spyForms(() => new Response("ok")); const { storeId, instance } = await mint({ url: URL_, headers: { cookie: "tok=one" } }); using app = await instance.handle(); await app.postForm({}, { csrf: "tok" }); await worker.fetch( new Request(`https://webapp.example/store/${storeId}/cookie`, { method: "PUT", body: JSON.stringify("tok=two") }), testEnv, ); await app.postForm({}, { csrf: "tok" }); expect(seen.map((s) => s.form.csrf)).toEqual(["one", "two"]); }); });