Skip to content

test: spec coverage for AbortSignal/AbortController and structuredClone - #33324

Closed
robobun wants to merge 4 commits into
mainfrom
farm/2b677b4f/web-platform-coverage
Closed

robobun wants to merge 4 commits into
mainfrom
farm/2b677b4f/web-platform-coverage

Conversation

@robobun

@robobun robobun commented Jul 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

Two web-platform primitives with surprisingly thin coverage. Expectations were written from the DOM and HTML specs, then cross-checked against Node, rather than read off Bun's current output.

AbortSignal / AbortController (+36 tests)

test/js/web/abort/abort.test.ts had 5 tests, three of which were process-spawn smoke checks. Notable holes:

  • AbortSignal.prototype.throwIfAborted() was never called anywhere in test/.
  • The only AbortController.abort(reason) coverage lived in a fixture that calls controller.abort() with no argument in the loop body, so custom reasons were never actually exercised.
  • AbortSignal.timeout() firing was test.skip'd in that fixture with a "test runner hangs" note. It does not hang; there is now a test that awaits the abort event.

Now covered: [SameObject] signal, non-constructible AbortSignal, reason identity (including falsy reasons), default AbortError DOMException, second abort() being a no-op, abort event shape, listeners added after abort, aborting from inside an abort listener, listeners added during dispatch, onabort position in the listener list, throwIfAborted identity/falsy/default, AbortSignal.abort, AbortSignal.timeout firing and argument validation, AbortSignal.any (reason identity, already-aborted sources, empty list, composite-of-composite, any iterable, fires once, TypeError paths), and a getter brand check.

structuredClone (+28 tests)

DataCloneError was only exercised for detached ArrayBuffers. Now: functions, arrow functions, symbols (as values, property values and array elements), WeakMap, WeakSet, WeakRef, globalThis, Promise, a Proxy, a detached ArrayBuffer, and a typed array in the transfer list.

Object semantics from the serialization spec: own getters invoked exactly once and landing as data properties, non-enumerable and symbol-keyed properties dropped, explicit undefined kept, holes kept, clone prototype reset to Object.prototype, RegExp lastIndex reset, Map/Set insertion order, reference identity across sibling properties, cycles through objects, arrays, Map values and Set members, and a Map key that is also its own value.

Divergences it found

Marked test.failing, so CI stays green and each reports the moment it is fixed.

DOMException never captures a stack.

$ bun -e 'console.log(new DOMException("x", "AbortError").stack)'
undefined
$ bun -e 'console.log(JSON.stringify(AbortSignal.abort().reason.stack))'
undefined

Node gives "AbortError: ...\n at new DOMException (...)" for both. AbortSignal.timeout()'s reason has stack === "", and controller.abort()'s has "abort@[native code]\n..." rather than a header naming the error. This is the root cause of #17877, #25182 and #21900.

structuredClone drops Error.cause. structuredClone(new Error("x", { cause: new RangeError("y") })).cause is undefined; Node/V8 and Firefox both serialize it.

Everything else passes. #18357 (structuredClone of an error loses the stack) does not reproduce on main, and the clone's stack is now asserted.

Verification

bun bd test test/js/web/abort/abort.test.ts                 41 pass, 0 fail
bun bd test test/js/web/workers/structured-clone.test.ts   240 pass, 0 fail

No src/ changes.


[stamp-90s] gate passed · iteration 1 · 2 files touched

passes on PR (with fix)
Test-only change.

Debug/ASAN (expected pass):
$ bun bd test 'test/js/web/abort/abort.test.ts' 'test/js/web/workers/structured-clone.test.ts'
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/js/web/abort/abort.test.ts test/js/web/workers/structured-clone.test.ts
info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu
info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05)
info: component rust-src is up to date
info: checking for self-update (current version: 1.29.0)
bun test v1.4.0 (2dc9a18c0)

