browser_use/tools/
click.rs1use crate::error::{BrowserError, Result};
2use crate::tools::{Tool, ToolContext, ToolResult};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
8pub struct ClickParams {
9 #[serde(flatten)]
11 pub selector: ElementSelector,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
15#[serde(untagged)]
16pub enum ElementSelector {
17 Css {
19 selector: String,
21 },
22 Index {
24 index: usize,
26 },
27}
28
29#[derive(Default)]
31pub struct ClickTool;
32
33impl Tool for ClickTool {
34 type Params = ClickParams;
35
36 fn name(&self) -> &str {
37 "click"
38 }
39
40 fn execute_typed(&self, params: ClickParams, context: &mut ToolContext) -> Result<ToolResult> {
41 match params.selector {
42 ElementSelector::Css { selector } => {
43 let element = context.session.find_element(&selector)?;
44 element
45 .click()
46 .map_err(|e| BrowserError::ToolExecutionFailed {
47 tool: "click".to_string(),
48 reason: e.to_string(),
49 })?;
50
51 Ok(ToolResult::success_with(serde_json::json!({
52 "selector": selector,
53 "method": "css"
54 })))
55 }
56 ElementSelector::Index { index } => {
57 let css_selector = {
58 let dom = context.get_dom()?;
59 let selector_info = dom.get_selector(index).ok_or_else(|| {
60 BrowserError::ElementNotFound(format!("No element with index {}", index))
61 })?;
62 selector_info.css_selector.clone()
63 };
64
65 let element = context.session.find_element(&css_selector)?;
66 element
67 .click()
68 .map_err(|e| BrowserError::ToolExecutionFailed {
69 tool: "click".to_string(),
70 reason: e.to_string(),
71 })?;
72
73 Ok(ToolResult::success_with(serde_json::json!({
74 "index": index,
75 "selector": css_selector,
76 "method": "index"
77 })))
78 }
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_click_params_css() {
89 let json = serde_json::json!({
90 "selector": "#my-button"
91 });
92
93 let params: ClickParams = serde_json::from_value(json).unwrap();
94 match params.selector {
95 ElementSelector::Css { selector } => assert_eq!(selector, "#my-button"),
96 _ => panic!("Expected CSS selector"),
97 }
98 }
99
100 #[test]
101 fn test_click_params_index() {
102 let json = serde_json::json!({
103 "index": 5
104 });
105
106 let params: ClickParams = serde_json::from_value(json).unwrap();
107 match params.selector {
108 ElementSelector::Index { index } => assert_eq!(index, 5),
109 _ => panic!("Expected index selector"),
110 }
111 }
112}