use captchaforge::detect::detect;
use captchaforge::solver::{
BehavioralCaptchaSolver, CaptchaSolver, CaptchaSolverChain, SolveConfig,
};
mod common;
#[tokio::test]
async fn behavioral_solver_runs_on_turnstile_mock() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"
document.body.innerHTML = '<div class="cf-turnstile" data-sitekey="test"></div>' +
'<script src="https://challenges.cloudflare.com/turnstile/v0/api.js"></script>';
"true"
"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let solver = BehavioralCaptchaSolver::new();
let result = solver.solve(&page, &info).await.unwrap();
assert!(!result.success || result.solution.is_empty());
browser.close().await.unwrap();
}
#[tokio::test]
async fn default_chain_runs_on_unknown_page() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"document.body.innerHTML = '<h1>Nothing here</h1>'; 'done'"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let chain = CaptchaSolverChain::default_chain();
let result = chain.solve(&page, &info).await;
assert!(!result.success);
browser.close().await.unwrap();
}
#[tokio::test]
async fn default_chain_runs_on_recaptcha_mock() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"
document.body.innerHTML = '<div class="g-recaptcha" data-sitekey="test"></div>' +
'<script src="https://www.google.com/recaptcha/api.js"></script>';
"true"
"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let chain = CaptchaSolverChain::default_chain();
let result = chain.solve(&page, &info).await;
assert!(!result.success || result.time_ms > 0);
browser.close().await.unwrap();
}
#[tokio::test]
async fn default_chain_runs_on_hcaptcha_mock() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"
document.body.innerHTML = '<div class="h-captcha" data-sitekey="test"></div>' +
'<script src="https://js.hcaptcha.com/1/api.js"></script>';
"true"
"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let chain = CaptchaSolverChain::default_chain();
let result = chain.solve(&page, &info).await;
assert!(!result.success || result.time_ms > 0);
browser.close().await.unwrap();
}
#[tokio::test]
async fn solver_name_is_non_empty() {
let solver = BehavioralCaptchaSolver::new();
assert!(!solver.name().is_empty());
}
#[tokio::test]
async fn solve_config_custom_values_used() {
let config = SolveConfig {
checkbox_poll_interval_ms: 50,
checkbox_max_attempts: 1,
token_poll_interval_ms: 50,
token_max_attempts: 1,
audio_button_delay_ms: 50,
audio_submit_delay_ms: 50,
vlm_http_timeout_ms: 500,
client_http_timeout_ms: 500,
};
assert_eq!(config.checkbox_poll_interval_ms, 50);
assert_eq!(config.checkbox_max_attempts, 1);
}
#[tokio::test]
async fn empty_chain_on_image_captcha() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"
document.body.innerHTML = '<div class="captcha"><img src="/captcha.png"></div>';
"true"
"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let chain = CaptchaSolverChain::empty();
let result = chain.solve(&page, &info).await;
assert!(!result.success);
browser.close().await.unwrap();
}
#[tokio::test]
async fn chain_with_added_solver() {
let mut browser = common::launch_browser().await;
let page = browser.new_page("about:blank").await.unwrap();
let js = r#"
document.body.innerHTML = '<div class="cf-turnstile" data-sitekey="test"></div>';
"true"
"#;
let _: String = page.evaluate(js).await.unwrap().into_value().unwrap();
let info = detect(&page).await.unwrap();
let mut chain = CaptchaSolverChain::empty();
chain.add_solver(BehavioralCaptchaSolver::new());
let result = chain.solve(&page, &info).await;
assert!(!result.success || result.time_ms > 0);
browser.close().await.unwrap();
}
#[tokio::test]
async fn behavioral_solver_method_is_behavioral() {
let solver = BehavioralCaptchaSolver::new();
assert_eq!(
solver.method(),
captchaforge::solver::SolveMethod::BehavioralBypass
);
}