chore(web): declare the Node floor the test environment actually needs - #321
Merged
Conversation
Running `bun run test` on Node 20.18 fails to load the jsdom environment, and the error names neither Node nor jsdom: Error: require() of ES Module .../@exodus/bytes/encoding-lite.js from .../html-encoding-sniffer/lib/html-encoding-sniffer.js not supported. jsdom 29 pulls html-encoding-sniffer 6, which is CommonJS and requires @exodus/bytes — an ESM-only package. That only works where require(esm) is unflagged: Node 20.19.0+ or 22.12.0+. CI is on a new enough runtime, so this never showed up there; a local Node one patch below the line loses the whole jsdom test environment. The failure mode is what makes this worth a field rather than a README line: vitest reports the six jsdom-based suites as an "unhandled error" while still printing `Test Files 12 passed`, so the run LOOKS green even though every component test — App.esc, BlackboardDrawer, NewSessionModal, PackBrowser, SessionControls, SessionListPane — silently did not run. The exit code is 1, so CI is honest; a human reading the summary is the one who gets misled. Declaring the floor turns that into an install-time warning naming the real requirement. No dependency or lockfile change: nothing is broken in CI, and pinning around a working setup to suit an old local runtime would be the wrong trade. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
akhiljavelin
approved these changes
Sep 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The symptom
bun run testinweb/on Node 20.18 dies with an error that names neither Node nor jsdom:The cause
jsdom@29pullshtml-encoding-sniffer@6, which is CommonJS and doesrequire("@exodus/bytes/encoding-lite.js").@exodus/bytes@1.15.1is"type": "module"— ESM-only.That combination only works where
require(esm)is unflagged: Node 20.19.0+ or 22.12.0+ (backported to 20.19). CI runs a new enough runtime, so it has never surfaced there. A local Node one patch below the line loses the entire jsdom test environment.Why a field rather than a README line
The failure mode is quiet in the place people look. Vitest reports the six jsdom suites as an "unhandled error" while still printing:
So the run looks green while every component test silently did not run —
App.esc,BlackboardDrawer,NewSessionModal,PackBrowser,SessionControls, andSessionListPane.The exit code is 1, so CI stays honest. It's the human reading the summary who gets misled — which is exactly how I nearly shipped #320 believing its component test had run.
What this does not do
No dependency or lockfile change. Nothing is broken in CI, and pinning around a working setup to accommodate an old local runtime would be the wrong trade. This only makes the existing requirement explicit, so
npm installwarns with the real reason instead of surfacing an ESM/CJS stack trace later.>=20.19rather than>=22deliberately: 20.19 is the actual boundary, and there's no reason to exclude a working LTS.🤖 Generated with Claude Code