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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat: support AbortSignal on server-side methods by Skn0tt · Pull Request #41141 · microsoft/playwright · GitHub
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

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

@Skn0ttSimon Knott (Skn0tt) changed the title feat(client): support AbortSignal on server-side methodsfeat: support AbortSignal on server-side methodsJun 4, 2026
Comment threadpackages/playwright-core/src/client/connection.ts
Comment threaddocs/src/api/params.md Outdated
Comment threadpackages/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 threadpackages/playwright-core/src/client/connection.ts
Comment threadpackages/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
ContributorAuthor

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 c7b916cCompareJune 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 07a7b5cCompareJune 18, 2026 10:19
@Skn0tt

Copy link
Copy Markdown
ContributorAuthor

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 1b21b1dCompareJune 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 threadpackages/playwright-core/src/client/browserContext.ts Outdated
Comment threadtests/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
ContributorAuthor

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 freeto 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

@Skn0tt@dgozman