browser_use/dom/
selector_map.rs1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6pub struct ElementSelector {
7 pub css_selector: String,
9
10 #[serde(skip_serializing_if = "Option::is_none")]
12 pub xpath: Option<String>,
13
14 pub tag_name: String,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub id: Option<String>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub text: Option<String>,
24}
25
26impl ElementSelector {
27 pub fn new(css_selector: impl Into<String>, tag_name: impl Into<String>) -> Self {
29 Self {
30 css_selector: css_selector.into(),
31 xpath: None,
32 tag_name: tag_name.into(),
33 id: None,
34 text: None,
35 }
36 }
37
38 pub fn with_xpath(mut self, xpath: impl Into<String>) -> Self {
40 self.xpath = Some(xpath.into());
41 self
42 }
43
44 pub fn with_id(mut self, id: impl Into<String>) -> Self {
46 self.id = Some(id.into());
47 self
48 }
49
50 pub fn with_text(mut self, text: impl Into<String>) -> Self {
52 self.text = Some(text.into());
53 self
54 }
55
56 pub fn best_selector(&self) -> &str {
58 &self.css_selector
59 }
60}
61
62#[derive(Debug, Clone, Default)]
65pub struct SelectorMap {
66 map: IndexMap<usize, ElementSelector>,
68
69 next_index: usize,
71}
72
73impl SelectorMap {
74 pub fn new() -> Self {
76 Self {
77 map: IndexMap::new(),
78 next_index: 0,
79 }
80 }
81
82 pub fn register(&mut self, selector: ElementSelector) -> usize {
84 let index = self.next_index;
85 self.map.insert(index, selector);
86 self.next_index += 1;
87 index
88 }
89
90 pub fn get(&self, index: usize) -> Option<&ElementSelector> {
92 self.map.get(&index)
93 }
94
95 pub fn get_mut(&mut self, index: usize) -> Option<&mut ElementSelector> {
97 self.map.get_mut(&index)
98 }
99
100 pub fn contains(&self, index: usize) -> bool {
102 self.map.contains_key(&index)
103 }
104
105 pub fn remove(&mut self, index: usize) -> Option<ElementSelector> {
107 self.map.shift_remove(&index)
108 }
109
110 pub fn len(&self) -> usize {
112 self.map.len()
113 }
114
115 pub fn is_empty(&self) -> bool {
117 self.map.is_empty()
118 }
119
120 pub fn clear(&mut self) {
122 self.map.clear();
123 self.next_index = 0;
124 }
125
126 pub fn iter(&self) -> impl Iterator<Item = (&usize, &ElementSelector)> {
128 self.map.iter()
129 }
130
131 pub fn indices(&self) -> impl Iterator<Item = &usize> {
133 self.map.keys()
134 }
135
136 pub fn selectors(&self) -> impl Iterator<Item = &ElementSelector> {
138 self.map.values()
139 }
140
141 pub fn find_by_css_selector(&self, css_selector: &str) -> Option<usize> {
143 self.map
144 .iter()
145 .find(|(_, sel)| sel.css_selector == css_selector)
146 .map(|(idx, _)| *idx)
147 }
148
149 pub fn find_by_id(&self, id: &str) -> Option<usize> {
151 self.map
152 .iter()
153 .find(|(_, sel)| sel.id.as_deref() == Some(id))
154 .map(|(idx, _)| *idx)
155 }
156
157 pub fn to_json(&self) -> Result<String, serde_json::Error> {
159 serde_json::to_string_pretty(&self.map)
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_element_selector() {
169 let selector = ElementSelector::new("#my-button", "button")
170 .with_id("my-button")
171 .with_text("Click me");
172
173 assert_eq!(selector.css_selector, "#my-button");
174 assert_eq!(selector.tag_name, "button");
175 assert_eq!(selector.id, Some("my-button".to_string()));
176 assert_eq!(selector.text, Some("Click me".to_string()));
177 assert_eq!(selector.best_selector(), "#my-button");
178 }
179
180 #[test]
181 fn test_selector_map_register() {
182 let mut map = SelectorMap::new();
183
184 let selector1 = ElementSelector::new("#btn1", "button");
185 let selector2 = ElementSelector::new("#btn2", "button");
186
187 let idx1 = map.register(selector1);
188 let idx2 = map.register(selector2);
189
190 assert_eq!(idx1, 0);
191 assert_eq!(idx2, 1);
192 assert_eq!(map.len(), 2);
193 }
194
195 #[test]
196 fn test_selector_map_get() {
197 let mut map = SelectorMap::new();
198
199 let selector = ElementSelector::new("#test", "div").with_id("test");
200 let index = map.register(selector);
201
202 let retrieved = map.get(index).unwrap();
203 assert_eq!(retrieved.css_selector, "#test");
204 assert_eq!(retrieved.id, Some("test".to_string()));
205 }
206
207 #[test]
208 fn test_selector_map_remove() {
209 let mut map = SelectorMap::new();
210
211 let selector = ElementSelector::new("#remove-me", "span");
212 let index = map.register(selector);
213
214 assert!(map.contains(index));
215
216 let removed = map.remove(index);
217 assert!(removed.is_some());
218 assert!(!map.contains(index));
219 assert_eq!(map.len(), 0);
220 }
221
222 #[test]
223 fn test_selector_map_clear() {
224 let mut map = SelectorMap::new();
225
226 map.register(ElementSelector::new("#one", "div"));
227 map.register(ElementSelector::new("#two", "div"));
228 map.register(ElementSelector::new("#three", "div"));
229
230 assert_eq!(map.len(), 3);
231
232 map.clear();
233
234 assert_eq!(map.len(), 0);
235 assert!(map.is_empty());
236 }
237
238 #[test]
239 fn test_selector_map_find() {
240 let mut map = SelectorMap::new();
241
242 let selector1 = ElementSelector::new("#btn1", "button").with_id("btn1");
243 let selector2 = ElementSelector::new(".link", "a").with_id("link1");
244
245 let idx1 = map.register(selector1);
246 let _idx2 = map.register(selector2);
247
248 let found = map.find_by_css_selector("#btn1");
249 assert_eq!(found, Some(idx1));
250
251 let found_by_id = map.find_by_id("link1");
252 assert_eq!(found_by_id, Some(1));
253
254 let not_found = map.find_by_css_selector("#nonexistent");
255 assert!(not_found.is_none());
256 }
257
258 #[test]
259 fn test_selector_map_iteration() {
260 let mut map = SelectorMap::new();
261
262 map.register(ElementSelector::new("#one", "div"));
263 map.register(ElementSelector::new("#two", "div"));
264 map.register(ElementSelector::new("#three", "div"));
265
266 let indices: Vec<_> = map.indices().copied().collect();
267 assert_eq!(indices, vec![0, 1, 2]);
268
269 let css_selectors: Vec<_> = map.selectors().map(|s| s.css_selector.clone()).collect();
270 assert_eq!(css_selectors, vec!["#one", "#two", "#three"]);
271 }
272
273 #[test]
274 fn test_selector_serialization() {
275 let selector = ElementSelector::new("#test", "button")
276 .with_id("test")
277 .with_text("Test Button");
278
279 let json = serde_json::to_string(&selector).unwrap();
280 let deserialized: ElementSelector = serde_json::from_str(&json).unwrap();
281
282 assert_eq!(selector, deserialized);
283 }
284
285 #[test]
286 fn test_selector_map_to_json() {
287 let mut map = SelectorMap::new();
288
289 map.register(ElementSelector::new("#btn", "button").with_text("Click"));
290 map.register(ElementSelector::new("#link", "a").with_text("Visit"));
291
292 let json = map.to_json().unwrap();
293 assert!(json.contains("#btn"));
294 assert!(json.contains("#link"));
295 assert!(json.contains("Click"));
296 assert!(json.contains("Visit"));
297 }
298}