A test report that says “click timed out after 30 seconds” compresses too much history into one sentence. During those 30 seconds the page may have submitted a form, opened a new tab, thrown a JavaScript exception, received a 401 response, or rendered a disabled control over the original target. The action failure is real, but it is not yet an explanation. WebDriver BiDi is useful precisely because it can preserve the browser-side events that occur between the action and the assertion.
A failure worth instrumenting
Consider a checkout flow that opens a payment provider in a new browsing context. In the local run, the new tab appears and the test continues. In CI, the click succeeds but the test waits in the original context. A screenshot of the original page shows a perfectly normal checkout form. The missing clue is the context event and, sometimes, a blocked popup or failed navigation response.
Before subscribing to everything, write the failure questions:
- Did the page throw an exception after the click?
- Did a navigation start, fail, or move to another context?
- Did the payment request return an unexpected status?
Those questions define a diagnostic fixture. They do not justify adding an event listener to every test in the suite.
Capture around the risky step
The following pseudocode shows the shape of the fixture. The exact client method names vary by language binding, so the important part is the scope and the cleanup.
const events = [];
const stop = await bidi.subscribe([
'log.entryAdded',
'network.responseCompleted',
'browsingContext.contextCreated'
], event => events.push(normalize(event)));await driver.findElement(loginButton).click(); await expect(accountHeading).toBeDisplayed(); await stop(); ~~~
Normalize events before storing them. Keep a URL origin and path pattern instead of a full query string, keep status and timing, and redact response bodies unless the test specifically needs a fixture body. The record should make a decision possible without becoming a second browser archive.
What the evidence looks like
An illustrative event sequence might be:
12:04:10 click checkout
12:04:10 browsingContext.contextCreated context=payment
12:04:10 network.responseCompleted path=/authorize status=401
12:04:10 log.entryAdded level=error message=Missing return URL
12:04:40 assertion timeout context=checkoutThat sequence routes the issue differently from a selector failure. The browser performed the click. The payment request was rejected. The application never provided a usable return path. A support engineer can now inspect the authentication hand-off instead of rewriting the selector.
BiDi is not a free debugging layer
Event names, browser versions, driver versions, and language bindings need a support table. Run the fixture on at least one Chromium and one Firefox version before making it shared. Decide what the test should do when a diagnostic event is unavailable: fail the diagnostic check, skip the optional evidence, or fall back to a screenshot. Do not let missing telemetry turn a passing product test into a false product failure.
Record the runner, browser, driver, operating system, and protocol features with the test result. If a listener changes timing, compare the same journey with and without the listener. A diagnostic tool that creates the flake it is meant to explain is not useful evidence.
Roll out by investigation time
Start with the two flaky flows that cost the most triage time. Compare old reports with the new event sequence, add a redaction test, and ask a second engineer to diagnose a failure using the record alone. Then publish the pattern in the test handbook.
Use a control run to separate product failure from instrumentation failure. Run the journey with the listener disabled, with the listener enabled but no event storage, and with the normalized record written to the CI artifact. If only the last variant fails, the evidence pipeline has become part of the test problem. Keep the diagnostic subscription scoped to the risky action and assert that cleanup runs when the product assertion throws.
The hand-off also benefits from a failure taxonomy. Label a record as action, navigation, context, network, console, or environment failure before assigning an owner. These labels are examples for triage, not a substitute for the trace. Over time, the team can see whether BiDi is reducing investigation time or merely producing more logs.
If the failure is intermittent, compare at least one passing and one failing record with the same fixture. The useful difference may be a response status, a context identifier, or an event ordering change. Keep that comparison in the issue so later fixes can be evaluated against the original failure rather than against a new anecdote.
Our view is that BiDi earns its place when it shortens the path from “something timed out” to “this layer rejected the request.” Keep portable actions in WebDriver, keep event subscriptions narrow, and let the evidence explain why the browser test failed.