test/js/web/abort/abort.test.ts:
(pass) AbortSignal > spawn test [455.73ms]
(pass) AbortSignal > AbortSignal.timeout(n) should not freeze the process [539.58ms]
(pass) AbortSignal > AbortSignal.any() should fire abort event [21.56ms]
(pass) AbortSignal > .signal.reason should be a DOMException [10.07ms]
(pass) AbortSignal > .signal.reason should be a DOMException for timeout [19.33ms]
(pass) AbortController (DOM spec) > signal is the same object on every access [1.49ms]
(pass) AbortController (DOM spec) > AbortSignal is not constructible [3.71ms]
(pass) AbortController (DOM spec) > a fresh signal is not aborted and has no reason [2.23ms]
(pass) AbortController (DOM spec) > abort(reason) stores the reason by identity [2.46ms]
(pass) AbortController (DOM spec) > abort(reason) accepts falsy reasons [1.85ms]
(pass) AbortController (DOM spec) > abort() without a reason creates an AbortError DOMException [2.52ms]
(pass) AbortController (DOM spec) > abort(undefined) behaves like abort() [2.20ms]
(pass) AbortController (DOM spec) > a second abort() keeps the first reason and does not fire again [4.10ms]
(pass) AbortController (DOM spec) > the abort event is a plain Event targeted at the signal [4.84ms]
(pass) AbortController (DOM spec) > listeners added after the abort never fire [2.08ms]
(pass) AbortController (DOM spec) > aborting inside an abort listener does not re-dispatch [3.62ms]
(pass) AbortController (DOM spec) > a listener added during dispatch is not called for that dispatch [3.52ms]
(pass) AbortController (DOM spec)
... (truncated)
Exit: 0
diff hotspot
test/js/web/abort/abort.test.ts              | 295 +++++++++++++++++++++++++++
 test/js/web/workers/structured-clone.test.ts | 178 ++++++++++++++++
 2 files changed, 473 insertions(+)

gate history · 1 passed · 0 rejected · iteration 1

evidence per changed file
file                                          reads  edits  tests
test/js/web/abort/abort.test.ts                   6      6      0
test/js/web/workers/structured-clone.test.ts      5      7      0

@github-actions github-actions Bot added the claude label Jul 4, 2026
@robobun

robobun commented Jul 4, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 12:17 PM PT - Jul 13th, 2026

❌ @robobun, your commit 2dc9a18 has 2 failures in Build #72461 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 33324

That installs a local version of the PR into your bun-33324 executable, so you can run:

bun-33324 --bun

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Found 4 issues this PR may fix:

  1. structuredClone() an error loses the stack trace #18357 - PR tests structuredClone of Error objects (name, message, stack preserved), directly covering the behavior reported as broken
  2. No stack trace when calling throwIfAborted() on an AbortSignal #17877 - PR adds tests for throwIfAborted() behavior, which is the API surface this issue reports has no stack trace
  3. No stack trace on AbortSignal.timeout error #25182 - PR tests AbortSignal.timeout() firing an abort event with TimeoutError, directly covering the API where this issue reports empty stack traces
  4. Random TimeoutError is sometimes thrown without a stack trace #21900 - Same root cause as No stack trace on AbortSignal.timeout error #25182 — TimeoutError from AbortSignal.timeout() has an empty stack, exercised by the PR's timeout tests

If this is helpful, copy the block below into the PR description to auto-close these issues on merge.

Fixes #18357
Fixes #17877
Fixes #25182
Fixes #21900

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds test coverage for AbortController/AbortSignal DOM behavior and structuredClone semantics. It expands abort-event, static AbortSignal, and Error/DataCloneError cloning cases without changing exported APIs.

Changes

AbortController/AbortSignal test coverage

Layer / File(s) Summary
AbortController and abort event semantics
test/js/web/abort/abort.test.ts
Adds tests for signal identity stability, AbortSignal non-constructibility, default state, abort(reason) handling, default AbortError, and detailed abort event dispatch and listener ordering.
throwIfAborted behavior
test/js/web/abort/abort.test.ts
Adds tests verifying return and throw behavior, reason identity, and default DOMException when reason is absent.
AbortSignal static factory methods
test/js/web/abort/abort.test.ts
Adds tests for AbortSignal.abort, AbortSignal.timeout, and a polling helper used by timeout checks.
AbortSignal.any behavior
test/js/web/abort/abort.test.ts
Adds tests for already-aborted sources, later abort propagation, single firing across multiple sources, empty input, nested composites, iterable inputs, and invalid inputs.

