Skip to content

[Feature]: support signal in waitFor* APIs #40578

Closed

Description

@tmkx

🚀 Feature Request

Many Playwright ⁠waitFor* APIs support a ⁠timeout option, which works well for fixed upper bounds. A complementary capability would be support for ⁠AbortSignal, so callers can cancel an in-flight wait based on external application state.

Example

A consistent API shape could look like this wherever ⁠timeout is already supported:

await locator.waitFor({
  state: 'visible',
  timeout: 30_000,
  signal,
});

await page.waitForURL('**/dashboard', {

Motivation

This would make Playwright waiting APIs easier to compose with:

  • shared cancellation across multiple concurrent operations
  • higher-level test orchestration
  • user-defined deadlines and cascading cancellation
  • integration with standard Web Platform and Node.js cancellation patterns

Activity

  1. rohan-patnaik commented on May 16, 2026

    @rohan-patnaik

    I’d like to work on this if it is open for community contribution.
    To keep the first PR reviewable, I’d start with a small set of wait APIs that already have timeout handling, add an optional signal through the existing wait/cancellation path, and add focused tests for pre-aborted and mid-wait abort cases. No new dependencies.
    Is that dirrection okay, and is there a preferred first set of APIs to cover?

  2. Skn0tt commented on Jun 4, 2026

    @Skn0tt
    Contributor

    Tmk (@tmkx) can you elaborate on your usecases for this, maybe with some pseudo code for how it fits into application code? Also please explain the practical benefits you in per-action signals over signal.on('abort', () => browserContext.close()) or page.close().

  3. tmkx commented on Jun 5, 2026

    @tmkx
    ContributorAuthor

    I often need both a task-level cancellation signal and a per-step timeout. timeout is useful for fixed upper bounds, but it does not compose as well when a higher-level workflow wants to cancel several Playwright actions at once. In those cases, I want to abort the wait itself, not close the browser context.

    signal.on('abort', () => browserContext.close()) is too coarse for my use case: I may still need the context alive to collect state, take screenshots, or run cleanup after the cancellation.

    For example:

    async function longTask(page: Page, taskSignal: AbortSignal) {
      // ...
      await page.goto(url, { signal: taskSignal });
      await page.waitFor('...', {
        signal: AbortSignal.any([taskSignal, AbortSignal.timeout(3_000)]),
      });
    }
    
    await longTask(page, AbortSignal.timeout(60_000)); // global signal, or AbortController
    await snapshotState(page);

    so the practical benefit of per-action signal support is more precise cancellation: it lets me cancel a single wait or step without forcing browser/context teardown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions