Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CDP And BiDi

Keep protocol-specific code behind a small boundary. CDP is Chromium-only and enabled by thirtyfour’s default features. BiDi is the W3C cross-browser path, but it requires both a Cargo feature and a session capability. The currently documented and tested implementations are Chromium with chromedriver 115 or newer and Firefox with geckodriver 0.31 or newer.

Clear Chromium’s Cache With CDP

#![allow(unused)]
fn main() {
use thirtyfour::prelude::*;

#[tokio::test]
async fn clears_the_browser_cache() -> WebDriverResult<()> {
    let driver = WebDriver::managed(DesiredCapabilities::chrome()).await?;

    let test_result: WebDriverResult<()> = async {
        driver.goto("https://example.test/catalogue").await?;
        driver.cdp().network().clear_browser_cache().await?;

        let version = driver.cdp().browser().get_version().await?;
        println!("cleared cache in {}", version.product);
        Ok(())
    }
    .await;

    let quit_result = driver.quit().await;
    test_result?;
    quit_result
}
}

This recipe needs the cdp feature, which is enabled by default, and a Chromium-backed driver. Typed commands use the existing WebDriver connection; no event WebSocket is required. See the CDP guide for supported domains and the untyped escape hatch.

Subscribe To A BiDi Load Event

Enable the optional bidi feature and add futures-util for StreamExt:

[dependencies]
futures-util = "0.3"
thirtyfour = { version = "0.37.4", features = ["bidi"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
#![allow(unused)]
fn main() {
use std::time::Duration;
use futures_util::StreamExt;
use thirtyfour::bidi::events::Load;
use thirtyfour::prelude::*;

#[tokio::test]
async fn observes_a_page_load() -> WebDriverResult<()> {
    let mut caps = DesiredCapabilities::chrome();
    caps.enable_bidi()?;
    let driver = WebDriver::managed(caps).await?;

    let test_result: WebDriverResult<()> = async {
        let bidi = driver.bidi().await?;
        let mut loads = bidi.subscribe::<Load>().await?;
        let context = bidi.browsing_context().top_level().await?;

        bidi.browsing_context()
            .navigate(context, "https://example.test/dashboard", None)
            .await?;
        let load = tokio::time::timeout(Duration::from_secs(10), loads.next())
            .await
            .map_err(|_| WebDriverError::Timeout("BiDi load event timed out".into()))?
            .ok_or_else(|| WebDriverError::FatalError("BiDi event stream closed".into()))?;
        println!("loaded: {}", load.url);

        // Dropping the last typed stream schedules a best-effort unsubscribe.
        drop(loads);
        Ok(())
    }
    .await;

    let quit_result = driver.quit().await;
    test_result?;
    quit_result
}
}

enable_bidi() requests the WebSocket URL during session creation, and subscribe::<Load>() subscribes while the typed stream is alive. Dropping the last stream schedules a best-effort background unsubscribe; the following driver.quit() closes the WebDriver session regardless. The BiDi overview covers browser support, and the BiDi Events guide covers typed streams, scoping, and interception.