structuredClone test coverage

Layer / File(s) Summary
Non-serializable value rejection
test/js/web/workers/structured-clone.test.ts
Adds tests asserting DataCloneError DOMException for unsupported inputs and typed arrays in the transfer list.
Object cloning semantics
test/js/web/workers/structured-clone.test.ts
Adds tests for getter and property behavior, prototype normalization, RegExp lastIndex reset, Map and Set order and identity preservation, and cycle handling.
Error cloning
test/js/web/workers/structured-clone.test.ts
Adds tests that preserve Error subclass name, message, and stack, drop extra own properties, and include a failing case for Error cause cloning.

Possibly related PRs

  • oven-sh/bun#32747: Expanded AbortSignal reason identity and throwIfAborted tests exercise the abort-reason tracking changes.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: added spec coverage for AbortSignal/AbortController and structuredClone.
Description check ✅ Passed The description covers both required areas—what the PR does and how it was verified—with concrete test details.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/js/web/abort/abort.test.ts`:
- Around line 221-226: The abort identity test is too weak because
`toThrow(reason)` only matches the error message, not the exact thrown object.
Update the `throws the reason by identity` test around `AbortController.abort`
and `signal.throwIfAborted()` to capture the thrown value explicitly and assert
it is the same `reason` instance using identity comparison (`toBe`), so the test
verifies the exact object was thrown.

In `@test/js/web/workers/structured-clone.test.ts`:
- Around line 744-747: The typed-array transfer test in structuredClone is too
broad because it only checks for a DOMException and could pass for the wrong
error name. Update the assertion in the test that uses structuredClone(view, {
transfer: [view as any] }) so it also verifies the thrown error’s name is
"DataCloneError", matching the other cases in this describe block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 056b91ee-af69-462f-be9f-371d4c8e1252

📥 Commits

Reviewing files that changed from the base of the PR and between a8d0692 and 64c0526.

📒 Files selected for processing (2)
  • test/js/web/abort/abort.test.ts
  • test/js/web/workers/structured-clone.test.ts

Comment thread test/js/web/abort/abort.test.ts
Comment thread test/js/web/workers/structured-clone.test.ts
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. test(abort): Add AbortSignal.any basic tests #25406 - Adds the same AbortSignal.any basic spec tests (empty array, single/multiple signals, already-aborted, reason propagation)
  2. test(abort): Add AbortSignal.any advanced tests #25407 - Adds the same AbortSignal.any advanced spec tests (event firing, nested any(), timeout interaction)

🤖 Generated with Claude Code

@claude claude 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.

LGTM — pure additive test coverage for AbortSignal/AbortController and structuredClone, no src/ changes.

Extended reasoning...

Overview

This PR appends ~60 new tests to two existing test files: test/js/web/abort/abort.test.ts (+32 tests covering AbortController/AbortSignal DOM spec behavior) and test/js/web/workers/structured-clone.test.ts (+28 tests covering DataCloneError rejection cases and HTML serialization semantics). All changes are purely additive — no existing tests are modified or removed, and there are zero src/ changes.

Security risks

None. This is test-only code that never ships in the runtime. No auth, crypto, permissions, or user-input handling is touched.

Level of scrutiny

Low. Test-only additions to existing files, following established patterns in those files. The tests are spec-referenced (DOM and HTML spec URLs cited), use strong assertions (.toBe identity checks, specific error names/types rather than bare .toThrow()), and avoid flaky constructs — the AbortSignal.timeout test awaits the abort event via Promise.withResolvers rather than sleeping. The one known divergence (Error cause not serialized) is correctly marked test.failing so it flips when fixed.

Other factors

The bug-hunting system found nothing. The PR description shows both files pass locally (37 pass / 240 pass). Worst-case failure mode is a test being wrong or overly strict, which CI will surface immediately and which carries no runtime risk. This is exactly the kind of mechanical, self-contained coverage expansion that doesn't need human review.

@robobun

robobun commented Jul 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

Thanks, all three bots. Addressed in 4346ac7.

CodeRabbit: both correct.

  • toThrow(reason) only compares the message, so a fresh Error("nope") would have passed. Now captures the thrown value and asserts toBe(reason).
  • The typed-array transfer case now asserts name === "DataCloneError" like its siblings.

find-issues: this PR does not fix any of the four, so no Fixes lines. But three of them turned out to share one root cause that my tests walked right past, so I added coverage for it:

$ bun -e 'console.log(new DOMException("x", "AbortError").stack)'
undefined
$ bun -e 'console.log(JSON.stringify(AbortSignal.abort().reason.stack))'
undefined

Node gives "AbortError: ...\n at new DOMException (...)" for both. AbortSignal.timeout()'s reason has stack === "", and controller.abort()'s has "abort@[native code]\n..." rather than a header naming the error. So DOMException never captures a stack, which is #17877, #25182 and #21900. Four new test.failing cases pin that; they flip the moment DOMException starts capturing one.

#18357 (structuredClone of an error loses the stack) does not reproduce on main: structuredClone(new Error("boom")).stack comes back with the same frames as the original. The PR already asserts the stack survives the clone.

duplicate-prs: #25406 and #25407 overlap on AbortSignal.any, and they were first (opened in December). If a maintainer prefers to land those, I am happy to drop the AbortSignal.any describe block from this PR; the rest (throwIfAborted, reason identity, dispatch reentrancy, listener ordering, structuredClone) does not overlap.

@claude claude 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 issues found — the tests look solid and spec-derived. Deferring to a maintainer mainly for the open call on the AbortSignal.any overlap with #25406/#25407, and to sanity-check the five test.failing expectations before they land as pinned behavior.

Extended reasoning...

Overview

Test-only PR adding ~60 spec-derived cases to two existing files: test/js/web/abort/abort.test.ts (AbortController/AbortSignal: reason identity, event dispatch ordering, throwIfAborted, abort/timeout/any statics, brand checks) and test/js/web/workers/structured-clone.test.ts (DataCloneError rejection matrix, object-graph semantics, Error cloning). No src/ changes. Both CodeRabbit nits were addressed in 4346ac7 and the bug-hunting pass found nothing.

Security risks

None. Pure test additions with no runtime, network, or filesystem side effects beyond what the existing test files already exercise.

Level of scrutiny

Medium. While test-only, this is 60 new assertions that encode spec expectations Bun will be held to going forward, plus five test.failing cases that pin the shape of a future DOMException-stack fix (e.g. stack must contain "AbortError"). A maintainer should confirm those pinned expectations match what they actually intend to ship, since test.failing will flip red the moment the behavior changes in any direction.

Other factors

The author explicitly left a decision to a maintainer: the AbortSignal.any describe block overlaps open PRs #25406/#25407 and they offered to drop it. That call — land this as-is vs. drop the overlap and let the earlier PRs land first — is not mine to make. The tests themselves follow harness conventions (await conditions via Promise.withResolvers, no sleeps, identity assertions via toBe, test.each-style tables) and read cleanly.

@robobun
robobun force-pushed the farm/2b677b4f/web-platform-coverage branch from 4346ac7 to f76e289 Compare July 4, 2026 20:38

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/js/web/workers/structured-clone.test.ts`:
- Around line 731-754: Extract a shared expectDataCloneError helper for the
duplicated try/catch assertion logic in structuredClone tests. Move the repeated
“capture thrown value, assert DOMException, assert name is DataCloneError” block
into a small helper near the rejected cases, then call it from both the rejected
loop and the typed-array transfer test to keep the structured-clone test cases
concise and consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2b22c4fb-a347-4b58-b3c3-64380d8b4c1d

