import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; const origin = "https://pad.example"; let currentUrl; let historyCall; let dispatchedEvent; globalThis.CustomEvent = class CustomEvent { constructor(type, init = {}) { this.type = type; this.detail = init.detail; } }; globalThis.window = { location: null, history: { pushState(state, _title, url) { historyCall = { method: "pushState", state }; setLocation(url); }, replaceState(state, _title, url) { historyCall = { method: "replaceState", state }; setLocation(url); }, }, dispatchEvent(event) { dispatchedEvent = event; }, }; function setLocation(value) { currentUrl = new URL(value, origin); window.location = { get href() { return currentUrl.href; }, get search() { return currentUrl.search; }, }; } function resetWindow(value) { setLocation(value); historyCall = undefined; dispatchedEvent = undefined; } const source = await readFile(new URL("../static/js/url-state.js", import.meta.url), "utf8"); const moduleUrl = `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`; const { currentShareUrl, readEditorState, writeEditorState } = await import(moduleUrl); test("editor state reads supported values", () => { resetWindow("/w/demo/n/note?view=preview&mode=text"); assert.deepEqual(readEditorState(), { view: "preview", mode: "text" }); }); test("editor state rejects unsupported values", () => { resetWindow("/w/demo/n/note?view=invalid&mode=html"); assert.deepEqual(readEditorState(), { view: "split", mode: "markdown" }); }); test("writing editor state preserves unrelated query and hash", () => { resetWindow("/w/demo/n/note?filter=recent#section"); const result = new URL(writeEditorState({ view: "edit", mode: "text" })); assert.equal(result.searchParams.get("filter"), "recent"); assert.equal(result.searchParams.get("view"), "edit"); assert.equal(result.searchParams.get("mode"), "text"); assert.equal(result.hash, "#section"); assert.equal(historyCall.method, "pushState"); assert.deepEqual(historyCall.state, { view: "edit", mode: "text" }); assert.equal(dispatchedEvent.type, "rustpad:urlchange"); }); test("replace mode uses replaceState", () => { resetWindow("/p/demo"); writeEditorState({ view: "split", mode: "markdown" }, { replace: true }); assert.equal(historyCall.method, "replaceState"); }); test("current share URL adds view state without inventing access tokens", () => { resetWindow("/w/demo/n/note?filter=recent#section"); const result = new URL(currentShareUrl({ view: "preview", mode: "markdown" })); assert.equal(result.searchParams.get("filter"), "recent"); assert.equal(result.searchParams.get("view"), "preview"); assert.equal(result.searchParams.get("mode"), "markdown"); assert.equal(result.searchParams.has("share"), false); assert.equal(result.hash, "#section"); });