@fairfox/polly 0.82.0 → 0.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/polly.js +22 -1
- package/dist/cli/polly.js.map +3 -3
- package/dist/tools/bdd/src/args.d.ts +21 -0
- package/dist/tools/bdd/src/bus-driver.d.ts +36 -0
- package/dist/tools/bdd/src/check-verify.d.ts +15 -0
- package/dist/tools/bdd/src/cli.d.ts +2 -0
- package/dist/tools/bdd/src/cli.js +701 -0
- package/dist/tools/bdd/src/cli.js.map +19 -0
- package/dist/tools/bdd/src/config.d.ts +9 -0
- package/dist/tools/bdd/src/extract.d.ts +2 -0
- package/dist/tools/bdd/src/index.d.ts +19 -0
- package/dist/tools/bdd/src/index.js +540 -0
- package/dist/tools/bdd/src/index.js.map +17 -0
- package/dist/tools/bdd/src/parse.d.ts +3 -0
- package/dist/tools/bdd/src/report.d.ts +6 -0
- package/dist/tools/bdd/src/run.d.ts +8 -0
- package/dist/tools/bdd/src/scaffold.d.ts +7 -0
- package/dist/tools/bdd/src/steps.d.ts +55 -0
- package/dist/tools/bdd/src/types.d.ts +145 -0
- package/dist/tools/bdd/src/witness.d.ts +23 -0
- package/dist/tools/gallery/src/cli.js +4 -3
- package/dist/tools/gallery/src/cli.js.map +3 -3
- package/dist/tools/mutate/src/cli.js +8 -1
- package/dist/tools/mutate/src/cli.js.map +3 -3
- package/dist/tools/quality/src/cli.js +304 -15
- package/dist/tools/quality/src/cli.js.map +6 -4
- package/dist/tools/quality/src/index.d.ts +2 -0
- package/dist/tools/quality/src/index.js +309 -15
- package/dist/tools/quality/src/index.js.map +6 -4
- package/dist/tools/quality/src/no-fixed-waits.d.ts +52 -0
- package/dist/tools/quality/src/no-tautology-ensures.d.ts +67 -0
- package/dist/tools/quality/src/plugins/core.d.ts +1 -1
- package/dist/tools/test/src/coverage-policy/cli.js +5 -1
- package/dist/tools/test/src/coverage-policy/cli.js.map +3 -3
- package/dist/tools/test/src/tiers/args.d.ts +5 -0
- package/dist/tools/test/src/tiers/cli.js +97 -23
- package/dist/tools/test/src/tiers/cli.js.map +9 -8
- package/dist/tools/test/src/tiers/index.d.ts +2 -1
- package/dist/tools/test/src/tiers/order.d.ts +25 -0
- package/dist/tools/test/src/tiers/types.d.ts +15 -0
- package/dist/tools/verify/src/cli.js +540 -15
- package/dist/tools/verify/src/cli.js.map +8 -4
- package/dist/tools/visualize/src/cli.js +17 -13
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +9 -16
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../tools/test/src/tiers/cli.ts", "../tools/test/src/tiers/args.ts", "../tools/test/src/tiers/discover.ts", "../tools/test/src/tiers/detect.ts", "../tools/test/src/tiers/protocol.ts", "../tools/test/src/tiers/engine.ts", "../tools/test/src/tiers/reporter.ts"],
|
|
3
|
+
"sources": ["../tools/test/src/tiers/cli.ts", "../tools/test/src/tiers/args.ts", "../tools/test/src/tiers/discover.ts", "../tools/test/src/tiers/detect.ts", "../tools/test/src/tiers/order.ts", "../tools/test/src/tiers/protocol.ts", "../tools/test/src/tiers/engine.ts", "../tools/test/src/tiers/reporter.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"#!/usr/bin/env bun\n/**\n * Consumer-facing tiered test runner — what `polly test --tier …` runs from a\n * consumer's own Polly project. It auto-discovers the project's tiers (see\n * discover.ts) and runs them through the shared engine, exactly as Polly's own\n * internal suite does.\n *\n * Usage (from a Polly project root):\n * polly test --tier # discovered unit + integration (fast loop)\n * polly test --tier --all # every discovered tier\n * polly test --tier=browser # one tier\n * polly test --tier --list # show what was discovered, run nothing\n * polly test --tier --json # write test-results/tiers.json\n *\n * (Bare `polly test` still delegates to `bun test`; the --tier-family flags\n * switch into this runner.)\n */\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { parseTierArgs } from \"./args\";\nimport { discoverPlan } from \"./discover\";\nimport { runPlan } from \"./engine\";\nimport { formatPlan, formatSummary, toJSON } from \"./reporter\";\n\n/** Tiers run when no tier is named (fast inner loop), if they were discovered. */\nconst DEFAULT_TIERS = [\"unit\", \"integration\"];\n\nasync function main(): Promise<void> {\n const args = parseTierArgs(process.argv.slice(2));\n const root = process.cwd();\n const plan = await discoverPlan(root);\n\n if (plan.tiers.length === 0) {\n console.log(\n \"polly test: no tiers discovered.\\n\" +\n \" Looked for *.test.{ts,tsx}, *.browser.{ts,tsx}, and scripts/e2e-*.{ts,tsx}.\"\n );\n process.exit(0);\n }\n\n if (args.list) {\n console.log(formatPlan(plan));\n return;\n }\n\n const discovered = plan.tiers.map((t) => t.name);\n const known = new Set(discovered);\n let tiers: string[];\n if (args.tiers.length > 0) {\n const unknown = args.tiers.filter((t) => !known.has(t));\n if (unknown.length > 0) {\n console.log(`Unknown tier(s): ${unknown.join(\", \")}`);\n console.log(`Discovered tiers: ${discovered.join(\", \")}`);\n process.exit(2);\n }\n tiers = args.tiers;\n } else if (args.all || args.full) {\n tiers = discovered;\n } else {\n const fast = discovered.filter((t) => DEFAULT_TIERS.includes(t));\n tiers = fast.length > 0 ? fast : discovered;\n }\n\n console.log(\n `polly test — tiers: ${tiers.join(\" → \")}${args.only.length ? ` only: ${args.only.join(\", \")}` : \"\"}`\n );\n\n const report = await runPlan(plan, {\n tiers,\n only: args.only,\n bail: args.bail,\n strictNeeds: args.strictNeeds,\n cwd: root,\n log: (m) => console.log(m),\n });\n\n console.log(formatSummary(report));\n\n if (args.json) {\n mkdirSync(dirname(args.json), { recursive: true });\n await Bun.write(args.json, toJSON(report));\n console.log(`\\nwrote ${args.json}`);\n }\n\n process.exit(report.ok ? 0 : 1);\n}\n\nawait main();\n",
|
|
6
|
-
"/**\n * Shared flag parsing for the tiered runner CLIs.\n *\n * Both front-ends (Polly's internal scripts/test/cli.ts and the consumer-facing\n * tools/test/src/tiers/cli.ts) accept the same flags; only their tier *sets*\n * differ. This keeps the surface identical.\n */\n\nexport interface TierArgs {\n /** Explicit tier names (positional or via --tier=a,b). */\n tiers: string[];\n /** --only=substr filters across tiers. */\n only: string[];\n all: boolean;\n full: boolean;\n list: boolean;\n bail: boolean;\n strictNeeds: boolean;\n /** Path to write JSON results, or null. */\n json: string | null;\n}\n\nexport const DEFAULT_JSON = \"test-results/tiers.json\";\n\nconst BOOL_FLAGS: Record<string, \"all\" | \"full\" | \"list\" | \"bail\" | \"strictNeeds\"> = {\n \"--all\": \"all\",\n \"--full\": \"full\",\n \"--list\": \"list\",\n \"--bail\": \"bail\",\n \"--strict-needs\": \"strictNeeds\",\n};\n\nfunction listValue(arg: string, name: string): string[] {\n return arg.startsWith(name) ? arg.slice(name.length).split(\",\") : [];\n}\n\n/**
|
|
7
|
-
"/**\n * Zero-config tier discovery for a consumer's Polly project.\n *\n * `polly test --tier` from a consumer's project builds its {@link TierPlan} by\n * convention — no config required:\n * - unit `bun test` (or `bun test tests/unit` if that dir exists)\n * - integration `bun test tests/integration` (when the dir exists)\n * - browser the Polly browser runner over `*.browser.{ts,tsx}`\n * - e2e `scripts/e2e-*.{ts,tsx}` exporting `run(ctx)` — the same\n * contract Polly dogfoods, so consumer e2e scripts written with\n * `@fairfox/polly/test` helpers slot straight in.\n *\n * A tier only appears when its inputs exist, so a project with just unit tests\n * gets just a unit tier.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { CaseSpec, Tier, TierPlan } from \"./types\";\n\n/** Files matching `pattern` under `root`, excluding node_modules, sorted. */\nasync function globFiles(root: string, pattern: string): Promise<string[]> {\n const glob = new Bun.Glob(pattern);\n const out: string[] = [];\n for await (const file of glob.scan({ cwd: root, onlyFiles: true })) {\n if (file.includes(\"node_modules\") || file.startsWith(\"dist/\")) continue;\n out.push(file);\n }\n return out.sort();\n}\n\n/** Resolve the browser runner, preferring the bundled build. */\nfunction browserRunner(): string {\n const bundled = `${import.meta.dir}/../browser/run.js`;\n const source = `${import.meta.dir}/../browser/run.ts`;\n return existsSync(bundled) ? bundled : source;\n}\n\n/** A safe directory to hand the browser runner (never the project root, which\n * would make it scan node_modules). */\nfunction browserDir(root: string, files: string[]): string {\n if (existsSync(join(root, \"tests/browser\"))) return \"tests/browser\";\n if (existsSync(join(root, \"tests\"))) return \"tests\";\n return dirname(files[0] ?? \".\") || \".\";\n}\n\n/** `scripts/e2e-foo-bar.ts` → `foo-bar`. */\nfunction e2eId(file: string): string {\n const base = file.replace(/^.*\\//, \"\").replace(/\\.(ts|tsx)$/, \"\");\n return base.replace(/^e2e-/, \"\") || base;\n}\n\nexport async function discoverPlan(root: string): Promise<TierPlan> {\n const tiers: Tier[] = [];\n\n const hasUnitDir = existsSync(join(root, \"tests/unit\"));\n const hasIntegrationDir = existsSync(join(root, \"tests/integration\"));\n const testFiles = await globFiles(root, \"**/*.test.{ts,tsx}\");\n\n if (hasUnitDir) {\n tiers.push({\n name: \"unit\",\n description: \"bun test tests/unit\",\n cases: [\n { id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/unit\"], cwd: root } },\n ],\n });\n } else if (testFiles.length > 0) {\n tiers.push({\n name: \"unit\",\n description: `bun test (${testFiles.length} files)`,\n cases: [{ id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\"], cwd: root } }],\n });\n }\n\n if (hasIntegrationDir) {\n tiers.push({\n name: \"integration\",\n description: \"bun test tests/integration\",\n cases: [\n {\n id: \"integration\",\n exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/integration\"], cwd: root },\n },\n ],\n });\n }\n\n const browserFiles = await globFiles(root, \"**/*.browser.{ts,tsx}\");\n if (browserFiles.length > 0) {\n tiers.push({\n name: \"browser\",\n description: `Puppeteer over ${browserFiles.length} *.browser file(s)`,\n timeoutMs: 180_000,\n cases: [\n {\n id: \"browser\",\n needs: [\"browser\"],\n exec: {\n kind: \"command\",\n argv: [\"bun\", browserRunner(), browserDir(root, browserFiles)],\n cwd: root,\n },\n },\n ],\n });\n }\n\n const e2eFiles = await globFiles(root, \"scripts/e2e-*.{ts,tsx}\");\n if (e2eFiles.length > 0) {\n const cases: CaseSpec[] = e2eFiles.map((file) => ({\n id: e2eId(file),\n tags: [\"e2e\"],\n exec: { kind: \"module\", modulePath: join(root, file) },\n }));\n tiers.push({\n name: \"e2e\",\n description: `run()-export scripts (${e2eFiles.length})`,\n concurrency: 2,\n timeoutMs: 240_000,\n cases,\n });\n }\n\n return { tiers };\n}\n",
|
|
5
|
+
"#!/usr/bin/env bun\n/**\n * Consumer-facing tiered test runner — what `polly test --tier …` runs from a\n * consumer's own Polly project. It auto-discovers the project's tiers (see\n * discover.ts) and runs them through the shared engine, exactly as Polly's own\n * internal suite does.\n *\n * Usage (from a Polly project root):\n * polly test --tier # discovered unit + integration (fast loop)\n * polly test --tier --all # every discovered tier\n * polly test --tier=browser # one tier\n * polly test --tier --all --order=cost # heaviest cases first (min wall-clock)\n * polly test --tier --all --fail-fast # soft early-stop on first failure\n * polly test --tier --list # show what was discovered, run nothing\n * polly test --tier --json # write test-results/tiers.json\n *\n * (Bare `polly test` still delegates to `bun test`; the --tier-family flags\n * switch into this runner.)\n */\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { parseTierArgs } from \"./args\";\nimport { discoverPlan } from \"./discover\";\nimport { runPlan } from \"./engine\";\nimport { formatPlan, formatSummary, toJSON } from \"./reporter\";\n\n/** Tiers run when no tier is named (fast inner loop), if they were discovered. */\nconst DEFAULT_TIERS = [\"unit\", \"integration\"];\n\nasync function main(): Promise<void> {\n const args = parseTierArgs(process.argv.slice(2));\n const root = process.cwd();\n const plan = await discoverPlan(root);\n\n if (plan.tiers.length === 0) {\n console.log(\n \"polly test: no tiers discovered.\\n\" +\n \" Looked for *.test.{ts,tsx}, *.browser.{ts,tsx}, and scripts/e2e-*.{ts,tsx}.\"\n );\n process.exit(0);\n }\n\n if (args.list) {\n console.log(formatPlan(plan));\n return;\n }\n\n const discovered = plan.tiers.map((t) => t.name);\n const known = new Set(discovered);\n let tiers: string[];\n if (args.tiers.length > 0) {\n const unknown = args.tiers.filter((t) => !known.has(t));\n if (unknown.length > 0) {\n console.log(`Unknown tier(s): ${unknown.join(\", \")}`);\n console.log(`Discovered tiers: ${discovered.join(\", \")}`);\n process.exit(2);\n }\n tiers = args.tiers;\n } else if (args.all || args.full) {\n tiers = discovered;\n } else {\n const fast = discovered.filter((t) => DEFAULT_TIERS.includes(t));\n tiers = fast.length > 0 ? fast : discovered;\n }\n\n console.log(\n `polly test — tiers: ${tiers.join(\" → \")}${args.only.length ? ` only: ${args.only.join(\", \")}` : \"\"}`\n );\n\n const report = await runPlan(plan, {\n tiers,\n only: args.only,\n // --fail-fast wants cheap, high-signal cases first so the abort trips\n // soonest; an explicit --order always wins.\n order: args.order ?? (args.failFast ? \"fast\" : \"default\"),\n bail: args.bail,\n failFast: args.failFast,\n strictNeeds: args.strictNeeds,\n cwd: root,\n log: (m) => console.log(m),\n });\n\n console.log(formatSummary(report));\n\n if (args.json) {\n mkdirSync(dirname(args.json), { recursive: true });\n await Bun.write(args.json, toJSON(report));\n console.log(`\\nwrote ${args.json}`);\n }\n\n process.exit(report.ok ? 0 : 1);\n}\n\nawait main();\n",
|
|
6
|
+
"/**\n * Shared flag parsing for the tiered runner CLIs.\n *\n * Both front-ends (Polly's internal scripts/test/cli.ts and the consumer-facing\n * tools/test/src/tiers/cli.ts) accept the same flags; only their tier *sets*\n * differ. This keeps the surface identical.\n */\n\nimport type { CaseOrder } from \"./types\";\n\nexport interface TierArgs {\n /** Explicit tier names (positional or via --tier=a,b). */\n tiers: string[];\n /** --only=substr filters across tiers. */\n only: string[];\n all: boolean;\n full: boolean;\n list: boolean;\n bail: boolean;\n /** --fail-fast: soft early-stop on the first failing case. */\n failFast: boolean;\n /** --order=fast|cost|default within-tier ordering, or null to leave unset. */\n order: CaseOrder | null;\n strictNeeds: boolean;\n /** Path to write JSON results, or null. */\n json: string | null;\n}\n\nexport const DEFAULT_JSON = \"test-results/tiers.json\";\n\nconst BOOL_FLAGS: Record<string, \"all\" | \"full\" | \"list\" | \"bail\" | \"failFast\" | \"strictNeeds\"> = {\n \"--all\": \"all\",\n \"--full\": \"full\",\n \"--list\": \"list\",\n \"--bail\": \"bail\",\n \"--fail-fast\": \"failFast\",\n \"--strict-needs\": \"strictNeeds\",\n};\n\n/** Narrow a raw `--order=` value to a {@link CaseOrder}, or null if unknown. */\nfunction parseOrder(value: string): CaseOrder | null {\n if (value === \"default\" || value === \"fast\" || value === \"cost\") return value;\n return null;\n}\n\nfunction listValue(arg: string, name: string): string[] {\n return arg.startsWith(name) ? arg.slice(name.length).split(\",\") : [];\n}\n\n/** Apply a value-bearing flag (`--name=value`, or bare `--json`). Returns false\n * if `arg` isn't one, so the caller can fall through to tier names. Exits(2) on\n * a malformed `--order=`. */\nfunction applyValueFlag(args: TierArgs, arg: string): boolean {\n if (arg === \"--json\") {\n args.json = DEFAULT_JSON;\n return true;\n }\n if (arg.startsWith(\"--json=\")) {\n args.json = arg.slice(\"--json=\".length);\n return true;\n }\n if (arg.startsWith(\"--tier=\")) {\n args.tiers.push(...listValue(arg, \"--tier=\"));\n return true;\n }\n if (arg.startsWith(\"--only=\")) {\n args.only.push(...listValue(arg, \"--only=\"));\n return true;\n }\n if (arg.startsWith(\"--order=\")) {\n const order = parseOrder(arg.slice(\"--order=\".length));\n if (order === null) {\n console.log(\"Unknown --order value (expected default, fast, or cost)\");\n process.exit(2);\n }\n args.order = order;\n return true;\n }\n return false;\n}\n\n/** Parse argv into {@link TierArgs}. Exits(2) on an unknown `--flag`. */\nexport function parseTierArgs(argv: string[]): TierArgs {\n const args: TierArgs = {\n tiers: [],\n only: [],\n all: false,\n full: false,\n list: false,\n bail: false,\n failFast: false,\n order: null,\n strictNeeds: false,\n json: null,\n };\n for (const arg of argv) {\n const boolKey = BOOL_FLAGS[arg];\n if (boolKey) {\n args[boolKey] = true;\n continue;\n }\n if (applyValueFlag(args, arg)) {\n continue;\n }\n if (arg.startsWith(\"-\")) {\n console.log(`Unknown flag: ${arg}`);\n process.exit(2);\n }\n args.tiers.push(arg);\n }\n return args;\n}\n",
|
|
7
|
+
"/**\n * Zero-config tier discovery for a consumer's Polly project.\n *\n * `polly test --tier` from a consumer's project builds its {@link TierPlan} by\n * convention — no config required:\n * - unit `bun test` (or `bun test tests/unit` if that dir exists)\n * - integration `bun test tests/integration` (when the dir exists)\n * - browser the Polly browser runner over `*.browser.{ts,tsx}`\n * - e2e `scripts/e2e-*.{ts,tsx}` exporting `run(ctx)` — the same\n * contract Polly dogfoods, so consumer e2e scripts written with\n * `@fairfox/polly/test` helpers slot straight in.\n *\n * A tier only appears when its inputs exist, so a project with just unit tests\n * gets just a unit tier.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { CaseSpec, Tier, TierPlan } from \"./types\";\n\n/** Files matching `pattern` under `root`, excluding node_modules, sorted. */\nasync function globFiles(root: string, pattern: string): Promise<string[]> {\n const glob = new Bun.Glob(pattern);\n const out: string[] = [];\n for await (const file of glob.scan({ cwd: root, onlyFiles: true })) {\n if (file.includes(\"node_modules\") || file.startsWith(\"dist/\")) continue;\n out.push(file);\n }\n return out.sort();\n}\n\n/** Resolve the browser runner, preferring the bundled build. */\nfunction browserRunner(): string {\n const bundled = `${import.meta.dir}/../browser/run.js`;\n const source = `${import.meta.dir}/../browser/run.ts`;\n return existsSync(bundled) ? bundled : source;\n}\n\n/** Resolve the `polly bdd` CLI, preferring the bundled build. */\nfunction bddRunner(): string {\n const bundled = `${import.meta.dir}/../../../bdd/src/cli.js`;\n const source = `${import.meta.dir}/../../../bdd/src/cli.ts`;\n return existsSync(bundled) ? bundled : source;\n}\n\n/** A safe directory to hand the browser runner (never the project root, which\n * would make it scan node_modules). */\nfunction browserDir(root: string, files: string[]): string {\n if (existsSync(join(root, \"tests/browser\"))) return \"tests/browser\";\n if (existsSync(join(root, \"tests\"))) return \"tests\";\n return dirname(files[0] ?? \".\") || \".\";\n}\n\n/** `scripts/e2e-foo-bar.ts` → `foo-bar`. */\nfunction e2eId(file: string): string {\n const base = file.replace(/^.*\\//, \"\").replace(/\\.(ts|tsx)$/, \"\");\n return base.replace(/^e2e-/, \"\") || base;\n}\n\nexport async function discoverPlan(root: string): Promise<TierPlan> {\n const tiers: Tier[] = [];\n\n const hasUnitDir = existsSync(join(root, \"tests/unit\"));\n const hasIntegrationDir = existsSync(join(root, \"tests/integration\"));\n const testFiles = await globFiles(root, \"**/*.test.{ts,tsx}\");\n\n if (hasUnitDir) {\n tiers.push({\n name: \"unit\",\n description: \"bun test tests/unit\",\n cases: [\n { id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/unit\"], cwd: root } },\n ],\n });\n } else if (testFiles.length > 0) {\n tiers.push({\n name: \"unit\",\n description: `bun test (${testFiles.length} files)`,\n cases: [{ id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\"], cwd: root } }],\n });\n }\n\n if (hasIntegrationDir) {\n tiers.push({\n name: \"integration\",\n description: \"bun test tests/integration\",\n cases: [\n {\n id: \"integration\",\n exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/integration\"], cwd: root },\n },\n ],\n });\n }\n\n const featureFiles = await globFiles(root, \"**/*.feature\");\n if (featureFiles.length > 0) {\n tiers.push({\n name: \"bdd\",\n description: `executable Gherkin (${featureFiles.length} *.feature file(s))`,\n timeoutMs: 120_000,\n cases: [\n {\n id: \"bdd\",\n tags: [\"bdd\", \"gherkin\"],\n exec: { kind: \"command\", argv: [\"bun\", bddRunner(), \"run\"], cwd: root },\n },\n ],\n });\n }\n\n const browserFiles = await globFiles(root, \"**/*.browser.{ts,tsx}\");\n if (browserFiles.length > 0) {\n tiers.push({\n name: \"browser\",\n description: `Puppeteer over ${browserFiles.length} *.browser file(s)`,\n timeoutMs: 180_000,\n cases: [\n {\n id: \"browser\",\n needs: [\"browser\"],\n exec: {\n kind: \"command\",\n argv: [\"bun\", browserRunner(), browserDir(root, browserFiles)],\n cwd: root,\n },\n },\n ],\n });\n }\n\n const e2eFiles = await globFiles(root, \"scripts/e2e-*.{ts,tsx}\");\n if (e2eFiles.length > 0) {\n const cases: CaseSpec[] = e2eFiles.map((file) => ({\n id: e2eId(file),\n tags: [\"e2e\"],\n exec: { kind: \"module\", modulePath: join(root, file) },\n }));\n tiers.push({\n name: \"e2e\",\n description: `run()-export scripts (${e2eFiles.length})`,\n concurrency: 2,\n timeoutMs: 240_000,\n cases,\n });\n }\n\n return { tiers };\n}\n",
|
|
8
8
|
"/**\n * Host capability detection for need-gating.\n *\n * A case declaring `needs: [\"docker\"]` is skipped (not failed) when the host\n * can't satisfy it, unless `--strict-needs` is set. Detection is cached for the\n * lifetime of the process so a 30-case run probes `docker info` once.\n */\nimport type { Need } from \"./types\";\n\nconst cache = new Map<Need, boolean>();\n\nasync function commandSucceeds(argv: string[]): Promise<boolean> {\n try {\n const proc = Bun.spawn(argv, { stdout: \"ignore\", stderr: \"ignore\", stdin: \"ignore\" });\n return (await proc.exited) === 0;\n } catch {\n return false;\n }\n}\n\nasync function probe(need: Need): Promise<boolean> {\n switch (need) {\n case \"docker\":\n // `docker info` fails fast when the daemon is down, unlike `docker --version`.\n return commandSucceeds([\"docker\", \"info\"]);\n case \"browser\":\n // Puppeteer ships Chromium as a devDependency; assume present in-repo.\n // A real probe would resolve the executable path, but that pulls puppeteer\n // into the engine. Front-ends that need a stricter check can override.\n return true;\n case \"network\":\n return true;\n default:\n return false;\n }\n}\n\n/** Resolve whether a need is satisfied, memoised. */\nexport async function hasNeed(need: Need): Promise<boolean> {\n const cached = cache.get(need);\n if (cached !== undefined) return cached;\n const result = await probe(need);\n cache.set(need, result);\n return result;\n}\n\n/** First unmet need among `needs`, or null if all are satisfied. */\nexport async function firstUnmetNeed(needs: Need[] | undefined): Promise<Need | null> {\n for (const need of needs ?? []) {\n if (!(await hasNeed(need))) return need;\n }\n return null;\n}\n",
|
|
9
|
+
"/**\n * Within-tier case ordering.\n *\n * The engine drains a tier's cases through a bounded pool in array order, so\n * where a case sits decides when it launches. Reordering by a coarse cost hint\n * buys two different things depending on intent:\n *\n * - \"cost\" (heaviest first): the long poles launch in the first `concurrency`\n * slots and everything cheaper packs in behind them, so wall-clock collapses\n * toward the single slowest case instead of the sum. Use for a full run.\n * - \"fast\" (lightest first): cheap, high-signal cases run first, so under\n * soft-fail-fast they trip the abort soonest — you can't un-spawn a 4-minute\n * case, so you want it to *not* have started when a 2-second case fails.\n * - \"default\": registry definition order, unchanged.\n *\n * Pure and dependency-free on purpose: this is the one piece of the engine that\n * is worth unit-testing in isolation, and keeping it out of engine.ts keeps the\n * subprocess-heavy engine off the unit-coverage table.\n */\nimport type { CaseOrder, CaseSpec } from \"./types\";\n\nconst COST_WEIGHT: Record<NonNullable<CaseSpec[\"cost\"]>, number> = {\n light: 0,\n medium: 1,\n heavy: 2,\n};\n\n/** Weight of a case; unset cost is treated as \"medium\". */\nfunction weightOf(spec: CaseSpec): number {\n return COST_WEIGHT[spec.cost ?? \"medium\"];\n}\n\n/**\n * Return a copy of `cases` reordered per `order`. Stable: cases of equal weight\n * keep their original relative order, and \"default\" returns the input as-is.\n */\nexport function orderCases(cases: CaseSpec[], order: CaseOrder): CaseSpec[] {\n if (order === \"default\") return cases;\n const direction = order === \"cost\" ? -1 : 1; // cost → heaviest first; fast → lightest first\n return cases\n .map((spec, index) => ({ spec, index }))\n .sort((a, b) => (weightOf(a.spec) - weightOf(b.spec)) * direction || a.index - b.index)\n .map((entry) => entry.spec);\n}\n",
|
|
9
10
|
"/**\n * The one shared constant between the engine and its subprocess worker.\n *\n * It lives in its own leaf module so the engine never has to *import* the\n * worker (only spawn it by path). If the engine imported the worker, a\n * `splitting: false` bundle would inline the worker's `import.meta.main`\n * self-exec block into the CLI bundle and run it on startup. Keeping the\n * sentinel here avoids that.\n */\nexport const SENTINEL = \"__TIER_RESULT__\";\n",
|
|
10
|
-
"/**\n * The tiered test engine.\n *\n * Runs a {@link TierPlan} tier-by-tier in order. Within a tier, cases run with\n * bounded concurrency. Each case is its own subprocess (see worker.ts) so the\n * isolation the e2e scripts assume is preserved. Cases whose host needs are\n * unmet are skipped (logged), not failed, unless `strictNeeds` is set.\n */\nimport { firstUnmetNeed } from \"./detect\";\nimport { SENTINEL } from \"./protocol\";\nimport type {\n CaseOutcome,\n CaseReport,\n CaseSpec,\n EngineOptions,\n RunReport,\n Tier,\n TierPlan,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\nasync function workerPath(): Promise<string> {\n const bundled = `${import.meta.dir}/worker.js`;\n const source = `${import.meta.dir}/worker.ts`;\n return (await Bun.file(bundled).exists()) ? bundled : source;\n}\n\nfunction caseLabel(spec: CaseSpec): string {\n return spec.label ?? spec.id;\n}\n\nfunction caseMatches(spec: CaseSpec, only: string[] | undefined): boolean {\n if (!only || only.length === 0) return true;\n const haystacks = [spec.id, caseLabel(spec), ...(spec.tags ?? [])].map((s) => s.toLowerCase());\n return only.some((needle) => {\n const n = needle.toLowerCase();\n return haystacks.some((h) => h.includes(n));\n });\n}\n\ninterface SubprocOutcome {\n exitCode: number;\n stdout: string;\n timedOut: boolean;\n}\n\nasync function runSubprocess(\n argv: string[],\n opts: { cwd?: string; env: Record<string, string | undefined>; timeoutMs: number },\n onLine: (line: string) => void\n): Promise<SubprocOutcome> {\n const proc = Bun.spawn(argv, {\n cwd: opts.cwd,\n env: opts.env,\n stdout: \"pipe\",\n stderr: \"pipe\",\n stdin: \"ignore\",\n });\n\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n proc.kill();\n }, opts.timeoutMs);\n\n const chunks: string[] = [];\n const pump = async (stream: ReadableStream<Uint8Array>): Promise<void> => {\n const decoder = new TextDecoder();\n let buffered = \"\";\n for await (const chunk of stream) {\n buffered += decoder.decode(chunk, { stream: true });\n let nl = buffered.indexOf(\"\\n\");\n while (nl !== -1) {\n const line = buffered.slice(0, nl);\n chunks.push(line);\n onLine(line);\n buffered = buffered.slice(nl + 1);\n nl = buffered.indexOf(\"\\n\");\n }\n }\n if (buffered) {\n chunks.push(buffered);\n onLine(buffered);\n }\n };\n\n await Promise.all([pump(proc.stdout), pump(proc.stderr)]);\n const exitCode = await proc.exited;\n clearTimeout(timer);\n\n return { exitCode, stdout: chunks.join(\"\\n\"), timedOut };\n}\n\nfunction parseSentinel(stdout: string): { pass: boolean; message?: string } | null {\n const idx = stdout.lastIndexOf(SENTINEL);\n if (idx === -1) return null;\n const after = stdout.slice(idx + SENTINEL.length);\n const newline = after.indexOf(\"\\n\");\n const json = newline === -1 ? after : after.slice(0, newline);\n try {\n const parsed = JSON.parse(json.trim());\n return { pass: Boolean(parsed.pass), message: parsed.message };\n } catch {\n return null;\n }\n}\n\ninterface Verdict {\n outcome: CaseOutcome;\n message?: string;\n}\n\nconst VERDICT_ICON: Record<CaseOutcome, string> = {\n pass: \"✓\",\n fail: \"✗\",\n skip: \"⊘\",\n timeout: \"⏱\",\n};\n\n/** Resolve argv + cwd for a case, falling back to the run-wide cwd. */\nfunction buildInvocation(\n spec: CaseSpec,\n worker: string,\n options: EngineOptions\n): { argv: string[]; cwd?: string } {\n if (spec.exec.kind === \"module\") {\n return { argv: [\"bun\", worker, spec.exec.modulePath, spec.id], cwd: options.cwd };\n }\n return { argv: spec.exec.argv, cwd: spec.exec.cwd ?? options.cwd };\n}\n\n/** Decide pass/fail/timeout, preferring the sentinel over the exit code. */\nfunction decideVerdict(spec: CaseSpec, result: SubprocOutcome, timeoutMs: number): Verdict {\n if (result.timedOut) return { outcome: \"timeout\", message: `timed out after ${timeoutMs}ms` };\n const sentinel = spec.exec.kind === \"module\" ? parseSentinel(result.stdout) : null;\n const pass = sentinel ? sentinel.pass : result.exitCode === 0;\n if (pass) return { outcome: \"pass\" };\n return { outcome: \"fail\", message: sentinel?.message ?? `exit code ${result.exitCode}` };\n}\n\nasync function runOneCase(\n spec: CaseSpec,\n tier: Tier,\n options: EngineOptions,\n worker: string\n): Promise<CaseReport> {\n const label = caseLabel(spec);\n const log = options.log ?? ((m: string) => console.log(m));\n\n const unmet = await firstUnmetNeed(spec.needs);\n if (unmet && !options.strictNeeds) {\n log(` ⊘ ${label} — skipped (needs ${unmet})`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: \"skip\",\n durationMs: 0,\n skipReason: `needs ${unmet}`,\n };\n }\n\n const timeoutMs = spec.timeoutMs ?? tier.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const env: Record<string, string | undefined> = { ...process.env, ...options.env };\n const { argv, cwd } = buildInvocation(spec, worker, options);\n\n const started = performance.now();\n const prefix = ` [${spec.id}] `;\n const result = await runSubprocess(argv, { cwd, env, timeoutMs }, (line) => {\n if (!line.includes(SENTINEL) && line.trim()) log(prefix + line);\n });\n const durationMs = Math.round(performance.now() - started);\n\n const verdict = decideVerdict(spec, result, timeoutMs);\n const tail = verdict.message ? ` — ${verdict.message}` : \"\";\n log(` ${VERDICT_ICON[verdict.outcome]} ${label} (${durationMs}ms)${tail}`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: verdict.outcome,\n durationMs,\n message: verdict.message,\n };\n}\n\nasync function runTier(tier: Tier, options: EngineOptions, worker: string): Promise<CaseReport[]> {\n const log = options.log ?? ((m: string) => console.log(m));\n const
|
|
11
|
-
"/**\n * Reporting for engine runs: a human summary table (with per-case timing and a\n * slowest-N list, the data the old `&&` chains never captured) and a JSON\n * artefact for tooling. No cloud reporters — everything lands on disk locally.\n */\nimport type { RunReport, TierPlan } from \"./types\";\n\nconst ICON = { pass: \"✓\", fail: \"✗\", skip: \"⊘\", timeout: \"⏱\" } as const;\n\n/** One-line-per-case summary plus totals and slowest cases. */\nexport function formatSummary(report: RunReport): string {\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(\"── results ─────────────────────────────────\");\n for (const c of report.cases) {\n const time = c.outcome === \"skip\" ? \"\" : `${c.durationMs}ms`;\n const tail = c.outcome === \"skip\" ? ` (${c.skipReason})` : c.message ? ` — ${c.message}` : \"\";\n lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${tail}`);\n }\n\n const ran = report.cases.filter((c) => c.outcome !== \"skip\");\n const slowest = [...ran].sort((a, b) => b.durationMs - a.durationMs).slice(0, 5);\n if (slowest.length > 0) {\n lines.push(\"\");\n lines.push(\"slowest:\");\n for (const c of slowest) lines.push(` ${c.durationMs}ms ${c.tier} › ${c.label}`);\n }\n\n lines.push(\"\");\n lines.push(\n `${report.ok ? \"PASS\" : \"FAIL\"} ${report.passed} passed, ${report.failed} failed, ` +\n `${report.skipped} skipped in ${(report.durationMs / 1000).toFixed(1)}s`\n );\n return lines.join(\"\\n\");\n}\n\n/** Stable JSON artefact written to test-results/. */\nexport function toJSON(report: RunReport): string {\n return JSON.stringify(report, null, 2);\n}\n\n/** `--list` output: tiers and their cases without running anything. */\nexport function formatPlan(plan: TierPlan): string {\n const lines: string[] = [\"Tiers (run order):\", \"\"];\n for (const tier of plan.tiers) {\n const conc = tier.concurrency && tier.concurrency > 1 ? ` ×${tier.concurrency}` : \"\";\n lines.push(`${tier.name}${conc}${tier.description ? ` — ${tier.description}` : \"\"}`);\n for (const c of tier.cases) {\n const needs = c.needs && c.needs.length > 0 ? ` (needs ${c.needs.join(\", \")})` : \"\";\n lines.push(` ${c.id}${needs}`);\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n"
|
|
11
|
+
"/**\n * The tiered test engine.\n *\n * Runs a {@link TierPlan} tier-by-tier in order. Within a tier, cases run with\n * bounded concurrency. Each case is its own subprocess (see worker.ts) so the\n * isolation the e2e scripts assume is preserved. Cases whose host needs are\n * unmet are skipped (logged), not failed, unless `strictNeeds` is set.\n */\nimport { firstUnmetNeed } from \"./detect\";\nimport { orderCases } from \"./order\";\nimport { SENTINEL } from \"./protocol\";\nimport type {\n CaseOutcome,\n CaseReport,\n CaseSpec,\n EngineOptions,\n RunReport,\n Tier,\n TierPlan,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\nasync function workerPath(): Promise<string> {\n const bundled = `${import.meta.dir}/worker.js`;\n const source = `${import.meta.dir}/worker.ts`;\n return (await Bun.file(bundled).exists()) ? bundled : source;\n}\n\nfunction caseLabel(spec: CaseSpec): string {\n return spec.label ?? spec.id;\n}\n\nfunction caseMatches(spec: CaseSpec, only: string[] | undefined): boolean {\n if (!only || only.length === 0) return true;\n const haystacks = [spec.id, caseLabel(spec), ...(spec.tags ?? [])].map((s) => s.toLowerCase());\n return only.some((needle) => {\n const n = needle.toLowerCase();\n return haystacks.some((h) => h.includes(n));\n });\n}\n\ninterface SubprocOutcome {\n exitCode: number;\n stdout: string;\n timedOut: boolean;\n}\n\nasync function runSubprocess(\n argv: string[],\n opts: { cwd?: string; env: Record<string, string | undefined>; timeoutMs: number },\n onLine: (line: string) => void\n): Promise<SubprocOutcome> {\n const proc = Bun.spawn(argv, {\n cwd: opts.cwd,\n env: opts.env,\n stdout: \"pipe\",\n stderr: \"pipe\",\n stdin: \"ignore\",\n });\n\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n proc.kill();\n }, opts.timeoutMs);\n\n const chunks: string[] = [];\n const pump = async (stream: ReadableStream<Uint8Array>): Promise<void> => {\n const decoder = new TextDecoder();\n let buffered = \"\";\n for await (const chunk of stream) {\n buffered += decoder.decode(chunk, { stream: true });\n let nl = buffered.indexOf(\"\\n\");\n while (nl !== -1) {\n const line = buffered.slice(0, nl);\n chunks.push(line);\n onLine(line);\n buffered = buffered.slice(nl + 1);\n nl = buffered.indexOf(\"\\n\");\n }\n }\n if (buffered) {\n chunks.push(buffered);\n onLine(buffered);\n }\n };\n\n await Promise.all([pump(proc.stdout), pump(proc.stderr)]);\n const exitCode = await proc.exited;\n clearTimeout(timer);\n\n return { exitCode, stdout: chunks.join(\"\\n\"), timedOut };\n}\n\nfunction parseSentinel(stdout: string): { pass: boolean; message?: string } | null {\n const idx = stdout.lastIndexOf(SENTINEL);\n if (idx === -1) return null;\n const after = stdout.slice(idx + SENTINEL.length);\n const newline = after.indexOf(\"\\n\");\n const json = newline === -1 ? after : after.slice(0, newline);\n try {\n const parsed = JSON.parse(json.trim());\n return { pass: Boolean(parsed.pass), message: parsed.message };\n } catch {\n return null;\n }\n}\n\ninterface Verdict {\n outcome: CaseOutcome;\n message?: string;\n}\n\nconst VERDICT_ICON: Record<CaseOutcome, string> = {\n pass: \"✓\",\n fail: \"✗\",\n skip: \"⊘\",\n timeout: \"⏱\",\n};\n\n/** Resolve argv + cwd for a case, falling back to the run-wide cwd. */\nfunction buildInvocation(\n spec: CaseSpec,\n worker: string,\n options: EngineOptions\n): { argv: string[]; cwd?: string } {\n if (spec.exec.kind === \"module\") {\n return { argv: [\"bun\", worker, spec.exec.modulePath, spec.id], cwd: options.cwd };\n }\n return { argv: spec.exec.argv, cwd: spec.exec.cwd ?? options.cwd };\n}\n\n/** Decide pass/fail/timeout, preferring the sentinel over the exit code. */\nfunction decideVerdict(spec: CaseSpec, result: SubprocOutcome, timeoutMs: number): Verdict {\n if (result.timedOut) return { outcome: \"timeout\", message: `timed out after ${timeoutMs}ms` };\n const sentinel = spec.exec.kind === \"module\" ? parseSentinel(result.stdout) : null;\n const pass = sentinel ? sentinel.pass : result.exitCode === 0;\n if (pass) return { outcome: \"pass\" };\n return { outcome: \"fail\", message: sentinel?.message ?? `exit code ${result.exitCode}` };\n}\n\nasync function runOneCase(\n spec: CaseSpec,\n tier: Tier,\n options: EngineOptions,\n worker: string\n): Promise<CaseReport> {\n const label = caseLabel(spec);\n const log = options.log ?? ((m: string) => console.log(m));\n\n const unmet = await firstUnmetNeed(spec.needs);\n if (unmet && !options.strictNeeds) {\n log(` ⊘ ${label} — skipped (needs ${unmet})`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: \"skip\",\n durationMs: 0,\n skipReason: `needs ${unmet}`,\n };\n }\n\n const timeoutMs = spec.timeoutMs ?? tier.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const env: Record<string, string | undefined> = { ...process.env, ...options.env };\n const { argv, cwd } = buildInvocation(spec, worker, options);\n\n const started = performance.now();\n const prefix = ` [${spec.id}] `;\n const result = await runSubprocess(argv, { cwd, env, timeoutMs }, (line) => {\n if (!line.includes(SENTINEL) && line.trim()) log(prefix + line);\n });\n const durationMs = Math.round(performance.now() - started);\n\n const verdict = decideVerdict(spec, result, timeoutMs);\n const tail = verdict.message ? ` — ${verdict.message}` : \"\";\n log(` ${VERDICT_ICON[verdict.outcome]} ${label} (${durationMs}ms)${tail}`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: verdict.outcome,\n durationMs,\n message: verdict.message,\n };\n}\n\nasync function runTier(tier: Tier, options: EngineOptions, worker: string): Promise<CaseReport[]> {\n const log = options.log ?? ((m: string) => console.log(m));\n const matched = tier.cases.filter((c) => caseMatches(c, options.only));\n if (matched.length === 0) return [];\n const selected = orderCases(matched, options.order ?? \"default\");\n\n log(\n `\\n▶ ${tier.name}${tier.description ? ` — ${tier.description}` : \"\"} (${selected.length} case${selected.length === 1 ? \"\" : \"s\"})`\n );\n\n const concurrency = Math.max(1, tier.concurrency ?? 1);\n const failFast = options.failFast ?? false;\n // Slots left empty when soft-fail-fast aborts before claiming them; filtered out below.\n const reports: (CaseReport | undefined)[] = new Array(selected.length);\n let next = 0;\n let aborted = false;\n async function worker_loop(): Promise<void> {\n while (!aborted) {\n const i = next++;\n const spec = selected[i];\n if (!spec) return;\n const report = await runOneCase(spec, tier, options, worker);\n reports[i] = report;\n if (failFast && (report.outcome === \"fail\" || report.outcome === \"timeout\")) {\n aborted = true; // soft: in-flight siblings finish, but no new case is claimed\n }\n }\n }\n await Promise.all(Array.from({ length: Math.min(concurrency, selected.length) }, worker_loop));\n const done = reports.filter((r): r is CaseReport => r !== undefined);\n if (aborted && done.length < selected.length) {\n log(\n ` ⏹ fail-fast: stopped after a failure — ${selected.length - done.length} case(s) not run`\n );\n }\n return done;\n}\n\n/** Run a plan and return a structured report. Does not exit the process. */\nexport async function runPlan(plan: TierPlan, options: EngineOptions = {}): Promise<RunReport> {\n const log = options.log ?? ((m: string) => console.log(m));\n const worker = await workerPath();\n const wanted = options.tiers && options.tiers.length > 0 ? new Set(options.tiers) : null;\n\n const started = performance.now();\n const stopOnFail = Boolean(options.bail || options.failFast);\n const all: CaseReport[] = [];\n for (const tier of plan.tiers) {\n if (wanted && !wanted.has(tier.name)) continue;\n const reports = await runTier(tier, options, worker);\n all.push(...reports);\n if (stopOnFail && reports.some((r) => r.outcome === \"fail\" || r.outcome === \"timeout\")) {\n log(\n `\\n⏹ ${options.failFast ? \"fail-fast\" : \"bail\"}: stopping after failing tier \"${tier.name}\"`\n );\n break;\n }\n }\n\n const durationMs = Math.round(performance.now() - started);\n const passed = all.filter((r) => r.outcome === \"pass\").length;\n const failed = all.filter((r) => r.outcome === \"fail\" || r.outcome === \"timeout\").length;\n const skipped = all.filter((r) => r.outcome === \"skip\").length;\n return { cases: all, passed, failed, skipped, durationMs, ok: failed === 0 };\n}\n",
|
|
12
|
+
"/**\n * Reporting for engine runs: a human summary table (with per-case timing and a\n * slowest-N list, the data the old `&&` chains never captured) and a JSON\n * artefact for tooling. No cloud reporters — everything lands on disk locally.\n */\nimport type { RunReport, TierPlan } from \"./types\";\n\nconst ICON = { pass: \"✓\", fail: \"✗\", skip: \"⊘\", timeout: \"⏱\" } as const;\n\n/** One-line-per-case summary plus totals and slowest cases. */\nexport function formatSummary(report: RunReport): string {\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(\"── results ─────────────────────────────────\");\n for (const c of report.cases) {\n const time = c.outcome === \"skip\" ? \"\" : `${c.durationMs}ms`;\n const tail = c.outcome === \"skip\" ? ` (${c.skipReason})` : c.message ? ` — ${c.message}` : \"\";\n lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${tail}`);\n }\n\n const ran = report.cases.filter((c) => c.outcome !== \"skip\");\n const slowest = [...ran].sort((a, b) => b.durationMs - a.durationMs).slice(0, 5);\n if (slowest.length > 0) {\n lines.push(\"\");\n lines.push(\"slowest:\");\n for (const c of slowest) lines.push(` ${c.durationMs}ms ${c.tier} › ${c.label}`);\n }\n\n lines.push(\"\");\n lines.push(\n `${report.ok ? \"PASS\" : \"FAIL\"} ${report.passed} passed, ${report.failed} failed, ` +\n `${report.skipped} skipped in ${(report.durationMs / 1000).toFixed(1)}s`\n );\n return lines.join(\"\\n\");\n}\n\n/** Stable JSON artefact written to test-results/. */\nexport function toJSON(report: RunReport): string {\n return JSON.stringify(report, null, 2);\n}\n\n/** `--list` output: tiers and their cases without running anything. */\nexport function formatPlan(plan: TierPlan): string {\n const lines: string[] = [\"Tiers (run order):\", \"\"];\n for (const tier of plan.tiers) {\n const conc = tier.concurrency && tier.concurrency > 1 ? ` ×${tier.concurrency}` : \"\";\n lines.push(`${tier.name}${conc}${tier.description ? ` — ${tier.description}` : \"\"}`);\n for (const c of tier.cases) {\n const needs = c.needs && c.needs.length > 0 ? ` (needs ${c.needs.join(\", \")})` : \"\";\n const cost = c.cost ? ` [${c.cost}]` : \"\";\n lines.push(` ${c.id}${cost}${needs}`);\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n"
|
|
12
13
|
],
|
|
13
|
-
"mappings": "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",
|
|
14
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "12E113E54144234E64756E2164756E21",
|
|
15
16
|
"names": []
|
|
16
17
|
}
|
|
@@ -10,5 +10,6 @@ export { DEFAULT_JSON, parseTierArgs, type TierArgs } from "./args";
|
|
|
10
10
|
export { firstUnmetNeed, hasNeed } from "./detect";
|
|
11
11
|
export { discoverPlan } from "./discover";
|
|
12
12
|
export { runPlan } from "./engine";
|
|
13
|
+
export { orderCases } from "./order";
|
|
13
14
|
export { formatPlan, formatSummary, toJSON } from "./reporter";
|
|
14
|
-
export type { CaseExec, CaseReport, CaseSpec, EngineOptions, Need, RunReport, Tier, TierPlan, } from "./types";
|
|
15
|
+
export type { CaseExec, CaseOrder, CaseReport, CaseSpec, EngineOptions, Need, RunReport, Tier, TierPlan, } from "./types";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Within-tier case ordering.
|
|
3
|
+
*
|
|
4
|
+
* The engine drains a tier's cases through a bounded pool in array order, so
|
|
5
|
+
* where a case sits decides when it launches. Reordering by a coarse cost hint
|
|
6
|
+
* buys two different things depending on intent:
|
|
7
|
+
*
|
|
8
|
+
* - "cost" (heaviest first): the long poles launch in the first `concurrency`
|
|
9
|
+
* slots and everything cheaper packs in behind them, so wall-clock collapses
|
|
10
|
+
* toward the single slowest case instead of the sum. Use for a full run.
|
|
11
|
+
* - "fast" (lightest first): cheap, high-signal cases run first, so under
|
|
12
|
+
* soft-fail-fast they trip the abort soonest — you can't un-spawn a 4-minute
|
|
13
|
+
* case, so you want it to *not* have started when a 2-second case fails.
|
|
14
|
+
* - "default": registry definition order, unchanged.
|
|
15
|
+
*
|
|
16
|
+
* Pure and dependency-free on purpose: this is the one piece of the engine that
|
|
17
|
+
* is worth unit-testing in isolation, and keeping it out of engine.ts keeps the
|
|
18
|
+
* subprocess-heavy engine off the unit-coverage table.
|
|
19
|
+
*/
|
|
20
|
+
import type { CaseOrder, CaseSpec } from "./types";
|
|
21
|
+
/**
|
|
22
|
+
* Return a copy of `cases` reordered per `order`. Stable: cases of equal weight
|
|
23
|
+
* keep their original relative order, and "default" returns the input as-is.
|
|
24
|
+
*/
|
|
25
|
+
export declare function orderCases(cases: CaseSpec[], order: CaseOrder): CaseSpec[];
|
|
@@ -39,6 +39,11 @@ export interface CaseSpec {
|
|
|
39
39
|
needs?: Need[];
|
|
40
40
|
/** Per-case timeout. Defaults to the engine's tier default. */
|
|
41
41
|
timeoutMs?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Coarse cost hint consumed by `--order` (see order.ts). Unset = "medium".
|
|
44
|
+
* A scheduling hint, not a measurement — tune from `--json` durations.
|
|
45
|
+
*/
|
|
46
|
+
cost?: "light" | "medium" | "heavy";
|
|
42
47
|
exec: CaseExec;
|
|
43
48
|
}
|
|
44
49
|
/** An ordered group of cases sharing a realism level. */
|
|
@@ -57,6 +62,8 @@ export interface TierPlan {
|
|
|
57
62
|
tiers: Tier[];
|
|
58
63
|
}
|
|
59
64
|
export type CaseOutcome = "pass" | "fail" | "skip" | "timeout";
|
|
65
|
+
/** How cases are ordered within a tier before the pool drains them. */
|
|
66
|
+
export type CaseOrder = "default" | "fast" | "cost";
|
|
60
67
|
export interface CaseReport {
|
|
61
68
|
tier: string;
|
|
62
69
|
id: string;
|
|
@@ -81,8 +88,16 @@ export interface EngineOptions {
|
|
|
81
88
|
tiers?: string[];
|
|
82
89
|
/** Only run cases whose id/label/tags match one of these substrings. */
|
|
83
90
|
only?: string[];
|
|
91
|
+
/** Order cases within each tier. Default "default" (definition order). */
|
|
92
|
+
order?: CaseOrder;
|
|
84
93
|
/** Stop after the first tier that has a failure. */
|
|
85
94
|
bail?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Soft fail-fast: on the first failing case, the tier's pool stops *claiming*
|
|
97
|
+
* new cases (in-flight ones finish) and the run stops after that tier. Unlike
|
|
98
|
+
* `bail`, which lets every case in the failing tier finish first.
|
|
99
|
+
*/
|
|
100
|
+
failFast?: boolean;
|
|
86
101
|
/** Treat unmet-need skips as failures (CI-strict). Default false. */
|
|
87
102
|
strictNeeds?: boolean;
|
|
88
103
|
/** Forwarded into each case's environment. */
|