📥 Commits

Reviewing files that changed from the base of the PR and between 64c0526 and f76e289.

📒 Files selected for processing (2)
  • test/js/web/abort/abort.test.ts
  • test/js/web/workers/structured-clone.test.ts

Comment thread test/js/web/workers/structured-clone.test.ts Outdated

@claude claude 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.

I didn't find any issues with the tests themselves — they're well-derived from spec and Node behavior — but the five test.failing cases pin expected behavior for open bugs, and the AbortSignal.any overlap with #25406/#25407 needs a maintainer call, so worth a human look before landing.

Extended reasoning...

Overview

This PR is purely additive test coverage: ~480 lines across test/js/web/abort/abort.test.ts (+36 tests) and test/js/web/workers/structured-clone.test.ts (+28 tests). No src/ changes. Tests are derived from the DOM and HTML specs and cross-checked against Node, covering throwIfAborted, abort-reason identity, event dispatch/reentrancy, AbortSignal.abort/timeout/any, and structuredClone rejection cases, object semantics, cycles, and Error cloning. The author addressed both of CodeRabbit's correctness comments (identity assertion in throwIfAborted, tightened DataCloneError name check) in commit 4346ac7; one trivial refactor nit (extract an expectDataCloneError helper) remains unaddressed but is cosmetic.

