Skip to content

test: check event streams against EventSource on Node, Deno and Bun - #137

Merged
dinwwwh merged 2 commits into
mainfrom
claude/sse-encoder-eventsource-e2e-e2b43f
Sep 30, 2026
Merged

dinwwwh merged 2 commits into
mainfrom
claude/sse-encoder-eventsource-e2e-e2b43f

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 30, 2026

Copy link
Copy Markdown
Member

Event streams from standard-server are now tested against a real EventSource client. A server built with standard-server streams events, and EventSource must receive the message, close and error events with the expected data. This catches encoder or adapter changes that would break browser-style SSE consumers.

Coverage

  • Node 20–26: sendStandardResponse with Node's built-in EventSource; both tests pass on Node 20, 24 and 26
  • Deno: toFetchResponse with Deno's built-in EventSource; both tests pass
  • Bun: toFetchResponse, skipped for now: bun-types declares EventSource, but Bun 1.4.2 has no runtime implementation. The tests start running on their own once Bun ships one

Notes for reviewers

  • Vitest workers now start with --experimental-eventsource, because Node 20–26 only expose the EventSource global behind that flag. The Node tests are skipped instead of failing if it is ever missing
  • No new dependencies
  • A generator that returns undefined sends a close event without data, which EventSource silently drops, so the client reconnects instead of seeing close. Both tests return a value; this is existing behavior, not changed here

A server built with standard-server now streams events to a real
EventSource, which must receive the message, close and error events.
Node and Deno use their built-in EventSource; the tests are skipped
where it is missing (Bun today).

Vitest workers start with --experimental-eventsource, since Node 20-26
only expose the EventSource global behind that flag.
@pkg-pr-new

pkg-pr-new Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
@standard-server/aws-lambda

npm i https://pkg.pr.new/@standard-server/aws-lambda@137

@standard-server/core

npm i https://pkg.pr.new/@standard-server/core@137

@standard-server/fastify

npm i https://pkg.pr.new/@standard-server/fastify@137

@standard-server/fetch

npm i https://pkg.pr.new/@standard-server/fetch@137

@standard-server/node

npm i https://pkg.pr.new/@standard-server/node@137

@standard-server/peer

npm i https://pkg.pr.new/@standard-server/peer@137

@standard-server/shared

npm i https://pkg.pr.new/@standard-server/shared@137

commit: c755bc5

@codecov

codecov Bot commented Sep 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 108 skipped benchmarks1


Comparing claude/sse-encoder-eventsource-e2e-e2b43f (c755bc5) with main (2090fb0)

Open in CodSpeed

Footnotes

  1. 108 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — one coverage observation and one documentation nit.

Reviewed changes

  • Node, Deno and Bun EventSource e2e tests — tests/event-source.test.ts (root), tests/bun/tests/event-source.test.ts, and tests/deno/tests/event-source.test.ts stand up a server via sendStandardResponse / toFetchResponse, stream an async generator, and assert that a real EventSource observes the message, close, and error events with their exact JSON payloads.
  • vitest.config.ts — adds test.execArgv: ['--experimental-eventsource'], the flag Node 20–26 requires to expose the built-in EventSource global; the Node test self-skips if the global is absent.

ℹ️ The typical generator-completion path is both untested and EventSource-incompatible

The tests only assert a generator that returns a value (return 'bye'), because a generator that completes with no value encodes event: close with no data: line — EventSource discards a data-less event and reconnects, so the client never sees close and the test would hang. Finishing without a value is the normal way an event stream ends, so the one path most user handlers take is exactly the case these tests cannot assert. The PR body documents this, but the test files do not.

Technical details
# Default completion emits a data-less close that EventSource ignores

## Affected sites
- `tests/event-source.test.ts:43-46`, `tests/bun/tests/event-source.test.ts:42-45`, `tests/deno/tests/event-source.test.ts:39-42` — generators return a value to force a data-bearing `close`
- `packages/fetch/src/event-stream.ts:189` — `close` data is `stringifyJSON(result.value)`; `undefined` yields no `data:` line
- `packages/core/src/event-stream/encoder.ts:50-56` / `:77-81` — `data === undefined` emits no `data:` line, and `event: close` is still emitted

## Required outcome
- No behavior change is required for this PR. At minimum, the test files should carry the same caveat the PR body does, so the value-returning generators are not "simplified" into a hang.

## Open questions for the human
- Is a data-less `close` arriving at EventSource as a reconnect (never a `close`) an accepted protocol limitation, or should the sender synthesize `data` for a value-less close? If accepted, stating it in the event-stream contract would help consumers.

ℹ️ Nitpicks

  • receive() resolves on the first close/error event but never rejects; if a regression prevents either, the test hangs until the default test timeout. A small timeout-rejection would turn an ambiguous timeout into a clear failure.
  • describe.skipIf(typeof EventSource === 'undefined') means the Node/Bun tests can silently stop running if the global disappears (e.g. a future Node drops the flag, or Bun restructures it). That trade-off is deliberate per the PR body, but a silent skip is easy to miss.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (default — pick a model for stronger reviews) | 𝕏

Comment thread tests/event-source.test.ts
@dinwwwh
dinwwwh merged commit 917b6a2 into main Sep 30, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant