import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { test } from "node:test"; import { runInNewContext } from "node:vm"; const layout = readFileSync(new URL("../../app/layout.tsx", import.meta.url), "utf8"); const script = layout.match(/const CHUNK_ERROR_RECOVERY_SCRIPT = `\\?\n([\s\S]*?)`;/)?.[1]; assert(script, "Test the exact recovery script delivered by the root layout"); function browser(pathname = "/flow-board", options: { blockedStorage?: boolean; storage?: Map } = {}) { const events = new Map void>(); const timers: Array<() => void> = []; const storage = options.storage || new Map(); const notices: unknown[] = []; let reloads = 0; const location = { pathname, reload: () => { reloads += 1; } }; const dom = { body: { appendChild: (node: unknown) => notices.push(node) }, createElement: () => ({ setAttribute() {}, style: {}, textContent: "" }), }; runInNewContext(script!, { window: { location, addEventListener: (name: string, handler: (event?: unknown) => void) => events.set(name, handler) }, document: dom, sessionStorage: { getItem: (key: string) => storage.get(key), setItem: (key: string, value: string) => { if (options.blockedStorage) throw new Error("Blocked storage"); storage.set(key, value); }, }, setTimeout: (handler: () => void) => timers.push(handler), console: { warn() {} }, }); return { location, storage, notices, dom, dispatch: (name: string, event?: unknown) => events.get(name)?.(event), flush: () => { while (timers.length) timers.shift()!(); }, reloads: () => reloads, }; } test("ordinary editor exceptions in bundled scripts never force a page reload", () => { for (const path of ["/flow-board", "/"]) { const page = browser(path); for (let i = 0; i < 3; i += 1) { page.dispatch("error", { message: "Cannot resolve a DOM node from Slate node", filename: "https://ai.example/_next/static/chunks/editor.js" }); page.flush(); } assert.equal(page.reloads(), 0); } }); test("failed imports and rejected chunk promises never reload the flow board", () => { const page = browser(); page.dispatch("error", { message: "ChunkLoadError: Loading chunk 123 failed" }); page.dispatch("unhandledrejection", { reason: new Error("Failed to fetch dynamically imported module") }); page.flush(); assert.equal(page.reloads(), 0); assert.equal(page.notices.length, 1); }); test("a genuinely missing chunk can recover a non-editor route only once", () => { const page = browser("/"); const error = { message: "ChunkLoadError: Loading chunk 123 failed" }; page.dispatch("error", error); page.flush(); page.dispatch("error", error); page.flush(); page.dispatch("load"); page.flush(); assert.equal(page.reloads(), 1); const afterReload = browser("/", { storage: page.storage }); afterReload.dispatch("error", error); afterReload.flush(); assert.equal(afterReload.reloads(), 0); }); test("blocked session storage cannot create a reload loop", () => { const page = browser("/", { blockedStorage: true }); page.dispatch("error", { message: "ChunkLoadError: Loading chunk 123 failed" }); page.flush(); assert.equal(page.reloads(), 0); }); test("navigating into a flow board cancels an already scheduled reload", () => { const page = browser("/"); page.dispatch("error", { message: "ChunkLoadError: Loading chunk 123 failed" }); page.location.pathname = "/flow-board"; page.flush(); assert.equal(page.reloads(), 0); assert.equal(page.notices.length, 1); }); test("server render failures do not masquerade as downloadable resource failures", () => { const page = browser("/"); page.dispatch("unhandledrejection", { reason: new Error("An error occurred in the Server Components render") }); page.dispatch("error", { message: "Application error: a client-side exception has occurred", filename: "/_next/static/chunks/editor.js" }); page.flush(); assert.equal(page.reloads(), 0); });