Security risks

None. Test-only changes with no production code, no network access beyond in-process APIs, no auth/crypto/permissions surface.

Level of scrutiny

Medium. The pass/fail tests themselves are low-risk — additive spec coverage that either passes or gets reverted. What warrants a maintainer's eye:

  • Five test.failing cases pin desired behavior for #17877/#25182/#21900 (DOMException stack traces) and Error cause serialization. These are reasonable expectations (Node and browsers agree), but they encode a commitment about what the fix should look like — e.g., reason.stack must contain "AbortError", new DOMException(...).stack must be a string. A maintainer should confirm these are the invariants Bun wants pinned.
  • The waitUntilAborted polling helper works around a Windows hang by polling signal.aborted in a bounded 2000×1ms loop rather than awaiting the event. It's documented and bounded, but it's a workaround for a runner bug rather than a fix.

Other factors

  • The duplicate-PR bot flagged overlap with open PRs #25406/#25407 for the AbortSignal.any block, and the author explicitly offered to drop that section if maintainers prefer landing those first. That's a coordination decision only a maintainer can make.
  • CI build #68379 was retriggered on the latest commit; I can't confirm it's green from here.
  • The tests are well-structured, use identity assertions where appropriate, cite spec sections and issue URLs, and follow the file's existing conventions. I found no flakiness patterns, unbounded waits, or vacuous assertions.

@robobun

robobun commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator Author

Good review. Three things in fb6cf9c.

"a workaround for a runner bug rather than a fix" is the sharpest point here, and it deserved better than a code comment. waitUntilAborted exists because awaiting the abort event of an AbortSignal.timeout() wedges the whole test file on Windows. That is a real bug, the repo already half-knew about it, and it was going to stay buried:

// test/js/web/abort/abort.ts:113
// FIXME: test runner hangs when this is enabled
test.skip("timeout works", done => { ... });

Filed as #33334 with the evidence chain: the await promise version timed out abort.test.ts on all three Windows lanes (build 68331); the bounded-poll version passes all three (build 68351); and a sibling test that does AbortSignal.timeout(0) + await Bun.sleep(10) + assert passes on Windows today, so the timer fires and aborted flips. The abort happens; awaiting its event from inside the runner is what hangs. The helper now points at the issue and says to revert it to awaiting the event once fixed.

CodeRabbit's expectDataCloneError nit was still open. Extracted; both sites call it now.

On the five test.failing cases: fair to want a maintainer to confirm the invariants. For what it's worth, four of them are one invariant stated four ways — DOMException never captures a stack at all:

$ bun -e 'console.log(new DOMException("x", "AbortError").stack)'
undefined

Everything downstream falls out of that: AbortSignal.abort().reason.stack is undefined, AbortSignal.timeout()'s is "", and controller.abort()'s is abort@[native code] with no header naming the error. Node gives "AbortError: ...\n at new DOMException (...)" for all of them, and that is what the assertions pin. The fifth is structuredClone dropping Error.cause, which Node/V8 and Firefox both serialize.

Worth noting the directionality: test.failing goes red when it starts passing, so a partial fix leaves them quietly failing rather than breaking anyone. The risk of pinning too tightly is low.

