← All decisions

Use a plain EventTarget for io's testing fallback, not jsdom

iotestingdomjsdom

Context

Testing io's keyboard/mouse polling for real (not mocked) needed a browser-less stand-in for `window`/addEventListener/dispatchEvent under Node. A full jsdom window polyfill (mirroring the pattern already used for webgpu) reliably hung or crashed the whole process whenever io's tests ran in the same gleeunit process as cs's WebGPU tests -- confirmed by isolation (io alone: fine; io+pe: fine; io+cs: broken every time).

Options considered

jsdom (full DOM polyfill) — rejected
Conflicted with the webgpu npm package's native addon when both ran in one process. Root cause not fully chased down, but also unnecessary: io never needed a full DOM, only addEventListener/dispatchEvent.
Node/Deno's built-in EventTarget + Event, with properties attached by hand (event.key = "a") — chosen
No npm package needed at all, and functionally identical for code that only ever reads plain data properties off an event -- which is all io's handlers do. Sidesteps the jsdom/webgpu conflict entirely rather than debugging it.

Decision

io_ffi.mjs uses `globalThis.window ?? new EventTarget()`; the jsdom devDependency was added then removed in the same work session.

Verification

10/10 clean runs after switching, versus reliable hangs/crashes with jsdom in the same process as cs's tests.

Consequences

General lesson applied elsewhere in this project since: prefer the lightest-weight real (not mocked) polyfill that satisfies the actual API surface used, not the most realistic/heaviest one available.

References