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
//! Frame-piercing integration tests.

use captchaforge::frame::{
    evaluate_in_all_frames, find_element_centre_in_frames, verify_token_in_frames,
};

mod common;

#[tokio::test]
async fn evaluate_in_all_frames_main_document() {
    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="a">hello</div>'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let results: Vec<String> = evaluate_in_all_frames(&page, "document.body.innerText")
        .await
        .unwrap();
    assert!(!results.is_empty());
    assert!(results.iter().any(|r| r.contains("hello")));
    browser.close().await.unwrap();
}

#[tokio::test]
async fn evaluate_in_all_frames_with_iframe() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let html = r#"
        <body>
            <iframe id="f1" srcdoc="<div id='inner'>iframe text</div>"></iframe>
        </body>
    "#;
    let _: String = page
        .evaluate(format!("document.body.innerHTML = `{}`; 'done'", html))
        .await
        .unwrap()
        .into_value()
        .unwrap();
    // Give the iframe time to load.
    tokio::time::sleep(std::time::Duration::from_millis(500)).await;
    let results: Vec<String> = evaluate_in_all_frames(&page, "document.body.innerText || ''")
        .await
        .unwrap();
    assert!(!results.is_empty());
    browser.close().await.unwrap();
}

#[tokio::test]
async fn find_element_centre_in_frames_finds_main_doc_element() {
    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" style="position:absolute;left:100px;top:200px;width:50px;height:50px;">X</button>'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let centre = find_element_centre_in_frames(&page, "#btn").await.unwrap();
    assert!(centre.is_some());
    let (x, y) = centre.unwrap();
    assert!((x - 125.0).abs() < 5.0, "expected x ~125, got {}", x);
    assert!((y - 225.0).abs() < 5.0, "expected y ~225, got {}", y);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn find_element_centre_in_frames_returns_none_for_missing() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let centre = find_element_centre_in_frames(&page, "#nonexistent")
        .await
        .unwrap();
    assert!(centre.is_none());
    browser.close().await.unwrap();
}

#[tokio::test]
async fn verify_token_in_frames_false_when_no_input() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let found = verify_token_in_frames(&page, "g-recaptcha-response")
        .await
        .unwrap();
    assert!(!found);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn verify_token_in_frames_true_when_input_has_value() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let _: String = page
        .evaluate(r#"document.body.innerHTML = '<input name="g-recaptcha-response" value="token123">'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let found = verify_token_in_frames(&page, "g-recaptcha-response")
        .await
        .unwrap();
    assert!(found);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn verify_token_in_frames_false_when_input_empty() {
    let mut browser = common::launch_browser().await;
    let page = browser.new_page("about:blank").await.unwrap();
    let _: String = page
        .evaluate(
            r#"document.body.innerHTML = '<input name="g-recaptcha-response" value="">'; 'done'"#,
        )
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let found = verify_token_in_frames(&page, "g-recaptcha-response")
        .await
        .unwrap();
    assert!(!found);
    browser.close().await.unwrap();
}

#[tokio::test]
async fn find_element_centre_in_frames_with_complex_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 = '<div data-test="value" style="position:absolute;left:10px;top:20px;width:30px;height:40px;"></div>'; 'done'"#)
        .await
        .unwrap()
        .into_value()
        .unwrap();
    let centre = find_element_centre_in_frames(&page, "[data-test='value']")
        .await
        .unwrap();
    assert!(centre.is_some());
    browser.close().await.unwrap();
}