captchaforge 0.2.36

[DO NOT USE — UNDER ACTIVE DEVELOPMENT, NOT PRODUCTION-READY] Captcha solver scaffolding for chromiumoxide-driven browsers. The architecture is in place (vendor solvers, retry-loop iframe walking, VLM provider abstraction, real-WAF bench harness) but the live-vendor success rate is still 0% — Cloudflare Turnstile / hCaptcha / reCAPTCHA detect us at a TLS / CDP fingerprint layer that no flag-based stealth has cleared. Watch the repo; do not depend on this for any real workload.
Documentation
//! Browser-level integration tests (no CAPTCHA logic, just chromiumoxide ops).

mod common;

#[tokio::test]
async fn browser_launches_and_closes() {
    let mut browser = common::launch_browser().await;
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_navigate_to_blank() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let url: String = page.url().await.unwrap().unwrap_or_default();
    assert!(url.contains("about:blank"));
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_evaluate_returns_value() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let result: i32 = page.evaluate("1 + 1").await.unwrap().into_value().unwrap();
    assert_eq!(result, 2);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_evaluate_sets_and_reads_title() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let _: String = page
        .evaluate("document.title = 'Test Title'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let title: String = page
        .evaluate("document.title")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    assert_eq!(title, "Test Title");
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_evaluate_injects_dom() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let _: String = page
        .evaluate(r#"document.body.innerHTML = '<div id="box">hello</div>'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let text: String = page
        .evaluate("document.getElementById('box').innerText")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    assert_eq!(text, "hello");
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_can_query_selector() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let _: String = page
        .evaluate(r#"document.body.innerHTML = '<button id="btn">Click</button>'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let exists: bool = page
        .evaluate("!!document.querySelector('#btn')")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    assert!(exists);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn local_server_serves_html() {
    let html = r#"<!DOCTYPE html><html><body><h1>Local</h1></body></html>"#.to_string();
    let addr = common::serve_once(html).await;
    let mut browser = common::launch_browser().await;
    let page = browser.new_page(format!("http://{}", addr)).await.unwrap();
    let _title: String = page
        .evaluate("document.title")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    // Title will be empty unless set, just verify page loaded.
    let body: String = page
        .evaluate("document.body.innerHTML")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    assert!(body.contains("Local"));
    browser.close().await.unwrap();
}

#[tokio::test]
async fn multiple_pages_in_one_browser() {
    let mut browser = common::launch_browser().await;
    let p1 = browser.new_page("about:blank").await.unwrap();
    let p2 = browser.new_page("about:blank").await.unwrap();
    let _: String = p1
        .evaluate("document.title = 'Page1'; 'done'")
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let _: String = p2
        .evaluate("document.title = 'Page2'; '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, "Page1");
    assert_eq!(t2, "Page2");
    browser.close().await.unwrap();
}

#[tokio::test]
async fn page_js_error_is_caught() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let result = page.evaluate("throw new Error('boom')").await;
    assert!(result.is_err());
    browser.close().await.unwrap();
}