fix(test-vendor): repair a poisoned bundle, track all bundle inputs, pin esbuild

Follow-ups to #241 (thanks @Lint111), from an independent review of that PR. The
script is a real fix for a real gap; these are the four defects the review found,
each reproduced before and after.

1. A wrong-but-fresh output was never repaired. The zerolag bundle is finished by a
   SECOND step (the alias append), so anything landing between esbuild and the
   append is permanent: the file looks complete, carries a current mtime, and the
   mtime-only cache reports "up to date" forever while the suite dies on
   `LocalEchoOverlay is not defined`. Reproduced by replaying #241's own two
   commits: running the first and then pulling the second kept the broken bundle.
   Fixed twice over, because the two halves address different cases. Builds now go
   to a temp file and `renameSync` into place, so this script can never publish a
   half-written output (that also covers an interrupted esbuild or copy, and two
   concurrent runs). And `isFresh` verifies the bundle actually contains its alias
   tail, which is what repairs a file an EARLIER version already poisoned; a rename
   alone cannot fix what is already on disk.

2. Freshness compared against the entry file only, but esbuild bundles its four
   siblings too, so editing overlay-renderer.ts left the suite testing a stale
   overlay while reporting "up to date". Editing those siblings is exactly the
   single-source workflow CLAUDE.md mandates. It now stats every `.ts` in the
   package source dir. A full rebuild is ~2s, so the cache was not buying much.

3. `execFileSync('npx', ...)` passed no cwd, unlike scripts/build.mjs, so a run from
   another directory missed the repo's pinned esbuild and would fetch an unpinned
   one from the registry. Both calls now pass `cwd: ROOT`.

4. Every invocation in test/mobile/README.md was a bare `npx vitest`, which skips
   the `pretest:mobile` hook npm only fires for `npm run test:mobile`, so the
   documented commands all bypassed the fix. Rewritten, with a note on why.

Also: an esbuild failure printed a raw stack; it now names the asset and its input,
matching the missing-input message. And the header comment no longer implies the
vendor dir is always empty: scripts/postinstall.js already writes these same seven
outputs, so what this script adds is freshness and independence from install time.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-09 12:13:18 +02:00
parent 341c7ccc59
commit a15b81db77
2 changed files with 107 additions and 30 deletions
+14 -6
View File
@@ -16,22 +16,30 @@ Validates Codeman's mobile UI across 136 devices, covering:
## Quick Start
⚠️ Go through `npm run test:mobile`, not `npx vitest` directly. The suite serves the
page from `src/web/public`, but `npm run build` puts the xterm vendor bundles in
`dist/web/public`, so without them every `/vendor/xterm*` request 404s, `Terminal` is
never defined and every test touching `app.terminal` fails on a null. The
`pretest:mobile` hook (`scripts/prepare-test-vendor.mjs`) is what puts them in place,
and npm only fires it for `npm run test:mobile`. Run the prepare script by hand first
if you really need a bare `npx vitest`.
```bash
# Run all mobile tests
npx vitest run --config test/mobile/vitest.config.ts
npm run test:mobile
# Run a single test file
npx vitest run --config test/mobile/vitest.config.ts test/mobile/keyboard.test.ts
npm run test:mobile -- test/mobile/keyboard.test.ts
# Quick mode — 6 representative devices, skip full matrix
CI_QUICK=1 npx vitest run --config test/mobile/vitest.config.ts
# Quick mode: 6 representative devices, skip full matrix
CI_QUICK=1 npm run test:mobile
# Full device matrix only (136 devices)
npx vitest run --config test/mobile/vitest.config.ts test/mobile/device-matrix.test.ts
npm run test:mobile -- test/mobile/device-matrix.test.ts
# Update visual baselines (delete old baselines, re-run)
rm -rf test/mobile/snapshots/*.png
npx vitest run --config test/mobile/vitest.config.ts test/mobile/visual-regression.test.ts
npm run test:mobile -- test/mobile/visual-regression.test.ts
```
## Test Files