mod common;
use chromewright::tools::{
HoverParams, ScrollParams, SelectParams, SnapshotParams, Tool, ToolContext, WaitCondition,
WaitParams, hover::HoverTool, scroll::ScrollTool, select::SelectTool, snapshot::SnapshotTool,
wait::WaitTool,
};
use log::info;
#[test]
#[ignore] fn test_select_tool() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body>
<select id="country">
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="ca">Canada</option>
</select>
<div id="result"></div>
<script>
document.getElementById('country').addEventListener('change', function(e) {
document.getElementById('result').textContent = 'Selected: ' + e.target.value;
});
</script>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
std::thread::sleep(std::time::Duration::from_millis(500));
let tool = SelectTool::default();
let mut context = ToolContext::new(&session);
let result = tool
.execute_typed(
SelectParams {
selector: Some("#country".to_string()),
index: None,
node_ref: None,
value: "uk".to_string(),
},
&mut context,
)
.expect("Failed to execute select tool");
assert!(result.success, "Tool execution should succeed");
assert!(result.data.is_some());
let data = result.data.unwrap();
info!(
"Select result: {}",
serde_json::to_string_pretty(&data).unwrap()
);
assert_eq!(data["value"].as_str(), Some("uk"));
assert_eq!(data["selectedText"].as_str(), Some("United Kingdom"));
assert_eq!(data["action"].as_str(), Some("select"));
assert_eq!(data["target"]["selector"].as_str(), Some("#country"));
assert!(data["document"]["revision"].as_str().is_some());
assert!(data["snapshot"].is_null());
assert!(data["nodes"].is_null());
}
#[test]
#[ignore]
fn test_hover_tool() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body>
<button id="hover-btn">Hover Me</button>
<div id="result"></div>
<script>
document.getElementById('hover-btn').addEventListener('mouseover', function() {
document.getElementById('result').textContent = 'Hovered!';
});
</script>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
std::thread::sleep(std::time::Duration::from_millis(500));
let tool = HoverTool::default();
let mut context = ToolContext::new(&session);
let result = tool
.execute_typed(
HoverParams {
selector: Some("#hover-btn".to_string()),
index: None,
node_ref: None,
},
&mut context,
)
.expect("Failed to execute hover tool");
assert!(result.success, "Tool execution should succeed");
assert!(result.data.is_some());
let data = result.data.unwrap();
info!(
"Hover result: {}",
serde_json::to_string_pretty(&data).unwrap()
);
assert_eq!(data["action"].as_str(), Some("hover"));
assert_eq!(data["target"]["selector"].as_str(), Some("#hover-btn"));
assert_eq!(data["element"]["tagName"].as_str(), Some("BUTTON"));
}
#[test]
#[ignore]
fn test_scroll_tool_with_amount() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body style="height: 3000px;">
<h1>Top of page</h1>
<div style="margin-top: 1000px;">Middle</div>
<div style="margin-top: 1000px;">Bottom</div>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
std::thread::sleep(std::time::Duration::from_millis(500));
let tool = ScrollTool::default();
let mut context = ToolContext::new(&session);
let result = tool
.execute_typed(ScrollParams { amount: Some(500) }, &mut context)
.expect("Failed to execute scroll tool");
assert!(result.success, "Tool execution should succeed");
assert!(result.data.is_some());
let data = result.data.unwrap();
info!(
"Scroll result: {}",
serde_json::to_string_pretty(&data).unwrap()
);
let scrolled = data["scrolled"].as_i64();
assert!(
scrolled.is_some() && scrolled.unwrap() > 0,
"Should have scrolled"
);
}
#[test]
#[ignore]
fn test_scroll_tool_to_bottom() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body style="height: 2000px;">
<h1>Top of page</h1>
<div style="margin-top: 1800px;">Bottom</div>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
std::thread::sleep(std::time::Duration::from_millis(500));
let tool = ScrollTool::default();
let mut context = ToolContext::new(&session);
for _ in 0..10 {
let result = tool
.execute_typed(ScrollParams { amount: None }, &mut context)
.expect("Failed to execute scroll tool");
assert!(result.success);
let data = result.data.as_ref().unwrap();
let is_at_bottom = data["isAtBottom"].as_bool().unwrap_or(false);
info!(
"Scroll iteration: scrolled={}, isAtBottom={}",
data["scrolled"], is_at_bottom
);
if is_at_bottom {
info!("Reached bottom of page");
break;
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
#[test]
#[ignore]
fn test_select_with_index() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body>
<select id="color">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
std::thread::sleep(std::time::Duration::from_millis(500));
let snapshot_tool = SnapshotTool::default();
let tool = SelectTool::default();
let mut context = ToolContext::new(&session);
let snapshot = snapshot_tool
.execute_typed(SnapshotParams::default(), &mut context)
.expect("Failed to execute snapshot tool");
let node_ref: chromewright::dom::NodeRef =
serde_json::from_value(snapshot.data.unwrap()["nodes"][0]["node_ref"].clone())
.expect("node_ref should deserialize");
let result = tool
.execute_typed(
SelectParams {
selector: None,
index: None,
node_ref: Some(node_ref),
value: "green".to_string(),
},
&mut context,
)
.expect("Select with node_ref should succeed");
assert!(result.success);
let data = result.data.unwrap();
assert_eq!(data["selectedText"].as_str(), Some("Green"));
}
#[test]
#[ignore]
fn test_wait_tool_text_contains() {
let _guard = common::browser_test_guard();
let Some(session) = common::launch_or_skip() else {
return;
};
let html = r#"
<!DOCTYPE html>
<html>
<body>
<div id="status">Loading</div>
<script>
setTimeout(() => {
document.getElementById('status').textContent = 'Ready now';
}, 150);
</script>
</body>
</html>
"#;
let data_url = format!("data:text/html,{}", html);
session.navigate(&data_url).expect("Failed to navigate");
let tool = WaitTool::default();
let mut context = ToolContext::new(&session);
let result = tool
.execute_typed(
WaitParams {
selector: Some("#status".to_string()),
index: None,
node_ref: None,
condition: WaitCondition::TextContains,
text: Some("Ready now".to_string()),
value: None,
since_revision: None,
timeout_ms: 5_000,
},
&mut context,
)
.expect("Wait tool should succeed");
assert!(result.success);
let data = result.data.unwrap();
assert_eq!(data["action"].as_str(), Some("wait"));
assert_eq!(data["condition"].as_str(), Some("text_contains"));
assert!(data["document"]["revision"].as_str().is_some());
}