import { test, expect, beforeEach } from "bun:test"; import { Window } from "happy-dom"; import { NAV_RUNTIME } from "../src/nav-runtime.ts"; let win: any; let fetchCalls: { url: string; opts: any }[]; let nextHtml: string; function install(bodyHtml: string): void { win = new Window({ url: "https://example.test/" }); win.document.body.innerHTML = bodyHtml; fetchCalls = []; nextHtml = ""; const g = globalThis as any; g.window = win; g.document = win.document; g.history = win.history; g.location = win.location; g.DOMParser = win.DOMParser; g.CustomEvent = win.CustomEvent; g.Event = win.Event; g.fetch = win.fetch = (url: string, opts: any) => { fetchCalls.push({ url, opts }); return Promise.resolve({ redirected: false, url, headers: { get: (k: string) => k.toLowerCase() === "content-type" ? "text/html; charset=utf-8" : null, }, text: () => Promise.resolve(nextHtml), }); }; (0, eval)(NAV_RUNTIME); } const flush = () => new Promise((r) => setTimeout(r, 0)); beforeEach(() => { const g = globalThis as any; for (const k of [ "window", "document", "history", "location", "DOMParser", "CustomEvent", "Event", "fetch", ]) { delete g[k]; } }); test("intercepts an internal link click and swaps #app in place", async () => { install(`

Home

About
`); nextHtml = `About` + `

About page

`; win.document.getElementById("lnk").click(); await flush(); expect(fetchCalls.length).toBe(1); expect(fetchCalls[0]!.url).toContain("/about"); expect(fetchCalls[0]!.opts.headers["x-wrnexus-nav"]).toBe("1"); expect(win.document.getElementById("app").innerHTML).toContain("About page"); expect(win.document.title).toBe("About"); }); test("prefetches focused routes once and reuses the document during navigation", async () => { install(`
About
`); nextHtml = `About` + `

Prefetched

`; const link = win.document.getElementById("prefetch"); link.dispatchEvent(new win.FocusEvent("focusin", { bubbles: true })); await flush(); expect(fetchCalls).toHaveLength(1); expect(fetchCalls[0]?.opts.headers["x-wrnexus-prefetch"]).toBe("1"); link.click(); await flush(); expect(fetchCalls).toHaveLength(1); expect(win.document.querySelector("h1")?.textContent).toBe("Prefetched"); }); test("does not prefetch links merely passing under the pointer while scrolling", async () => { install(`
About
`); const link = win.document.getElementById("prefetch"); link.dispatchEvent(new win.PointerEvent("pointerover", { bubbles: true })); await flush(); expect(fetchCalls).toHaveLength(0); link.dispatchEvent(new win.PointerEvent("pointerdown", { bubbles: true })); await flush(); expect(fetchCalls).toHaveLength(1); expect(fetchCalls[0]?.opts.headers["x-wrnexus-prefetch"]).toBe("1"); }); test("ignores cross-origin links (full navigation)", async () => { install(`
x
`); win.document.getElementById("lnk").click(); await flush(); expect(fetchCalls.length).toBe(0); }); test("ignores modified clicks so new-tab still works", async () => { install(`
x
`); const MouseEventConstructor = (win as unknown as { MouseEvent: typeof MouseEvent }).MouseEvent; win.document.getElementById("lnk").dispatchEvent( new MouseEventConstructor("click", { bubbles: true, cancelable: true, button: 0, metaKey: true, }), ); await flush(); expect(fetchCalls.length).toBe(0); }); test("exposes programmatic navigation", async () => { install(`

Home

`); nextHtml = `Dash

Dashboard

`; expect(typeof win.__wrnexusNavigate).toBe("function"); win.__wrnexusNavigate("/dashboard"); await flush(); expect(fetchCalls.length).toBe(1); expect(win.document.getElementById("app").innerHTML).toContain("Dashboard"); }); test("rebinds theme controls after swapping the page", async () => { install(`
About
`); let boundRoot: unknown; win.wrnTheme = { bind: (root: unknown) => (boundRoot = root) }; nextHtml = `
`; win.document.getElementById("lnk").click(); await flush(); expect(boundRoot).toBe(win.document); expect(win.document.querySelector("[data-wrn-theme-toggle]")).not.toBeNull(); }); test("synchronizes and rebinds i18n data during client navigation", async () => { install(`
About
`); let boundRoot: unknown; const translate = () => "translated"; const setLanguage = () => true; win.__wrnI18n = { lang: "en", messages: { old: "Old" }, t: translate, set: setLanguage }; win.__wrnLang = { bind: (root: unknown) => (boundRoot = root) }; nextHtml = `

नवीन

` + `` + ``; win.document.getElementById("lnk").click(); await flush(); expect(win.__wrnI18n.lang).toBe("mr"); expect(win.__wrnI18n.messages.home.title).toBe("नवीन"); expect(win.__wrnI18n.t).toBe(translate); expect(win.__wrnI18n.set).toBe(setLanguage); expect(boundRoot).toBe(win.document.getElementById("app")); }); test("preserves same-language translations when an incoming navigation catalog is partial", async () => { install(`
About
`); win.__wrnI18n = { lang: "en", messages: { navigation: { home: "Home" }, footer: { contact: "Contact" } }, fallbackMessages: {}, }; win.__wrnLang = { bind: (root: ParentNode) => { root.querySelectorAll("[data-t]").forEach((node) => { const parts = String(node.getAttribute("data-t") || "").split("."); let value: any = win.__wrnI18n.messages; for (const part of parts) value = value?.[part]; node.textContent = typeof value === "string" ? value : node.getAttribute("data-t"); }); }, }; nextHtml = `

navigation.home

` + `` + ``; win.document.getElementById("lnk").click(); await flush(); expect(win.__wrnI18n.messages.navigation.home).toBe("Home"); expect(win.__wrnI18n.messages.footer.contact).toBe("Contact"); expect(win.document.querySelector("[data-t]")?.textContent).toBe("Home"); }); test("unmounts and remounts package runtimes during client navigation", async () => { install( `
Old
Next
`, ); let mounts = 0; let unmounts = 0; win.__wrnexusRuntimes = { captcha: { mount: () => mounts++, unmount: () => unmounts++, }, }; nextHtml = `
New
`; win.document.getElementById("lnk").click(); await flush(); expect(unmounts).toBe(1); expect(mounts).toBe(1); expect(win.document.getElementById("app").textContent).toContain("New"); }); test("synchronizes page styles during client navigation and preserves the current nonce", async () => { install( `` + `` + `
About
`, ); nextHtml = `` + `` + `

About

`; win.document.getElementById("lnk").click(); await flush(); expect(win.document.querySelector('style[data-wrnexus-style-id="home"]')).toBeNull(); const style = win.document.querySelector('style[data-wrnexus-style-id="about"]'); expect(style).not.toBeNull(); expect(style.textContent).toContain("color:blue"); expect(style.getAttribute("nonce")).toBe("current-nonce"); }); test("restores declared form state but never preserves sensitive fields", async () => { install( `` + `
`, ); nextHtml = `
Next
`; win.__wrnexusNavigate("/next"); await flush(); nextHtml = `
` + `
`; win.__wrnexusNavigate("/"); await flush(); expect(win.document.querySelector('[name="query"]').value).toBe("draft"); expect(win.document.querySelector('[name="password"]').value).toBe(""); }); test("KeepAlive preserves the same live DOM instance across routes", async () => { install( `
`, ); const original = win.document.querySelector("[data-wrn-keepalive]"); original.runtimeState = { count: 7 }; nextHtml = `
`; win.__wrnexusNavigate("/next"); await flush(); const restored = win.document.querySelector("[data-wrn-keepalive]"); expect(restored).toBe(original); expect(restored.runtimeState).toEqual({ count: 7 }); expect(restored.querySelector("input").value).toBe("live"); });