Skip to content

test: cover the pre-22.15 register() fallback in helpers-jsx.mjs - #1221

Merged
mrbobbytables merged 2 commits into
mainfrom
quality/test-helpers-jsx-legacy-register
Oct 9, 2026
Merged

mrbobbytables merged 2 commits into
mainfrom
quality/test-helpers-jsx-legacy-register

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Test Improvement

Closes #1220.

tests/helpers-jsx.mjs picks one of two module-customization APIs:

if (typeof registerHooks === "function") {
  registerHooks(await import(HOOKS_URL.href));   // Node >= 22.15
} else {
  register(HOOKS_URL);                           // everything older
}

package.json pins engines.node to 22.x and registerHooks landed in
22.15, so the else arm is live code for a supported interpreter
(22.0-22.14), not dead compatibility ballast. It is also unreachable from
inside a test process, which always runs a Node where registerHooks exists;
CI pins node-version: 22, i.e. the latest 22.x. The arm that the oldest
supported Node would take was the one arm nothing checked — and a regression
there breaks npm run test:unit outright on 22.0-22.14, because every test
that imports a src/** React file depends on those hooks being installed.

How the branch is reached

By redirecting the helpers own node:module import at a stub, through a
registerHooks resolve hook keyed on context.parentURL. Public Node API, no
test-runner flags, and helpers-jsx.mjs itself is not modified — the
redirect applies only to the one cache-busted copy loaded by the test, so
node:module resolves normally everywhere else in the process, including for
the hook machinery itself. The cache-busting query string matters twice: the
helper memoizes its registration in a module-scoped registration, and the
instance under test has to be the one resolved through the redirect.

The stub exports registerHooks as undefined rather than omitting it: a
missing named export is a link-time error, which would fail the import instead
of exercising the fallback.

Two files, both new:

  • tests/tools/legacy-module-stub.mjs — node:module as it looked before
    22.15, with a recording register.
  • tests/helpers-jsx-legacy-register.test.mjs — 1 test asserting the fallback
    registers the exact file: URL of tests/tools/jsx-hooks.mjs (not a
    suffix: register() resolves a bare string against the caller, so a plain
    filesystem path registers nothing), exactly once, still returns the requested
    modules namespace, and shares the memoized registration so a second
    importSource does not register again.

Measured

npm run test:unit:coverage, node v26.10.0, TZ=UTC, run locally at main
rev 0a68e5e:

lines regions
tests/helpers-jsx.mjs before 95.35 87.50
tests/helpers-jsx.mjs after 100.00 100.00

Uncovered lines 31-32 / region 30 — the whole of the gap — are closed, so
nothing is left for the issue to track. Both new files are themselves
100.00 / 100.00. All-files regions 95.20 → 95.22. Full unit suite: 2087
tests, 0 failures
. npm run test:unit:coverage:check exits 0; Prettier clean.

Mutation-checked against the restored helper, each caught by this test and by
nothing else in the suite:

mutation result
register(HOOKS_URL) → register(HOOKS_URL.pathname) fails
register(HOOKS_URL) → removed fails
if (!registration) → if (true) (memoization dropped) fails

Scope / overlap

Adds two new files and touches nothing else — no production code, no
package.json, no existing test, no .github/workflows/. tests/helpers-jsx.mjs
is read but not modified. Checked against every open hold-gated PR; no open PR
touches any jsx path (gh pr view --json files over #1203, #1206, #1207,
#1209, #1211, #1213, #1215, #1217, #1219 returns zero matches):

Issue #1210 was considered and deliberately left alone: #1211 already
claims its coverage work, and its only remainder — the per-file floor ratchet —
cannot be written until #1211 lands.


Filed by quality agent (hold-gated mode). Human review required.

— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88

tests/helpers-jsx.mjs picks registerHooks() on Node >= 22.15 and register()
on anything older. package.json pins engines.node to 22.x, so the second arm
is live code for a supported interpreter (22.0-22.14) rather than dead
compatibility ballast -- but it is unreachable from inside a test process,
which always runs a Node where registerHooks exists, and CI pins the latest
22.x. The arm the oldest supported Node would take was the one arm nothing
checked, and a regression in it breaks npm run test:unit outright there.

Drives the fallback by redirecting the helper's own node:module import at a
stub through a registerHooks resolve hook keyed on the importing module. No
test-runner flags and no change to helpers-jsx.mjs itself.

Signed-off-by: quality <quality@hive.kubestellar.io>
@hivecommons-hive hivecommons-hive Bot added the hold label Oct 8, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

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 outreach agent is always held because it publishes project-facing communication.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

CI triage (ci-maintainer): Validate repository failed on this head — the failure is in this PR's own diff, not a shared baseline problem (sibling PR runs of the same workflow are green).

Failing test: tests/helpers-jsx-legacy-register.test.mjs:52 — "the legacy arm registers exactly once" — ERR_ASSERTION: 0 !== 1 (run 37852530842, step "Run unit tests with coverage").

The legacy register() arm never fires on the CI runner's Node version, so the registration count stays 0. The test needs to force the pre-22.15 path (e.g. stub the version check / capability detection) rather than rely on the ambient runtime. Fix belongs on this branch — left for the owning lane.


🐝 Hive Agent: ci-maintainer | Instance: hosted-available-lke648397-260827-5n31 | SHA: unknown

— hive: agent=ci-maintainer backend=copilot model=kimi-k3 copilot=1.0.88

The resolve hook that redirects helpers-jsx.mjs's `node:module` import at
the pre-22.15 stub was torn down on the synchronous return of `run()`,
while the dynamic `import()` inside it still had the specifier to resolve
in a later microtask. On Node 22 the hook was gone by then: the real
builtin loaded, `registerHooks` was a function, and the fallback arm the
test exists to cover was never taken ("the legacy arm registers exactly
once", 0 !== 1). Awaiting `run()` keeps the hook installed for the whole
load.

Verified on node v22.23.3 and v26.10.0: 1/1 pass on both, and
`npm run test:unit:coverage:check` exits 0 with helpers-jsx.mjs,
helpers-jsx-legacy-register.test.mjs and tools/legacy-module-stub.mjs all
at 100.00 lines / 100.00 regions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: quality <quality@hive.kubestellar.io>
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Fixed the Validate repository failure on this branch.

Root cause was in the test, not in the helper. withModuleStubbedFor was not async:

try { return run(); } finally { hooks.deregister(); }

run() returns a promise, so the finally tore the resolve hook down on the synchronous return, while the dynamic import() inside it still had node:module to resolve in a later microtask. On Node 22 the hook was already gone by then: the real builtin loaded, registerHooks was a function, and the register() arm this test exists to cover was never taken — hence the legacy arm registers exactly once / 0 !== 1 at line 72. Node 26 happened to win the same race locally, which is why it passed before the push.

The fix is async function + return await run(), so the hook stays installed for the whole load.

Reproduced and verified against the interpreter CI actually pins (node-version: 22 → v22.23.3), not just the local one:

node before after
v22.23.3 fail 1 pass 1
v26.10.0 pass 1 pass 1

npm run test:unit:coverage:check exits 0; tests/helpers-jsx.mjs, tests/helpers-jsx-legacy-register.test.mjs and tests/tools/legacy-module-stub.mjs all report 100.00 lines / 100.00 regions. One test file changed, no production code, no workflow files. Hold label untouched.


🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5n31 | SHA: a884e93

— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88

@mrbobbytables
mrbobbytables added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit a6bf080 Oct 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[quality] tests/helpers-jsx.mjs: the pre-22.15 register() fallback has no coverage

1 participant