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:
24
packages/dashboard/app/__tests__/build-output-setup.ts
Normal file
24
packages/dashboard/app/__tests__/build-output-setup.ts
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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/);
|
||||
|
||||
Reference in New Issue
Block a user