75 lines
2.6 KiB
TypeScript
75 lines
2.6 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test";
|
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import { explainBuildDecision } from "../src/explain.ts";
|
|
|
|
const roots: string[] = [];
|
|
afterEach(async () =>
|
|
Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))),
|
|
);
|
|
|
|
async function fixture(): Promise<string> {
|
|
const root = join(tmpdir(), `wrnexus-explain-${crypto.randomUUID()}`);
|
|
roots.push(root);
|
|
await mkdir(join(root, "dist"), { recursive: true });
|
|
await writeFile(
|
|
join(root, "dist", "build-report.json"),
|
|
JSON.stringify({
|
|
frameworkVersion: "0.8.0",
|
|
adapter: "edge",
|
|
measurements: { routeJsBytes: 12 },
|
|
budgetViolations: [],
|
|
assets: [{ file: "server.js", bytes: 12 }],
|
|
routes: [
|
|
{
|
|
kind: "page",
|
|
path: "/users/[id]",
|
|
source: "app/pages/users/[id].wrn",
|
|
execution: "authenticated-ssr",
|
|
canPrerender: false,
|
|
needsClientRuntime: true,
|
|
needsServerRuntime: true,
|
|
hydrationStrategy: "visible",
|
|
reasons: ["client interactivity", "authentication required"],
|
|
cachePolicy: { strategy: "stale-while-revalidate", ttl: "30s" },
|
|
requiredPermission: "users.read",
|
|
},
|
|
],
|
|
}),
|
|
);
|
|
return root;
|
|
}
|
|
|
|
describe("causal build explanations", () => {
|
|
test("explains route execution and hydration from persisted compiler evidence", async () => {
|
|
const root = await fixture();
|
|
const route = explainBuildDecision(root, "route", "/users/[id]");
|
|
expect(route.summary).toContain("authenticated-ssr");
|
|
expect(route.reasons).toContain("authentication required");
|
|
expect(explainBuildDecision(root, "hydration", "users/[id]").summary).toContain("visible");
|
|
});
|
|
|
|
test("explains build and bundle measurements", async () => {
|
|
const root = await fixture();
|
|
expect(explainBuildDecision(root, "build").reasons).toContain(
|
|
"all configured performance budgets pass",
|
|
);
|
|
expect(explainBuildDecision(root, "bundle").reasons[0]).toBe("server.js: 12 bytes");
|
|
});
|
|
|
|
test("explains cache and permission decisions", async () => {
|
|
const root = await fixture();
|
|
expect(explainBuildDecision(root, "cache", "/users/[id]").summary).toContain(
|
|
"stale-while-revalidate",
|
|
);
|
|
expect(explainBuildDecision(root, "permission", "users.read").reasons[0]).toContain(
|
|
"security.permission",
|
|
);
|
|
});
|
|
|
|
test("uses stable diagnostics for missing evidence", () => {
|
|
expect(() => explainBuildDecision("missing", "build")).toThrow("WRN-EXPLAIN-NO-BUILD");
|
|
});
|
|
});
|