HarperFast / HarperFast/studio
vitest exits 1 with all 2955 tests passing — an undici WebSocket dispatches a Node Event into the jsdom realm after teardown
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 4
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 40
Description
## What
`vitest run` intermittently exits **1** with every test passing:
```
Test Files 340 passed (340)
Tests 2955 passed | 11 skipped (2966)
Errors 1 error
```
The error is an uncaught exception outside any test:
```
⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯
TypeError: The "event" argument must be an instance of Event. Received an instance of Event
❯ WebSocket.dispatchEvent node:internal/event_target:784:13
❯ fireEvent undici@8.9.0/lib/web/websocket/util.js:69:10
❯ WebSocket.#onConnectionEstablished undici@8.9.0/lib/web/websocket/websocket.js:507:5
❯ Object.onConnectionEstablished undici@8.9.0/lib/web/websocket/websocket.js:77:85
❯ Object.processResponse undici@8.9.0/lib/web/websocket/connection.js:214:15
❯ undici@8.9.0/lib/web/fetch/index.js:1119:19
❯ processTicksAndRejections node:internal/process/task_queues:104:5
Serialized Error: { code: 'ERR_INVALID_ARG_TYPE' }
This error originated in "src/features/instance/applications/components/Chat/components/ToolCallGroup.test.tsx"
```
"Received an instance of Event" for an argument that "must be an instance of Event" is the
signature of two different `Event` constructors in one realm: undici's WebSocket builds its event
with the **Node** global, while the jsdom test environment installs jsdom's `Event`, and
`EventTarget.dispatchEvent` then rejects it on an `instanceof` check.
## Why it is a problem
Vitest's exit code is 1 whenever an unhandled error is reported, so **CI fails a run in which
every assertion passed**, and the failure moves between runs. It also means a genuine unhandled
error in this file would be indistinguishable from the flake.
Vitest's own warning names the second risk:
> This might cause false positive tests. Resolve unhandled errors to make sure your tests are not
> affected.
## Reproduction
Not deterministic — it depends on whether the socket connects before the worker tears down. Seen
twice in the same session on `stage` + an unrelated branch, and clean on the immediately following
re-run both times, so roughly one run in three locally under Node 24.19.0.
```bash
npx vitest run
```
The file alone always passes (`npx vitest run src/features/instance/applications/components/Chat/components/ToolCallGroup.test.tsx`),
which points at the shared-realm interaction rather than the test's own logic.
## Where to look
Something in the `Chat` tree reaches a real `WebSocket` during that test — the test does not mock
one, so a component or hook it renders is opening a connection that outlives the test. Two
plausible fixes, in order of preference:
1. **Stop the connection being opened at all** in the test — mock the module that constructs the
socket. A unit test for tool-call grouping should not need a live transport.
2. Failing that, ensure it is closed in an `afterEach`, so nothing dispatches after teardown.
Not found by this issue's author in the failing file itself, hence "where to look" rather than a
patch.
## Context
Noticed while running the gate for #1685's PR, which does not touch this file or anything it
imports.
Contributor guide
Research direction
Start with src/features/instance/applications/components/Chat/components/ToolCallGroup.test.tsx and run npx vitest run to reproduce the intermittent failure. Trace the Chat tree imports to find the component or hook opening the real WebSocket, then inspect its test cleanup. Done means the full suite has no uncaught error or exit-code failure while the grouping test still passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- frontend, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100