On the AbortSignal.any overlap with #25406/#25407: still a maintainer's call and the offer stands, I'll drop that describe block if you'd rather land those first. Nothing else in this PR touches the same ground.

@claude claude 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.

I didn't find any issues — the tests are well-structured and spec-derived — but with ~470 lines of new CI assertions (including five test.failing cases that encode expected future behavior) and the open overlap with #25406/#25407 you flagged, a maintainer should sign off on which expectations to commit to.

Extended reasoning...

Overview

This PR adds ~64 new test cases across two files with no src/ changes:

  • test/js/web/abort/abort.test.ts: +36 tests covering AbortController/AbortSignal DOM spec behavior (throwIfAborted, reason identity, event dispatch/reentrancy, listener ordering, AbortSignal.abort/timeout/any), plus 4 test.failing cases pinning the missing-stack-on-DOMException bugs (#17877, #25182, #21900).
  • test/js/web/workers/structured-clone.test.ts: +28 tests covering DataCloneError for non-serializable values, object cloning semantics (getters, holes, prototypes, cycles, identity), and Error cloning, plus 1 test.failing for Error.cause not being serialized.

All three rounds of CodeRabbit feedback have been addressed (identity assertion for throwIfAborted, DataCloneError name check, extracted expectDataCloneError helper). The bug-hunting system found nothing.

Security risks

None. Test-only additions with no changes to runtime, build, or CI configuration.

Level of scrutiny

Moderate. While test-only, this is a large surface (~470 lines) of new CI assertions derived from the DOM/HTML specs. Each passing test becomes a contract Bun must continue to satisfy, and each test.failing becomes a contract that fixing the referenced issue is required (the test will start failing CI once the underlying behavior changes). The assertions look correct against the specs and Node's behavior, but a maintainer should confirm they agree with all of them — particularly the test.failing cases, which encode opinions about what Bun should do (e.g., that DOMException must capture a stack, that structuredClone must preserve Error.cause).

Other factors

  • The author explicitly flagged overlap between the AbortSignal.any describe block and open PRs #25406/#25407, and deferred to maintainers on whether to drop it here or land those first. That coordination decision is still open.
  • A bounded-poll waitUntilAborted helper works around a Windows test-runner hang (filed as #33334) rather than awaiting the abort event. The workaround is safe (bounded, fails loudly), but a maintainer may want to weigh in on whether to land it or wait for the underlying fix.
  • The tests follow repo conventions well (no hardcoded ports, no sleeps-as-assertions except the bounded workaround, proper test.failing usage with issue links).

Given the scale, the embedded behavioral commitments via test.failing, and the open PR-overlap question, this warrants a human look rather than auto-approval.

robobun added 4 commits July 13, 2026 18:28
AbortSignal.prototype.throwIfAborted() was never called anywhere in the test
suite, AbortController.abort(reason) had no test that actually passed a reason,
and structuredClone's DataCloneError path only covered detached ArrayBuffers.

Adds 32 AbortController/AbortSignal tests from the DOM spec (signal identity,
reason propagation, dispatch reentrancy, listener ordering, throwIfAborted,
AbortSignal.any composition, brand checks) and 28 structuredClone tests from the
HTML serialization spec (the DataCloneError set, getter invocation, property
filtering, prototype reset, cycles through objects/arrays/Maps/Sets, reference
identity, Error serialization).

Everything passes except Error cause, which Bun drops and which Node/V8 and
Firefox both serialize; that one is marked test.failing.
Also tighten two assertions: compare the thrown reason by identity rather than
by message, and check the DataCloneError name on the transfer-list case.
Awaiting the abort event of an AbortSignal.timeout() wedges the test runner on
Windows, which is what the 'FIXME: test runner hangs' note in abort.ts already
warned about. A bounded poll on signal.aborted fails loudly instead of hanging
the whole file.
The bounded poll in abort.test.ts works around a real bug rather than a quirk of
the test, so it is filed as #33334 and the helper points at it. Reverting it to
await the event is the signal that the bug is fixed.
@robobun
robobun force-pushed the farm/2b677b4f/web-platform-coverage branch from fb6cf9c to 2dc9a18 Compare July 13, 2026 18:29

@claude claude 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.

I didn't find any correctness issues in the tests themselves, but you've left two calls open for a maintainer — whether to keep the AbortSignal.any block given the overlap with #25406/#25407, and confirming the test.failing invariants (DOMException stack shape, Error.cause serialization) — so this should get a human sign-off rather than a bot approval.

Checked: abort-event dispatch/reentrancy tests match DOM spec ordering; throwIfAborted identity assertions are strict (toBe, not toThrow); waitUntilAborted polling is bounded and the Windows hang is filed as #33334; the expectDataCloneError helper and structuredClone cycle/identity/hole tests match HTML serialization semantics and don't conflict with the existing object-pool tests in the same file.

Extended reasoning...

Overview

Test-only PR adding ~64 spec-derived tests across test/js/web/abort/abort.test.ts (+295 lines) and test/js/web/workers/structured-clone.test.ts (+178 lines). No src/ changes. Covers AbortController/AbortSignal DOM semantics (reason identity, event dispatch ordering, throwIfAborted, AbortSignal.abort/timeout/any, brand checks) and structuredClone HTML serialization semantics (DataCloneError cases, getter/enumerable/symbol-key handling, cycles, Error cloning). Five test.failing cases pin known divergences (DOMException never captures a stack; Error.cause dropped on clone).

Security risks

None. Pure test additions with no production code paths, no network/filesystem access beyond the existing harness patterns, no credentials or auth logic.

Level of scrutiny

Moderate. The tests are well-constructed, spec-cited, and follow repo conventions (bounded polling instead of sleeps, identity assertions via toBe, test.failing for known divergences). All three CodeRabbit comments were addressed and resolved. However, the author has explicitly deferred two decisions to a maintainer in the thread: (1) whether the AbortSignal.any describe block should be dropped in favor of the older #25406/#25407, and (2) confirmation that the five test.failing invariants — particularly the exact shape expected of DOMException.stack and that structuredClone must preserve Error.cause — are what Bun wants to commit to. Approving over those open questions would preempt a decision the author intentionally left to a human.

Other factors

The waitUntilAborted polling helper is a documented workaround for a filed Windows runner hang (#33334), with a comment saying to revert once fixed — reasonable, but another thing a maintainer may want to weigh in on. The PR is also fairly large (~470 lines) for a test addition, which alone nudges toward human review.

@robobun

robobun commented Jul 13, 2026 •

Copy link
Copy Markdown
Collaborator Author

CI status: build 72461 settled at 283 passed, 3 failed. None of the three is this diff.

  • test/js/node/test/parallel/test-worker-message-port-transfer-terminate.js — SIGABRT on the ASAN lane, JSC assertion !scope.exception() || !result in JSObject::getOwnPropertyDescriptor. Worker termination race; passes 5/5 locally on debug+ASAN. Already being worked on separately.
  • test/napi/napi.test.ts — Condition was not met after 100 GC attempts in a napi_wrap GC-timing test on Windows. Already being worked on separately.
  • darwin 14 x64 shard — the test runner's git clone vendor 'elysia' timed out before any test ran. Infra.

This diff adds tests only, to test/js/web/abort/abort.test.ts and test/js/web/workers/structured-clone.test.ts. Neither file appears in any failure annotation, and neither red test shares a file, a shard, or a code path with this change.

Both files pass locally:

bun bd test test/js/web/abort/abort.test.ts                  41 pass, 0 fail
bun bd test test/js/web/workers/structured-clone.test.ts    259 pass, 0 fail

Ready for a maintainer on the two open calls in the thread above (the AbortSignal.any overlap with #25406/#25407, and the test.failing invariants).

@robobun

robobun commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as part of a cleanup of stale pull requests. This PR has had no new commits since 2026-07-13, it conflicts with main, and its last CI run failed. This is not a judgment on the fix itself. If the problem still reproduces on a current build, reopen this PR after a rebase or open a new one against main.

@robobun robobun closed this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant