Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,215 @@
|
||||
// @vitest-environment node
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { resolveSummaryPath } from "./coverage-summary.mjs";
|
||||
import { buildVitestCoverageArgs, buildVitestCoverageEnv, evaluateTargets, isIgnorableCoverageTempFailure } from "./verify-test-coverage.mjs";
|
||||
|
||||
const repoRoot = path.resolve(fileURLToPath(import.meta.url), "..", "..");
|
||||
|
||||
function coveredFile(relativePath, statements = { covered: 8, total: 10 }, branches = { covered: 4, total: 5 }) {
|
||||
return {
|
||||
[path.join(repoRoot, relativePath)]: {
|
||||
statements,
|
||||
branches,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("verify-test-coverage", () => {
|
||||
it("keeps coverage-only artifact excludes out of coverage collection", async () => {
|
||||
const config = await import("../vitest.config.ts?coverage-excludes=1");
|
||||
expect(config.default.test?.coverage?.exclude).toEqual(
|
||||
expect.arrayContaining([
|
||||
"**/dist/**",
|
||||
"**/build/**",
|
||||
"**/.react-router/**",
|
||||
"**/storybook-static/**",
|
||||
"**/coverage/**",
|
||||
"**/coverage-gate/**",
|
||||
"**/generated/**",
|
||||
"**/*.generated.*",
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves full dev coverage reporters and the legacy coverage directory by default", async () => {
|
||||
const previous = process.env.TOOLCTRL_COVERAGE_GATE;
|
||||
delete process.env.TOOLCTRL_COVERAGE_GATE;
|
||||
try {
|
||||
const config = await import("../vitest.config.ts?coverage-default=1");
|
||||
expect(config.default.test?.coverage?.reporter).toEqual(["text-summary", "json-summary", "html", "lcov"]);
|
||||
expect(config.default.test?.coverage?.reportsDirectory).toBe("coverage");
|
||||
} finally {
|
||||
if (previous === undefined) {
|
||||
delete process.env.TOOLCTRL_COVERAGE_GATE;
|
||||
} else {
|
||||
process.env.TOOLCTRL_COVERAGE_GATE = previous;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("uses the lightweight coverage-gate reporters when the threshold gate env is set", async () => {
|
||||
const previous = process.env.TOOLCTRL_COVERAGE_GATE;
|
||||
process.env.TOOLCTRL_COVERAGE_GATE = "1";
|
||||
try {
|
||||
const gateConfig = await import("../vitest.config.ts?coverage-gate=1");
|
||||
expect(gateConfig.default.test?.coverage?.reporter).toEqual(["text-summary", "json-summary"]);
|
||||
expect(gateConfig.default.test?.coverage?.reportsDirectory).toBe("coverage-gate");
|
||||
} finally {
|
||||
if (previous === undefined) {
|
||||
delete process.env.TOOLCTRL_COVERAGE_GATE;
|
||||
} else {
|
||||
process.env.TOOLCTRL_COVERAGE_GATE = previous;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("runs the broad coverage gate on the threads pool to avoid fork coverage temp races", () => {
|
||||
expect(buildVitestCoverageArgs(["packages/url/src"])).toEqual(["exec", "vitest", "run", "--coverage", "--pool=threads", "packages/url/src"]);
|
||||
});
|
||||
|
||||
it("forces the lightweight coverage gate env for the spawned Vitest run", () => {
|
||||
expect(buildVitestCoverageEnv({ CI: "1", TOOLCTRL_COVERAGE_GATE: "0" })).toEqual({ CI: "1", TOOLCTRL_COVERAGE_GATE: "1" });
|
||||
});
|
||||
|
||||
it("ignores only coverage temp cleanup ENOENTs after tests passed and a summary exists", () => {
|
||||
const output = [
|
||||
" Test Files 396 passed | 3 skipped (399)",
|
||||
" Tests 3734 passed | 18 skipped (3752)",
|
||||
"Error: ENOENT: no such file or directory, lstat '/repo/coverage/.tmp'",
|
||||
].join("\n");
|
||||
|
||||
expect(isIgnorableCoverageTempFailure({ status: 1, output, summaryExists: true })).toBe(true);
|
||||
expect(isIgnorableCoverageTempFailure({ status: 1, output, summaryExists: false })).toBe(false);
|
||||
expect(isIgnorableCoverageTempFailure({ status: 1, output: output.replace("396 passed", "1 failed | 395 passed"), summaryExists: true })).toBe(false);
|
||||
expect(isIgnorableCoverageTempFailure({ status: 1, output: output.replace("coverage/.tmp", "coverage-summary.json"), summaryExists: true })).toBe(false);
|
||||
});
|
||||
|
||||
it("also recognizes coverage-gate temp cleanup ENOENTs", () => {
|
||||
const output = [
|
||||
" Test Files 396 passed | 3 skipped (399)",
|
||||
" Tests 3734 passed | 18 skipped (3752)",
|
||||
"Error: ENOENT: no such file or directory, lstat '/repo/coverage-gate/.tmp'",
|
||||
].join("\n");
|
||||
|
||||
expect(isIgnorableCoverageTempFailure({ status: 1, output, summaryExists: true })).toBe(true);
|
||||
});
|
||||
|
||||
it("resolves coverage summary paths from env, coverage-gate, then legacy coverage", () => {
|
||||
const root = path.join(repoRoot, "tmp-root");
|
||||
const seen = new Set([path.join(root, "coverage-gate", "coverage-summary.json")]);
|
||||
const fsApi = { existsSync: (candidate) => seen.has(candidate) };
|
||||
|
||||
expect(resolveSummaryPath({ root, env: {}, fsApi })).toBe(path.join(root, "coverage-gate", "coverage-summary.json"));
|
||||
|
||||
seen.clear();
|
||||
seen.add(path.join(root, "coverage", "coverage-summary.json"));
|
||||
expect(resolveSummaryPath({ root, env: {}, fsApi })).toBe(path.join(root, "coverage", "coverage-summary.json"));
|
||||
|
||||
expect(resolveSummaryPath({ root, env: { COVERAGE_SUMMARY_PATH: "custom/summary.json" }, fsApi })).toBe(path.join(root, "custom", "summary.json"));
|
||||
});
|
||||
|
||||
it("fails a missing critical runtime target instead of counting it as skipped", () => {
|
||||
const result = evaluateTargets(
|
||||
[
|
||||
{
|
||||
name: "apps/api/src/auth (critical-path: Auth)",
|
||||
pathPrefixes: ["apps/api/src/auth/"],
|
||||
statements: 99,
|
||||
branches: 92,
|
||||
criticalPath: true,
|
||||
},
|
||||
],
|
||||
{
|
||||
total: {},
|
||||
...coveredFile("apps/api/src/other/file.ts"),
|
||||
}
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
passes: [],
|
||||
failures: ["FAIL apps/api/src/auth (critical-path: Auth) [CRITICAL] no covered files matched"],
|
||||
});
|
||||
});
|
||||
|
||||
it("does not allow critical runtime targets to skip via allowEmpty", () => {
|
||||
const result = evaluateTargets(
|
||||
[
|
||||
{
|
||||
name: "apps/web/app/routes/register (critical-path: Signup)",
|
||||
pathPrefixes: ["apps/web/app/routes/register/"],
|
||||
statements: 95,
|
||||
branches: 90,
|
||||
criticalPath: true,
|
||||
allowEmpty: true,
|
||||
},
|
||||
],
|
||||
{ total: {} }
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
passes: [],
|
||||
failures: ["FAIL apps/web/app/routes/register (critical-path: Signup) [CRITICAL] no covered files matched"],
|
||||
});
|
||||
});
|
||||
|
||||
it("allows explicitly empty targets to skip when no covered files match", () => {
|
||||
const result = evaluateTargets(
|
||||
[
|
||||
{
|
||||
name: "packages/generated-client",
|
||||
pathPrefixes: ["packages/generated-client/src/"],
|
||||
statements: 80,
|
||||
branches: 70,
|
||||
allowEmpty: true,
|
||||
},
|
||||
],
|
||||
{ total: {} }
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
passes: ["SKIP packages/generated-client no covered files matched"],
|
||||
failures: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("allows 0/0 type-only targets to skip when no covered files match", () => {
|
||||
const result = evaluateTargets(
|
||||
[
|
||||
{
|
||||
name: "packages/api-types (type-only — runtime coverage near zero by design)",
|
||||
pathPrefixes: ["packages/api-types/src/"],
|
||||
statements: 0,
|
||||
branches: 0,
|
||||
},
|
||||
],
|
||||
{ total: {} }
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
passes: ["SKIP packages/api-types (type-only — runtime coverage near zero by design) no covered files matched"],
|
||||
failures: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("does not treat every 0/0 target as type-only", () => {
|
||||
const result = evaluateTargets(
|
||||
[
|
||||
{
|
||||
name: "packages/runtime-placeholder",
|
||||
pathPrefixes: ["packages/runtime-placeholder/src/"],
|
||||
statements: 0,
|
||||
branches: 0,
|
||||
},
|
||||
],
|
||||
{ total: {} }
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
passes: [],
|
||||
failures: ["FAIL packages/runtime-placeholder no covered files matched"],
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user