// @vitest-environment node import { readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; import { dashboardHostAssetUrls } from "../src/dashboard-assets.js"; const packageDirectory = path.dirname(path.dirname(fileURLToPath(import.meta.url))); describe("Dashboard host asset locator", () => { it("exports only frozen immutable href strings for the three exact built files, never the source map", () => { expect(Object.isFrozen(dashboardHostAssetUrls)).toBe(true); expect(dashboardHostAssetUrls).toEqual({ appearance: new URL( "dist/browser/assets/ekklesia-dashboard/appearance.js", `file://${packageDirectory}/`, ).href, html: new URL("dist/browser/index.html", `file://${packageDirectory}/`).href, script: new URL( "dist/browser/assets/ekklesia-dashboard/app.js", `file://${packageDirectory}/`, ).href, }); expect(JSON.stringify(dashboardHostAssetUrls)).not.toContain(".map"); }); it("publishes the locator through a narrow package subpath, not the shell root barrel", async () => { const manifest = JSON.parse( await readFile(path.join(packageDirectory, "package.json"), "utf8"), ) as { exports?: Record }; expect(manifest.exports?.["./dashboard-assets"]).toEqual({ import: "./dist/dashboard-assets.js", types: "./dist/dashboard-assets.d.ts", }); const rootSource = await readFile(path.join(packageDirectory, "src/index.ts"), "utf8"); expect(rootSource).not.toContain("dashboardHostAssetUrls"); expect(rootSource).not.toContain("dashboard-assets"); }); it("declares both colour schemes before any script runs, and takes its background from tokens", async () => { // So a dark system never flashes a white page while the shell loads (ADR 0060). const html = await readFile(path.join(packageDirectory, "index.html"), "utf8"); expect(html).toContain(''); expect(html).toContain("background: var(--ekklesia-background-page);"); expect(html).toContain("color: var(--ekklesia-text-primary);"); }); it("loads exactly two fixed, absolute, same-origin scripts and no inline script", async () => { const html = await readFile(path.join(packageDirectory, "index.html"), "utf8"); expect(html).toContain('id="ekklesia-host"'); expect(html.match(/', ); expect(html).toContain(''); // Every script names a source: there is no inline script for a strict script-src to excuse. expect(html.match(/]*\bsrc=")/gu)).toBeNull(); }); it("applies the cached appearance before first paint: a classic script in , after the colour-scheme element it narrows (ADR 0062)", async () => { const html = await readFile(path.join(packageDirectory, "index.html"), "utf8"); const head = html.slice(html.indexOf(""), html.indexOf("")); const boot = head.indexOf(''); // Classic (no `type="module"`, no `defer`, no `async`), so it blocks rendering until it ran. expect(boot).toBeGreaterThan(-1); expect(head.indexOf('name="color-scheme"')).toBeLessThan(boot); expect(head.slice(boot)).not.toMatch(/appearance\.js"[^>]*(?:type=|defer|async)/u); }); it("carries exactly one empty API-origin meta element for the serving API to fill (ADR 0045)", async () => { const html = await readFile(path.join(packageDirectory, "index.html"), "utf8"); expect(html.match(/name="ekklesia-api-origin"/gu)).toHaveLength(1); expect(html).toContain(''); }); it("bakes no API origin into the bundle: the build defines nothing but NODE_ENV", async () => { const buildScript = await readFile( path.join(packageDirectory, "scripts/build-browser.mjs"), "utf8", ); expect(buildScript).not.toContain("__EKKLESIA_API_BASE_URL__"); }); it("builds the Dashboard entry at the exact path the locator names", async () => { const buildScript = await readFile( path.join(packageDirectory, "scripts/build-browser.mjs"), "utf8", ); expect(buildScript).toContain('"assets/ekklesia-dashboard/app": path.join('); expect(buildScript).toContain('"assets/ekklesia-dashboard/appearance": path.join('); }); });