1234import { describe, expect, test } from "bun:test";5import { runInNewContext } from "node:vm";6import { Browser, instance } from "./browser.ts";7import { makeRepos } from "./fixture.ts";89const script = await Bun.file(new URL("../public/js/nav.js", import.meta.url)).text();10const TOKEN = "ab".repeat(32);1112function run(cookie: string) {13 const nodes: Record<string, unknown>[] = [];14 let replacement: unknown[] = [];15 const document = {16 cookie,17 documentElement: { classList: { add: () => {} } },18 addEventListener: () => {},19 querySelector: () => ({20 parentElement: { after: () => {} },21 replaceWith: (...replaced: unknown[]) => {22 replacement = replaced;23 },24 }),25 createElement: (tag: string) => {26 const node: Record<string, unknown> = {27 tag,28 setAttribute: (name: string, value: string) => {29 node[name] = value;30 },31 addEventListener: () => {},32 replaceChildren: () => {},33 append: (...children: unknown[]) => {34 node.children = children;35 },36 };37 nodes.push(node);38 return node;39 },40 };41 runInNewContext(script, {42 document,43 window: { addEventListener: () => {} },44 fetch: async () => ({ ok: true, json: async () => ({ unread: 0, notifications: [] }) }),45 });46 return { nodes, replacement };47}4849describe("the signed-in navbar", () => {50 test("stays as it is without a mark carrying a form token", () => {51 for (const cookie of ["", "kepr_editor=1", `kepr_editor=${TOKEN.slice(1)}`]) {52 expect(run(cookie).replacement).toEqual([]);53 }54 });5556 test("offers admin and a log out form posting the mark's token", () => {57 const { nodes, replacement } = run(`theme=dark; kepr_editor=${TOKEN}`);58 const [admin, form] = replacement as Record<string, unknown>[];59 expect(admin).toMatchObject({ tag: "a", href: "/admin", textContent: "admin" });60 expect(form).toMatchObject({ tag: "form", method: "post", action: "/admin/sign-out" });61 const [field, button] = (form?.children ?? []) as Record<string, unknown>[];62 expect(field).toMatchObject({ tag: "input", type: "hidden", name: "form", value: TOKEN });63 expect(button).toMatchObject({ tag: "button", type: "submit", textContent: "log out" });64 expect(nodes.find((node) => node.tag === "summary")).toMatchObject({65 "aria-label": "notifications",66 });67 });6869 test("the mark's token is the one log out needs", async () => {70 const repos = await makeRepos(["app"]);71 const browser = new Browser((await instance(repos.bucketDir)).app);72 await browser.signIn();73 const mark = browser.cookies.get("kepr_editor") ?? "";74 expect(mark).toMatch(/^[0-9a-f]{64}$/);75 76 browser.cookies.set("kepr_editor", "1");77 await browser.get("/admin");78 expect(browser.cookies.get("kepr_editor")).toBe(mark);79 expect((await browser.post("/admin/sign-out", { form: mark })).status).toBe(303);80 expect((await browser.get("/admin")).status).toBe(401);81 });82});