Skip to content

feat: support AbortSignal on server-side methods#41141

Open
Skn0tt wants to merge 2 commits into
microsoft:mainfrom
Skn0tt:feat/abort-signal-server-side
Open

feat: support AbortSignal on server-side methods#41141
Skn0tt wants to merge 2 commits into
microsoft:mainfrom
Skn0tt:feat/abort-signal-server-side

Conversation

@Skn0tt
Copy link
Copy Markdown
Member

@Skn0tt Skn0tt commented Jun 4, 2026

Summary

  • Adds a client-only signal?: AbortSignal option next to every existing timeout option on action, getter and navigation methods.
  • Aborting cancels the in-flight server call via a __cancel__ wire message that aborts the dispatcher's ProgressController; a pre-aborted signal throws signal.reason synchronously.
  • Follows up feat: add AbortSignal support to client-side Waiter methods #41136 (Waiter-based waitFor* methods), which is excluded here as it already has signal support.

Not included (follow-ups)

  • expect assertions (toBeVisible, etc.) — deferred to a separate PR.
  • ElementHandle.inputValue — intentionally left out. Unlike Locator/Page/Frame.inputValue (which route through the Frame.inputValue protocol method that carries timeout), the ElementHandle.inputValue protocol method (packages/protocol/spec/handles.yml) declares no parameters, so the timeout option the public types have long advertised there is silently dropped by the wire validator. Adding signal would require a signature change and inherit that broken-timeout behavior. Fixing it is a separate change: add timeout/signal to the inputValue entry in handles.yml.

Refs #40578

Skn0tt added 2 commits June 4, 2026 17:33
Adds a client-only `signal` option that aborts an in-flight server
operation via a new fire-and-forget `__cancel__` message, which aborts
the call's ProgressController in the dispatcher.

Wires it up on Locator.click and Locator.waitFor as a starting point.

Fixes: microsoft#40578
Adds the signal option next to every existing timeout option on
action, getter and navigation methods, threading it through the
client so in-flight calls can be cancelled via the __cancel__ wire
message.

Refs: microsoft#40578
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Test results for "MCP"

7230 passed, 1103 skipped


Merge workflow run.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Test results for "tests 1"

3 flaky ⚠️ [chromium-library] › library/video.spec.ts:719 › screencast › should work with video+trace `@chromium-ubuntu-22.04-arm-node20`
⚠️ [chromium-library] › library/video.spec.ts:719 › screencast › should work with video+trace `@chromium-ubuntu-22.04-node24`
⚠️ [firefox-library] › library/inspector/cli-codegen-3.spec.ts:224 › cli codegen › should generate frame locators (4) `@firefox-ubuntu-22.04-node20`

39554 passed, 771 skipped


Merge workflow run.

@Skn0tt Skn0tt changed the title feat(client): support AbortSignal on server-side methods feat: support AbortSignal on server-side methods Jun 4, 2026
@Skn0tt Skn0tt requested a review from dgozman June 4, 2026 16:31
throw new Error('The object has been collected to prevent unbounded heap growth.');

const signal = options.signal;
if (signal?.aborted)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Suggested change
if (signal?.aborted)
signal?.throwIfAborted();

Comment thread docs/src/api/params.md
- `signal` <[AbortSignal]>

Allows to cancel the operation using an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal). If the signal is aborted, the operation will be aborted and throw an error.
Note that providing a signal does not disable the default timeout; pass `timeout: 0` to disable the timeout entirely.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's link to setDefaultTimeout here?


async ariaSnapshot(options: TimeoutOptions & { mode?: 'ai' | 'default', depth?: number, boxes?: boolean, _track?: string } = {}): Promise<string> {
const result = await this.mainFrame()._channel.ariaSnapshot({ timeout: this._timeoutSettings.timeout(options), track: options._track, mode: options.mode, depth: options.depth, boxes: options.boxes });
const result = await this.mainFrame()._channel.ariaSnapshot({ timeout: this._timeoutSettings.timeout(options), track: options._track, mode: options.mode, depth: options.depth, boxes: options.boxes, ...{ signal: options.signal } });
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How can we make sure that signal is passed for every method where it is defined? I think we are at least lacking signal option defined in many methods, and types like FetchOptions or ElectronOptions. Perhaps passing it explicitly as a second argument to generated channel methods is better? Or somehow ensuring in TypeScript that we pass non-optional AbortSignal | SomeSpecialSymbol to make sure it is always there.

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.

2 participants