Skip to content

feat: support AbortSignal on server-side methods - #41141

Merged
Simon Knott (Skn0tt) merged 6 commits into
microsoft:mainfrom
Skn0tt:feat/abort-signal-server-side
Jun 30, 2026
Merged

feat: support AbortSignal on server-side methods#41141
Simon Knott (Skn0tt) merged 6 commits into
microsoft:mainfrom
Skn0tt:feat/abort-signal-server-side

Conversation

@Skn0tt

@Skn0tt Simon Knott (Skn0tt) commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

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.
  • Internally, the signal travels as a required second argument on every client channel method, mirroring how progress works on the dispatcher side. That way the compiler enforces we forward it everywhere, rather than letting it hide in a params field.
  • 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

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@Skn0tt Simon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methods feat: support AbortSignal on server-side methods Jun 4, 2026
Comment thread packages/playwright-core/src/client/connection.ts
Comment thread docs/src/api/params.md Outdated
Comment thread packages/playwright-core/src/client/page.ts Outdated
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread packages/playwright-core/src/client/connection.ts
Comment thread packages/playwright-core/src/server/network.ts Outdated

async scrollIntoViewIfNeeded(options: channels.ElementHandleScrollIntoViewIfNeededOptions & TimeoutOptions = {}) {
await this._elementChannel.scrollIntoViewIfNeeded({ ...options, timeout: this._frame._timeout(options) });
await this._elementChannel.scrollIntoViewIfNeeded({ ...options, timeout: this._frame._timeout(options), 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.

In theory, can we replace timeouts with client-side signals that abort on timeout? Worth an experiment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we could, yes! I'll try it out.

@Skn0tt
Simon Knott (Skn0tt) force-pushed the feat/abort-signal-server-side branch from a782655 to c7b916c Compare June 18, 2026 10:15
Threads an AbortSignal through the client as a required second argument
on channel methods (mirroring progress on the dispatcher side), so
server-side calls can be cancelled.
@Skn0tt
Simon Knott (Skn0tt) force-pushed the feat/abort-signal-server-side branch from c7b916c to 07a7b5c Compare June 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
Contributor Author

Rebased onto #41321.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Aborting a channel call now rejects with an AbortError (mirroring
Node.js abort-aware operations), preserving the original abort reason
as cause instead of rethrowing the raw reason. This guarantees
Playwright never throws a non-Error value when aborted with a string
reason, in both the in-flight and already-aborted cases.
@Skn0tt
Simon Knott (Skn0tt) force-pushed the feat/abort-signal-server-side branch from fe1c16f to 1b21b1d Compare June 18, 2026 13:18
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread packages/playwright-core/src/client/browserContext.ts Outdated
Comment thread tests/page/page-click.spec.ts Outdated
evaluateHandle<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(pageFunction: PageFunctionOn<E, Arg, R>, arg?: Arg, options?: { timeout?: number }): Promise<SmartHandle<R>>;
evaluateAll<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(pageFunction: PageFunctionOn<E[], Arg, R>, arg?: Arg): Promise<R>;
waitForFunction<Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(pageFunction: PageFunctionOn<E, Arg, any>, arg?: Arg, options?: { timeout?: number }): Promise<void>;
waitForFunction<Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(pageFunction: PageFunctionOn<E, Arg, any>, arg?: Arg, options?: { timeout?: number, signal?: AbortSignal }): Promise<void>;

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.

What about other overrides here that have a timeout? I think these should get a signal as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i think there's many more missing, I'll do those chunked in follow-ups.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "MCP"

3 failed
❌ [chrome] › mcp/http.spec.ts:349 › client should receive list roots request @mcp-macos-latest-chrome
❌ [chrome] › mcp/http.spec.ts:349 › client should receive list roots request @mcp-ubuntu-latest-chrome
❌ [firefox] › mcp/http.spec.ts:349 › client should receive list roots request @mcp-ubuntu-latest-firefox

7458 passed, 1132 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "tests 1"

2 failed
❌ [chromium-library] › library/browsercontext-add-init-script.spec.ts:28 › should work without navigation, after all bindings @chromium-ubuntu-22.04-arm-node20
❌ [chromium-library] › library/browsercontext-expose-function.spec.ts:77 › should be callable from-inside addInitScript @chromium-ubuntu-22.04-arm-node20

2 flaky ⚠️ [chromium-library] › library/video.spec.ts:476 › screencast › should capture static page in persistent context Radoslav Kirilov (@smoke) `@chromium-ubuntu-22.04-node20`
⚠️ [chromium-library] › library/video.spec.ts:717 › screencast › should work with video+trace `@chromium-ubuntu-22.04-node22`

49217 passed, 1163 skipped


Merge workflow run.

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