captchaforge 0.2.39

Captcha detection and solving for Firefox and BiDi-driven browsers. Detection, vendor solver scaffolding, trusted cross-origin click delivery into nested OOPIFs, and stealth personas are implemented and tested; broad live-vendor solve rates are not yet benchmarked.
Documentation
//! Concurrent browser operation tests.

mod common;

#[tokio::test]
async fn two_browsers_independent() {
    let b1 = common::launch_browser().await;
    let b2 = common::launch_browser().await;

    let p1 = b1.new_page("about:blank").await.unwrap();
    let p2 = b2.new_page("about:blank").await.unwrap();

    let _: String = p1
        .evaluate("document.title = 'B1'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let _: String = p2
        .evaluate("document.title = 'B2'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();

    let t1: String = p1
        .evaluate("document.title")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let t2: String = p2
        .evaluate("document.title")
        .await
        .unwrap()
        .into_value()
        .unwrap();

    assert_eq!(t1, "B1");
    assert_eq!(t2, "B2");

    b1.close().await.unwrap();
    b2.close().await.unwrap();
}

#[tokio::test]
async fn sequential_navigations_preserve_state() {
    let browser = common::launch_browser().await;

    let p1 = browser.new_page("about:blank").await.unwrap();
    let _: String = p1
        .evaluate("document.title = 'First'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();

    // Re-navigate the same page to a new blank.
    let p2 = browser.new_page("about:blank").await.unwrap();
    let _: String = p2
        .evaluate("document.title = 'Second'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();

    // p1 and p2 point to the same underlying page, so title is now 'Second'.
    let t2: String = p2
        .evaluate("document.title")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    assert_eq!(t2, "Second");

    browser.close().await.unwrap();
}

#[tokio::test]
async fn concurrent_evaluates_on_same_page() {
    let browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();

    let f1 = page.evaluate("1 + 1");
    let f2 = page.evaluate("2 + 2");
    let f3 = page.evaluate("3 + 3");

    let (r1, r2, r3) = tokio::join!(f1, f2, f3);

    assert_eq!(r1.unwrap().into_value::<i32>().unwrap(), 2);
    assert_eq!(r2.unwrap().into_value::<i32>().unwrap(), 4);
    assert_eq!(r3.unwrap().into_value::<i32>().unwrap(), 6);

    browser.close().await.unwrap();
}