navbar.test.ts

2.6 KB · raw

1// Covers the signed-in navbar (nav.js): "admin" and "log out" in place of "log in", built from2// the readable mark signing in sets beside the session, with no request.34import { 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		querySelector: () => ({18			replaceWith: (...replaced: unknown[]) => {19				replacement = replaced;20			},21		}),22		createElement: (tag: string) => {23			const node: Record<string, unknown> = {24				tag,25				append: (...children: unknown[]) => {26					node.children = children;27				},28			};29			nodes.push(node);30			return node;31		},32	};33	runInNewContext(script, { document });34	return { nodes, replacement };35}3637describe("the signed-in navbar", () => {38	test("stays as it is without a mark carrying a form token", () => {39		for (const cookie of ["", "kepr_editor=1", `kepr_editor=${TOKEN.slice(1)}`]) {40			expect(run(cookie).replacement).toEqual([]);41		}42	});4344	test("offers admin and a log out form posting the mark's token", () => {45		const { nodes, replacement } = run(`theme=dark; kepr_editor=${TOKEN}`);46		const [admin, form] = replacement as Record<string, unknown>[];47		expect(admin).toMatchObject({ tag: "a", href: "/admin", textContent: "admin" });48		expect(form).toMatchObject({ tag: "form", method: "post", action: "/admin/sign-out" });49		const [field, button] = (form?.children ?? []) as Record<string, unknown>[];50		expect(field).toMatchObject({ tag: "input", type: "hidden", name: "form", value: TOKEN });51		expect(button).toMatchObject({ tag: "button", type: "submit", textContent: "log out" });52		expect(nodes).toHaveLength(4);53	});5455	test("the mark's token is the one log out needs", async () => {56		const repos = await makeRepos(["app"]);57		const browser = new Browser((await instance(repos.bucketDir)).app);58		await browser.signIn();59		const mark = browser.cookies.get("kepr_editor") ?? "";60		expect(mark).toMatch(/^[0-9a-f]{64}$/);61		// A mark from before it carried the token is brought up to date by any admin page.62		browser.cookies.set("kepr_editor", "1");63		await browser.get("/admin");64		expect(browser.cookies.get("kepr_editor")).toBe(mark);65		expect((await browser.post("/admin/sign-out", { form: mark })).status).toBe(303);66		expect((await browser.get("/admin")).status).toBe(401);67	});68});