test(FN-2343): harden build-output contract coverage

- Add shared test setup helpers that always build dashboard client assets before assertions run
- Remove skip-gated build-output tests and make CLI/dashboard suites deterministic by owning artifact setup
- Enforce hashed vendor chunk naming checks for vendor-react and vendor-xterm in generated assets
- Verify copied CLI client index references real built chunks and does not contain the dashboard stub marker
This commit is contained in:
Fusion
2026-04-23 13:29:23 -07:00
committed by gsxdsm
parent 233d8abef9
commit 18b2c827a0
4 changed files with 95 additions and 29 deletions

View File

@@ -0,0 +1,24 @@
import { execSync } from "node:child_process";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
const dashboardRoot = resolve(__dirname, "../..");
export const dashboardClientDistDir = resolve(dashboardRoot, "dist/client");
export const dashboardClientAssetsDir = resolve(dashboardClientDistDir, "assets");
/**
* Build output verification must be deterministic: the suite owns artifact setup
* and never skip-gates coverage based on whatever dist/ state already exists.
*/
export function ensureDashboardClientBuild() {
execSync("pnpm build:client", {
cwd: dashboardRoot,
stdio: "pipe",
timeout: 180_000,
});
if (!existsSync(dashboardClientDistDir) || !existsSync(dashboardClientAssetsDir)) {
throw new Error("Dashboard client build did not produce dist/client assets");
}
}

View File

@@ -1,23 +1,28 @@
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { readdirSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, test } from "vitest";
const distDir = resolve(__dirname, "../../dist/client");
const assetsDir = resolve(distDir, "assets");
const distExists = existsSync(distDir) && existsSync(assetsDir);
import { beforeAll, describe, expect, test } from "vitest";
import {
dashboardClientAssetsDir,
dashboardClientDistDir,
ensureDashboardClientBuild,
} from "./build-output-setup";
describe("mobile build output chunking", () => {
test.skipIf(!distExists)("creates vendor chunk files for core dependencies", () => {
const files = readdirSync(assetsDir);
beforeAll(() => {
ensureDashboardClientBuild();
}, 180_000);
test("creates vendor chunk files for core dependencies", () => {
const files = readdirSync(dashboardClientAssetsDir);
const jsFiles = files.filter((file) => file.endsWith(".js"));
expect(jsFiles.length).toBeGreaterThan(2);
expect(jsFiles.some((file) => file.includes("vendor-react"))).toBe(true);
expect(jsFiles.some((file) => file.includes("vendor-xterm"))).toBe(true);
expect(jsFiles.some((file) => /^vendor-react-[A-Za-z0-9_-]+\.js$/.test(file))).toBe(true);
expect(jsFiles.some((file) => /^vendor-xterm-[A-Za-z0-9_-]+\.js$/.test(file))).toBe(true);
});
test.skipIf(!distExists)("index.html references chunked asset scripts", () => {
const indexHtml = readFileSync(resolve(distDir, "index.html"), "utf8");
test("index.html references chunked asset scripts", () => {
const indexHtml = readFileSync(resolve(dashboardClientDistDir, "index.html"), "utf8");
expect(indexHtml).toContain("<script");
expect(indexHtml).toMatch(/assets\/.+-[A-Za-z0-9_-]+\.js/);