tests/configs/vitest.perf.config.ts (npm run test:perf) is a real gate, not a manual-only slot, so inGate() now recognizes its include list (tests/performance/** plus the four named files) directly. The 7 files already correctly listed as perf move out of MANUAL_ONLY, which is now reserved for files no automated lane covers. That alone left the guard red: tests/vfs/vfs-search-path-scope.test.ts was a genuine new orphan (added this cycle, named without the .unit.test.ts suffix its siblings use) — it ran under the broad root gate but silently missed test:unit. Renamed to match the sibling convention in tests/vfs/, which puts it back in the unit gate.
108 lines
5.1 KiB
TypeScript
108 lines
5.1 KiB
TypeScript
/**
|
|
* @module tests/unit/test-suite-coverage-guard
|
|
* @description Prevents a test file from silently falling outside EVERY vitest
|
|
* config (so it never runs and gives false coverage confidence — the exact drift
|
|
* that left ~27 test files un-run before 8.0). Every `*.test.ts` must either match
|
|
* a gate config (`tests/unit/**`, `tests/integration/**`, `*.unit.test.ts`,
|
|
* `*.integration.test.ts`, or the perf lane's `tests/configs/vitest.perf.config.ts`
|
|
* — see PERF_LANE_FILES below) or be explicitly listed in MANUAL_ONLY below.
|
|
*/
|
|
import { describe, it, expect } from 'vitest'
|
|
import { readdirSync } from 'node:fs'
|
|
import { join, relative, dirname } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../..')
|
|
const testsDir = join(repoRoot, 'tests')
|
|
|
|
function allTestFiles(dir: string, out: string[] = []): string[] {
|
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
const p = join(dir, e.name)
|
|
if (e.isDirectory()) allTestFiles(p, out)
|
|
else if (e.isFile() && p.endsWith('.test.ts')) out.push(relative(repoRoot, p).split('\\').join('/'))
|
|
}
|
|
return out
|
|
}
|
|
|
|
/**
|
|
* Test files INTENTIONALLY excluded from every automated gate — conformance
|
|
* suites invoked directly, and checks that need real resources (network,
|
|
* unusual scale) no CI lane provides. Wall-clock/scale benchmarks that DO
|
|
* run automatically belong to the perf lane (PERF_LANE_FILES / inGate
|
|
* below), not here. Every entry is a conscious decision — a NEW orphan not
|
|
* listed here fails the guard below.
|
|
*/
|
|
const MANUAL_ONLY = new Set<string>([
|
|
// Conformance suites run as an explicit gate stage (both engines run them
|
|
// by direct invocation), never swept into the unit/integration configs.
|
|
'tests/conformance/collider-fidelity.test.ts',
|
|
// Golden-log fold-conformance oracle: the two-implementation contract pin
|
|
// (byte + fold digests) — runs in the explicit conformance gate stage,
|
|
// same invocation family as the other conformance suites.
|
|
'tests/conformance/golden-log-fold.test.ts',
|
|
// The sparse-store cut's shared operator rows (both engines run these):
|
|
// explicit conformance-gate invocation, like its siblings.
|
|
'tests/conformance/sparse-store-cut.test.ts',
|
|
// NOT the perf lane: no wall-clock/scale assertion, so it does not belong
|
|
// in tests/configs/vitest.perf.config.ts's include list — genuinely run
|
|
// by hand only.
|
|
'tests/critical-neural-validation.test.ts',
|
|
'tests/package-size-breakdown.test.ts',
|
|
// Cross-engine field-addressing conformance suite: pinned bit-for-bit against
|
|
// the native accelerator's implementation of the SAME contract, and invoked
|
|
// directly (`npx vitest run tests/conformance/namespace-law.test.ts`), never
|
|
// swept into the unit/integration gates — a run against a branch where the
|
|
// resolver hasn't landed yet must SKIP loudly (see the file's own SELF-SKIP
|
|
// doc), not silently pass/fail as a side effect of which gate happened to
|
|
// pick it up.
|
|
'tests/conformance/namespace-law.test.ts'
|
|
])
|
|
|
|
/**
|
|
* The perf lane's own gate: `tests/configs/vitest.perf.config.ts`, run by
|
|
* `npm run test:perf`. Mirrors that config's `include` list — kept in sync
|
|
* by inspection, the same convention that config uses against the root
|
|
* gate's exclude list (see its own header comment). A file that runs here
|
|
* is GATED, not manual: it belongs in this set (or the `tests/performance/`
|
|
* prefix below), never in MANUAL_ONLY.
|
|
*/
|
|
const PERF_LANE_FILES = new Set<string>([
|
|
'tests/critical-performance-benchmark.test.ts',
|
|
'tests/api/performance-benchmarks.test.ts',
|
|
'tests/package-size-limit.test.ts',
|
|
'tests/model-loading.test.ts'
|
|
])
|
|
|
|
function inGate(rel: string): boolean {
|
|
return (
|
|
rel.startsWith('tests/unit/') ||
|
|
rel.startsWith('tests/integration/') ||
|
|
// The lifecycle biography lane — included by the integration config
|
|
// ('tests/lifecycle/**/*.test.ts'; see tests/lifecycle/README.md).
|
|
rel.startsWith('tests/lifecycle/') ||
|
|
rel.endsWith('.unit.test.ts') ||
|
|
rel.endsWith('.integration.test.ts') ||
|
|
// The perf lane (see PERF_LANE_FILES above) — mirrors
|
|
// tests/configs/vitest.perf.config.ts's `tests/performance/**` glob.
|
|
rel.startsWith('tests/performance/') ||
|
|
PERF_LANE_FILES.has(rel)
|
|
)
|
|
}
|
|
|
|
describe('test-suite coverage guard', () => {
|
|
it('every *.test.ts runs in a gate config or is explicitly allowlisted as manual', () => {
|
|
const orphans = allTestFiles(testsDir).filter((f) => !inGate(f) && !MANUAL_ONLY.has(f))
|
|
expect(
|
|
orphans,
|
|
'These test files match NO vitest config and are not in MANUAL_ONLY — rename to ' +
|
|
'*.unit.test.ts / *.integration.test.ts (or move under tests/unit|integration), or add to ' +
|
|
`MANUAL_ONLY if they are benchmarks:\n${orphans.join('\n')}`
|
|
).toEqual([])
|
|
})
|
|
|
|
it('the manual allowlist has no stale entries (every listed file still exists)', () => {
|
|
const all = new Set(allTestFiles(testsDir))
|
|
const stale = [...MANUAL_ONLY].filter((f) => !all.has(f))
|
|
expect(stale, `MANUAL_ONLY lists files that no longer exist — remove them:\n${stale.join('\n')}`).toEqual([])
|
|
})
|
|
})
|