import { afterEach, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { buildRouter } from "@wrnexus/router"; import { createHandlers, type RuntimeDeps } from "../src/runtime.ts"; const roots: string[] = []; afterEach(() => roots.splice(0).forEach((root) => rmSync(root, { recursive: true, force: true }))); test("server loader data is available to page rendering", async () => { const root = mkdtempSync(join(tmpdir(), "wrnexus-load-runtime-")); roots.push(root); const app = join(root, "app"); mkdirSync(join(app, "pages"), { recursive: true }); writeFileSync(join(app, "pages/users.ts"), "export default () => '';\n"); const handlers = createHandlers({ mode: "production", hmr: false, router: buildRouter(app), loadModule: async () => ({ __wrnexusLoad: async () => ({ users: ["Ada", "Lin"] }), default: (ctx: { users: string[]; data: { users: string[] } }) => `

${ctx.users.join(",")} / ${ctx.data.users.length}

`, }), getMiddleware: async () => [], assets: { serve: async () => null }, } satisfies RuntimeDeps); const response = await handlers.fetch(new Request("https://example.test/users"), { upgrade: () => false, }); expect(await response!.text()).toContain("Ada,Lin / 2"); }); test("HMR page synchronization initializes request-scoped loader caching", async () => { const root = mkdtempSync(join(tmpdir(), "wrnexus-hmr-load-runtime-")); roots.push(root); const app = join(root, "app"); mkdirSync(join(app, "pages"), { recursive: true }); writeFileSync(join(app, "pages/async.ts"), "export default () => '';\n"); const handlers = createHandlers({ mode: "development", hmr: true, router: buildRouter(app), loadModule: async () => ({ __wrnexusLoad: async () => ({ message: "Loaded through HMR" }), default: (ctx: { message: string }) => `

${ctx.message}

`, }), getMiddleware: async () => [], assets: { serve: async () => null }, } satisfies RuntimeDeps); const html = await new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error("HMR response timed out")), 1_000); handlers.websocket.message( { data: { kind: "hmr", baseUrl: "http://localhost", headers: [] }, send(value) { clearTimeout(timeout); resolve(String(value)); }, close() {}, }, JSON.stringify({ type: "sync", path: "/async" }), ); }); const message = JSON.parse(html) as { type: string; html?: string; message?: string }; expect(message.type).toBe("html"); expect(message.message).toBeUndefined(); expect(message.html).toContain("Loaded through HMR"); });