mod common;
use common::{Response, execute, skip_if_no_chrome, spawn};
use earl_protocol_browser::PreparedBrowserCommand;
use earl_protocol_browser::schema::BrowserStep;
use std::collections::HashMap;
#[tokio::test]
async fn handle_dialog_accepts_alert() {
if skip_if_no_chrome() {
return;
}
let _guard = common::chrome_lock().await;
let mut routes = HashMap::new();
routes.insert(
"GET /".to_string(),
Response::html(
r#"<html><body><p>loaded</p><script>window.onload = function() { setTimeout(function() { alert('Hello'); }, 100); };</script></body></html>"#,
),
);
let server = spawn(routes).await;
let data = PreparedBrowserCommand {
session_id: None,
headless: true,
timeout_ms: 30_000,
on_failure_screenshot: false,
steps: vec![
BrowserStep::Navigate {
url: server.url("/"),
expected_status: None,
timeout_ms: None,
optional: false,
},
BrowserStep::HandleDialog {
accept: true,
prompt_text: None,
optional: false,
},
],
};
let result = execute(data)
.await
.expect("execute should succeed — dialog should be accepted");
assert_eq!(
result["ok"].as_bool(),
Some(true),
"HandleDialog result should be {{\"ok\": true}}; got: {result}"
);
}
#[tokio::test]
async fn handle_dialog_fills_prompt_text() {
if skip_if_no_chrome() {
return;
}
let _guard = common::chrome_lock().await;
let mut routes = HashMap::new();
routes.insert(
"GET /".to_string(),
Response::html(
r#"<html><body><script>window.onload = function() { setTimeout(function() { document.title = window.prompt('Enter value') || ''; }, 100); };</script></body></html>"#,
),
);
let server = spawn(routes).await;
let data = PreparedBrowserCommand {
session_id: None,
headless: true,
timeout_ms: 30_000,
on_failure_screenshot: false,
steps: vec![
BrowserStep::Navigate {
url: server.url("/"),
expected_status: None,
timeout_ms: None,
optional: false,
},
BrowserStep::HandleDialog {
accept: true,
prompt_text: Some("my-answer".to_string()),
optional: false,
},
BrowserStep::WaitFor {
time: Some(0.2),
text: None,
text_gone: None,
timeout_ms: Some(2000),
optional: false,
},
BrowserStep::Evaluate {
function: "() => document.title".to_string(),
r#ref: None,
timeout_ms: None,
optional: false,
},
],
};
let result = execute(data).await.expect("execute should succeed");
assert_eq!(
result["value"].as_str(),
Some("my-answer"),
"document.title should equal 'my-answer' after prompt is filled; got: {result}"
);
}
#[tokio::test]
async fn handle_dialog_rejects_confirm() {
if skip_if_no_chrome() {
return;
}
let _guard = common::chrome_lock().await;
let mut routes = HashMap::new();
routes.insert(
"GET /".to_string(),
Response::html(
r#"<html><body><script>window.onload = function() { setTimeout(function() { document.body.textContent = window.confirm('Continue?') ? 'yes' : 'no'; }, 100); };</script></body></html>"#,
),
);
let server = spawn(routes).await;
let data = PreparedBrowserCommand {
session_id: None,
headless: true,
timeout_ms: 30_000,
on_failure_screenshot: false,
steps: vec![
BrowserStep::Navigate {
url: server.url("/"),
expected_status: None,
timeout_ms: None,
optional: false,
},
BrowserStep::HandleDialog {
accept: false,
prompt_text: None,
optional: false,
},
BrowserStep::WaitFor {
time: None,
text: Some("no".to_string()),
text_gone: None,
timeout_ms: Some(2000),
optional: false,
},
BrowserStep::Evaluate {
function: "() => document.body.textContent.trim()".to_string(),
r#ref: None,
timeout_ms: None,
optional: false,
},
],
};
let result = execute(data).await.expect("execute should succeed");
assert_eq!(
result["value"].as_str(),
Some("no"),
"body text should be 'no' after confirm is rejected; got: {result}"
);
}
#[tokio::test]
async fn handle_dialog_times_out_when_no_dialog_fires() {
if skip_if_no_chrome() {
return;
}
let _guard = common::chrome_lock().await;
let mut routes = HashMap::new();
routes.insert(
"GET /".to_string(),
Response::html("<html><body>no dialog here</body></html>"),
);
let server = spawn(routes).await;
let data = PreparedBrowserCommand {
session_id: None,
headless: true,
timeout_ms: 2_000, on_failure_screenshot: false,
steps: vec![
BrowserStep::Navigate {
url: server.url("/"),
expected_status: None,
timeout_ms: None,
optional: false,
},
BrowserStep::HandleDialog {
accept: true,
prompt_text: None,
optional: false,
},
],
};
let err = execute(data)
.await
.expect_err("HandleDialog should time out when no dialog fires");
let msg = err.to_string().to_lowercase();
assert!(
msg.contains("timeout") || msg.contains("timed out") || msg.contains("time"),
"error should mention timeout; got: {msg}"
);
}