fix(ci): a node test step with an unmatched glob is a gate that gates nothing (improvise-vz54)

Under bash an unmatched glob survives as a literal; node 22+ globs the literal
itself, matches nothing, reports 0 tests and exits 0. Both CI node steps -- the
`js` job and the browser job's bundle suite -- were exposed: rename or move
either directory and the step goes green having asserted nothing. Reproduced
under `bash -e`, which is the shell CI names; zsh ABORTS on an unmatched glob,
so the failure is invisible from a developer's shell.

The glob becomes the script's rather than the shell's. scripts/node-test.sh
expands it, refuses an empty match, and also refuses a matched file that
declares no test -- checked LEXICALLY, because node reports such a file as one
passing test named after the file, so the `# tests N` a minimum-count assertion
would read is the FILE count and is satisfied by the offender. Measured on node
24.20.

scripts/node-test-test.sh proves each refusal by injecting its fault, including
that the wrapper does not buy its refusals by swallowing a real failure, and
runs in the `js` job: a check wired into nothing is a convention.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-20 16:30:47 -07:00
parent 00f7678822
commit ea347ccab4
3 changed files with 152 additions and 3 deletions
+10 -3
View File
@@ -218,10 +218,17 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
# The glob is the SHELL's, not node's: `web/tests/bundle/` needs a built
# The glob is the SCRIPT's, not the shell's and not node's. Under bash an
# unmatched glob survives as a literal, node globs it, matches nothing and
# exits 0 having run no test -- so this step gated nothing the moment
# `web/tests/` moved (improvise-vz54). `web/tests/bundle/` needs a built
# wasm bundle and runs in the browser job instead.
- name: What the page decides between its boundaries
run: node --test web/tests/*.test.js
run: ./scripts/node-test.sh 'web/tests/*.test.js'
# The guard above is only worth its line if its refusals are themselves
# checked -- the step it replaces was green while asserting nothing.
- name: The node test runner refuses what it claims to
run: ./scripts/node-test-test.sh
kb:
name: Knowledge base consistency
@@ -349,7 +356,7 @@ jobs:
# runs here rather than in the `js` job, and before Playwright — a
# renamed export is cheaper to read here than as a blank page.
- name: The page's calls match the bundle it calls
run: node --test web/tests/bundle/*.test.js
run: ./scripts/node-test.sh 'web/tests/bundle/*.test.js'
- name: Run the harness
working-directory: harness
run: npx playwright test