Skip to content

[py] Add expect_* context managers for BiDi events#17653

Open
AutomatedTester wants to merge 1 commit into
trunkfrom
py-bidi-expect-events
Open

[py] Add expect_* context managers for BiDi events#17653
AutomatedTester wants to merge 1 commit into
trunkfrom
py-bidi-expect-events

Conversation

@AutomatedTester

@AutomatedTester AutomatedTester commented Jun 6, 2026

Copy link
Copy Markdown
Member

Motivation and Context

Waiting for a BiDi event today requires registering a callback, performing the action, polling with WebDriverWait, and removing the callback by hand — and if the event fires between the action and the first poll registration, it can be missed entirely. This PR adds Playwright-style expect_* context managers that register the event handler before the triggering action runs, eliminating that race and the boilerplate:

with driver.network.expect_response("**/api/**") as response_info:
    driver.find_element(By.ID, "load").click()
response = response_info.value
assert response.status == 200

What's added

Core primitive (py/private/_event_manager.py):

  • Subscription — queue-based capture of the first matching event, .wait(timeout) / .value, cancel(), context-manager protocol that waits for the event on clean with-block exit (raising TimeoutException if it never arrives), idempotent lock-guarded detach.
  • _EventManager.expect(...) plus a raw=True option on add_event_handler so handlers can receive the full wire-level params dict where the generated event dataclasses drop fields (e.g. request/response). Not exposed on the generated modules' public API.

High-level methods (generated via the enhancements manifest):

  • driver.network.expect_request(url_or_predicate) / expect_response(url_or_predicate) — URL glob (*, **, ?) or predicate filtering, wrapping the existing Request/Response classes (observational; no intercept is created).
  • driver.script.expect_console_message(predicate) — built on the existing LogHandlerRegistry, captures ConsoleMessage.
  • driver.browsing_context.expect_user_prompt(predicate) — captures typed UserPromptOpenedParameters; the result's .context feeds straight into handle_user_prompt().
  • driver.browsing_context.expect_download() — correlates downloadWillBegin/downloadEnd by navigation id into a new Download object with suggested_filename, path(), save_as() and failure().

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

No existing public signatures changed; all additions are new methods.

Testing

  • 25 new unit tests (py/test/unit/.../bidi_expect_events_tests.py) covering capture, glob/predicate filtering, timeout (including timeout=0), predicate exceptions, cached value, idempotent/concurrent cancel, detach-after-capture, cross-thread wait, and download correlation/cleanup.
  • 6 new browser-based tests appended to bidi_network_tests.py, bidi_script_tests.py and bidi_browsing_context_tests.py — all passing on Chrome locally (expect_download is xfail_firefox, matching the existing download tests).
  • Existing bidi_network / bidi_script unit suites pass; ./scripts/format.sh clean.

Adds a Subscription primitive to the BiDi event manager that registers
its event handler at creation time, so an event fired by an action
inside the with block cannot be missed:

    with driver.network.expect_response("**/api/**") as response_info:
        driver.find_element(By.ID, "load").click()
    response = response_info.value

New high-level methods generated via the enhancements manifest:
- network.expect_request / network.expect_response (URL glob or
  predicate filtering, observational Request/Response wrappers)
- script.expect_console_message (predicate over ConsoleMessage)
- browsing_context.expect_user_prompt (typed prompt params)
- browsing_context.expect_download, correlating downloadWillBegin and
  downloadEnd by navigation id into a new Download object with path(),
  save_as() and failure()

The event manager gains a raw=True option so expect_* handlers receive
the full wire-level params instead of the generated dataclasses that
drop fields like request/response.

Includes 25 unit tests and 6 browser-based integration tests.
@selenium-ci selenium-ci added the C-py Python Bindings label Jun 6, 2026
@AutomatedTester AutomatedTester added the A-needs decision TLC needs to discuss and agree label Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-needs decision TLC needs to discuss and agree C-py Python Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants