test: resolve the test harness repo root with fileURLToPath and cover the fixture-sandbox contract - #354
Conversation
tests/helpers.mjs and tests/validators-smoke.test.mjs both derived the repository root from URL.prototype.pathname, which stays percent-encoded. On a checkout whose path contains a space the root resolved to a directory that does not exist and all 55 tests failed in cpSync with ENOENT before any script under test was spawned. Resolve the root with fileURLToPath instead, and export the resolution so it can be asserted directly. Add tests/helpers.test.mjs covering the fixture-sandbox contract, which had no tests of its own even though every fixture-based validator test runs through it: percent-decoded root resolution, scripts/lib mirroring, nested fixture placement, isolation from the real repository, isolation between runs, temp-directory cleanup, and distinct reporting of status, stdout and stderr. Signed-off-by: kubestellar-hive[bot] <kubestellar-hive@hive.kubestellar.io>
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Non-outreach agents are held at ACMM L3–L5; the Hive will automatically remove the |
The cleanup assertion counted endusers-test-* entries in the shared temp directory before and after a run. node --test executes test files in parallel processes, so a sandbox created and removed by another file changes that count mid-assertion; CI failed with 1 !== 2 against a harness that cleans up correctly. Recover the sandbox path from the ENOENT the fixture-less run emits and assert that exact directory is gone, which is independent of concurrent runs. Signed-off-by: kubestellar-hive[bot] <kubestellar-hive@hive.kubestellar.io>
|
CI triage: the Root cause was in this PR's own new assertion, not in the harness under test. Fixed in c96210b by pinning the assertion to this run's own sandbox: the fixture-less run dies with an ENOENT naming its sandbox path, and the test asserts that exact directory no longer exists. That is independent of concurrent runs. Verified at node v26.8.2:
|
Test Improvement
Claims exactly three files:
tests/helpers.mjs(the module-levelrepoRootconstant only),
tests/validators-smoke.test.mjs, and a newtests/helpers.test.mjs. Cluster: the fixture-sandbox harness contract.The break
Both
tests/helpers.mjs:6andtests/validators-smoke.test.mjs:6derived therepository root from
URL.prototype.pathname, which stays percent-encoded.On a checkout whose path contains a space the root resolved to
/tmp/space%20dir/repo/— a directory that does not exist — so every sandboxrun died in
cpSyncwithENOENTbefore the script under test was everspawned:
~/My Documents/,/Users/jane doe/andC:\Users\...\My Repos\are allordinary developer layouts. This resolves the root with
fileURLToPathinstead, and exports the resolution so it can be asserted directly rather than
only observed through a downstream
ENOENT.The missing coverage
runScriptWithFixturesis the single point every fixture-based validator testruns through, and nothing exercised it. A regression in the harness degrades
those suites rather than failing them — a sandbox that quietly read the real
repository would make every "rejects X" assertion pass for the wrong reason,
and no assertion anywhere would notice.
tests/helpers.test.mjspins the contract in both directions: percent-decodedroot resolution,
scripts/libmirroring (so anERR_MODULE_NOT_FOUNDcannever masquerade as a rejected fixture), nested fixture placement, isolation
from the real repository, isolation between successive runs, temp-directory
cleanup, and distinct reporting of
status/stdout/stderr.Verification
Revision
00b44df, node v26.8.2, 2026-09-20./tmp/space dir/The one test still failing under a spaced path is
validate-architectures.mjs passes against current repo data, which is theproduction half of the same defect — six
scripts/*.mjsfiles carry theidentical
.pathnameline. That half is not in this PR: it is productioncode under
scripts/, which the quality lane cannot push. It is filed withexact replacement text as #353 and needs a human or an agent whose lane can
touch
scripts/to land it.Falsification check: reverting
resolveRepoRootto.pathnamefails exactlythe new percent-decoding assertion (8 tests, 7 pass, 1 fail), so the new test
cannot pass vacuously.
prettier --checkclean on all three files.Disjointness from open PRs
tests/helpers.mjs. It extendsrunScriptWithFixtureswithoptions.argsandoptions.readBackand leavesline 6 untouched. This PR changes the module-level
repoRootconstant andadds a new import from
node:url; it does not alter the function's signatureor body. Different invariant, no competing implementation. If [quality] test: cover validate-architecture-assets.mjs --fix write mode (tests/helpers.mjs args/readBack + tests/validate-architecture-assets.test.mjs) #231 lands
first, the only interaction is a trivial import-block rebase.
tests/tools/coverage-report.mjsfor coverage attribution ofsandbox runs ([quality] node --test coverage discards every fixture-sandbox run (reports 73.51%, true value 97.53%) #224); it does not test harness behaviour.
tests/helpers-*.mjssandboxes anddo not touch
tests/helpers.mjs.Related Issue
Closes #352 — merging this leaves nothing for #352 to track: it scopes only the
tests/half, and both of its boxes land here. Thescripts/half is trackedseparately as #353 and is deliberately out of scope for this lane.
Filed by quality agent (hold-gated mode). Human review required.
— hive: agent=quality backend=copilot model=claude-opus-5