navbar.test.ts

3.0 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. Notifications load separately.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		addEventListener: () => {},18		querySelector: () => ({19			parentElement: { after: () => {} },20			replaceWith: (...replaced: unknown[]) => {21				replacement = replaced;22			},23		}),24		createElement: (tag: string) => {25			const node: Record<string, unknown> = {26				tag,27				setAttribute: (name: string, value: string) => {28					node[name] = value;29				},30				addEventListener: () => {},31				replaceChildren: () => {},32				append: (...children: unknown[]) => {33					node.children = children;34				},35			};36			nodes.push(node);37			return node;38		},39	};40	runInNewContext(script, {41		document,42		fetch: async () => ({ ok: true, json: async () => ({ unread: 0, notifications: [] }) }),43	});44	return { nodes, replacement };45}4647describe("the signed-in navbar", () => {48	test("stays as it is without a mark carrying a form token", () => {49		for (const cookie of ["", "kepr_editor=1", `kepr_editor=${TOKEN.slice(1)}`]) {50			expect(run(cookie).replacement).toEqual([]);51		}52	});5354	test("offers admin and a log out form posting the mark's token", () => {55		const { nodes, replacement } = run(`theme=dark; kepr_editor=${TOKEN}`);56		const [admin, form] = replacement as Record<string, unknown>[];57		expect(admin).toMatchObject({ tag: "a", href: "/admin", textContent: "admin" });58		expect(form).toMatchObject({ tag: "form", method: "post", action: "/admin/sign-out" });59		const [field, button] = (form?.children ?? []) as Record<string, unknown>[];60		expect(field).toMatchObject({ tag: "input", type: "hidden", name: "form", value: TOKEN });61		expect(button).toMatchObject({ tag: "button", type: "submit", textContent: "log out" });62		expect(nodes.find((node) => node.tag === "summary")).toMatchObject({63			"aria-label": "notifications",64		});65	});6667	test("the mark's token is the one log out needs", async () => {68		const repos = await makeRepos(["app"]);69		const browser = new Browser((await instance(repos.bucketDir)).app);70		await browser.signIn();71		const mark = browser.cookies.get("kepr_editor") ?? "";72		expect(mark).toMatch(/^[0-9a-f]{64}$/);73		// A mark from before it carried the token is brought up to date by any admin page.74		browser.cookies.set("kepr_editor", "1");75		await browser.get("/admin");76		expect(browser.cookies.get("kepr_editor")).toBe(mark);77		expect((await browser.post("/admin/sign-out", { form: mark })).status).toBe(303);78		expect((await browser.get("/admin")).status).toBe(401);79	});80});