1use crate::imp::{
2 core::*,
3 frame::Frame,
4 prelude::*,
5 utils::{
6 ElementState, File, FloatRect, KeyboardModifier, MouseButton, Position, ScreenshotType,
7 WaitForSelectorState
8 }
9};
10
11#[derive(Debug)]
12pub(crate) struct ElementHandle {
13 channel: ChannelOwner
14}
15
16macro_rules! is_checked {
17 ($f: ident, $m: literal) => {
18 pub(crate) async fn $f(&self) -> ArcResult<bool> {
19 let v = send_message!(self, $m, Map::new());
20 let b = first(&v)
21 .ok_or(Error::InvalidParams)?
22 .as_bool()
23 .ok_or(Error::InvalidParams)?;
24 Ok(b)
25 }
26 };
27}
28
29impl ElementHandle {
30 pub(crate) fn new(channel: ChannelOwner) -> Self { Self { channel } }
31
32 pub(crate) async fn query_selector(
33 &self,
34 selector: &str
35 ) -> ArcResult<Option<Weak<ElementHandle>>> {
36 let mut args = HashMap::new();
37 args.insert("selector", selector);
38 let v = send_message!(self, "querySelector", args);
39 let guid = match as_only_guid(&v) {
40 Some(g) => g,
41 None => return Ok(None)
42 };
43 let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
44 Ok(Some(e))
45 }
46
47 pub(crate) async fn query_selector_all(
48 &self,
49 selector: &str
50 ) -> ArcResult<Vec<Weak<ElementHandle>>> {
51 let mut args = HashMap::new();
52 args.insert("selector", selector);
53 let v = send_message!(self, "querySelectorAll", args);
54 let first = first(&v).ok_or(Error::InvalidParams)?;
55 let elements: Vec<OnlyGuid> =
56 serde_json::from_value((*first).clone()).map_err(Error::Serde)?;
57 let es = elements
58 .into_iter()
59 .map(|OnlyGuid { guid }| {
60 get_object!(self.context()?.lock().unwrap(), &guid, ElementHandle)
61 })
62 .collect::<Result<Vec<_>, Error>>()?;
63 Ok(es)
64 }
65
66 pub(crate) async fn inner_text(&self) -> ArcResult<String> {
67 let v = send_message!(self, "innerText", Map::new());
68 let s = only_str(&v)?;
69 Ok(s.to_owned())
70 }
71
72 pub(crate) async fn inner_html(&self) -> ArcResult<String> {
73 let v = send_message!(self, "innerHTML", Map::new());
74 let s = only_str(&v)?;
75 Ok(s.to_owned())
76 }
77
78 is_checked! {is_checked, "isChecked"}
79 is_checked! {is_disabled, "isDisabled"}
80 is_checked! {is_editable, "isEditable"}
81 is_checked! {is_enabled, "isEnabled"}
82 is_checked! {is_hidden, "isHidden"}
83 is_checked! {is_visible, "isVisible"}
84
85 pub(crate) async fn owner_frame(&self) -> ArcResult<Option<Weak<Frame>>> {
86 let v = send_message!(self, "ownerFrame", Map::new());
87 let guid = match as_only_guid(&v) {
88 Some(g) => g,
89 None => return Ok(None)
90 };
91 let f = get_object!(self.context()?.lock().unwrap(), guid, Frame)?;
92 Ok(Some(f))
93 }
94
95 pub(crate) async fn content_frame(&self) -> ArcResult<Option<Weak<Frame>>> {
96 let v = send_message!(self, "contentFrame", Map::new());
97 let guid = match as_only_guid(&v) {
98 Some(g) => g,
99 None => return Ok(None)
100 };
101 let f = get_object!(self.context()?.lock().unwrap(), guid, Frame)?;
102 Ok(Some(f))
103 }
104
105 pub(crate) async fn get_attribute(&self, name: &str) -> ArcResult<Option<String>> {
106 let mut args = HashMap::new();
107 args.insert("name", name);
108 let v = send_message!(self, "getAttribute", args);
109 let s = maybe_only_str(&v)?;
110 Ok(s.map(ToOwned::to_owned))
111 }
112
113 pub(crate) async fn text_content(&self) -> ArcResult<Option<String>> {
114 let v = send_message!(self, "textContent", Map::new());
115 let s = maybe_only_str(&v)?;
116 Ok(s.map(ToOwned::to_owned))
117 }
118
119 pub(crate) async fn hover(&self, args: HoverArgs) -> ArcResult<()> {
120 let _ = send_message!(self, "hover", args);
121 Ok(())
122 }
123
124 pub(crate) async fn click(&self, args: ClickArgs) -> ArcResult<()> {
125 let _ = send_message!(self, "click", args);
126 Ok(())
127 }
128
129 pub(crate) async fn dblclick(&self, args: ClickArgs) -> ArcResult<()> {
130 let _ = send_message!(self, "dblclick", args);
131 Ok(())
132 }
133
134 pub(crate) async fn check(&self, args: CheckArgs) -> ArcResult<()> {
135 let _ = send_message!(self, "check", args);
136 Ok(())
137 }
138
139 pub(crate) async fn uncheck(&self, args: CheckArgs) -> ArcResult<()> {
140 let _ = send_message!(self, "uncheck", args);
141 Ok(())
142 }
143
144 pub(crate) async fn tap(&self, args: TapArgs) -> ArcResult<()> {
145 let _ = send_message!(self, "tap", args);
146 Ok(())
147 }
148
149 pub(crate) async fn fill(&self, args: FillArgs<'_>) -> ArcResult<()> {
150 let _ = send_message!(self, "fill", args);
151 Ok(())
152 }
153
154 pub(crate) async fn focus(&self) -> ArcResult<()> {
155 let _ = send_message!(self, "focus", Map::new());
156 Ok(())
157 }
158
159 pub(crate) async fn r#type(&self, args: TypeArgs<'_>) -> ArcResult<()> {
160 let _ = send_message!(self, "type", args);
161 Ok(())
162 }
163
164 pub(crate) async fn press(&self, args: PressArgs<'_>) -> ArcResult<()> {
165 let _ = send_message!(self, "press", args);
166 Ok(())
167 }
168
169 pub(crate) async fn scroll_into_view_if_needed(&self, timeout: Option<f64>) -> ArcResult<()> {
170 #[skip_serializing_none]
171 #[derive(Serialize)]
172 #[serde(rename_all = "camelCase")]
173 struct Args {
174 timeout: Option<f64>
175 }
176 let args = Args { timeout };
177 let _ = send_message!(self, "scrollIntoViewIfNeeded", args);
178 Ok(())
179 }
180
181 pub(crate) async fn select_text(&self, timeout: Option<f64>) -> ArcResult<()> {
182 #[skip_serializing_none]
183 #[derive(Serialize)]
184 #[serde(rename_all = "camelCase")]
185 struct Args {
186 timeout: Option<f64>
187 }
188 let args = Args { timeout };
189 let _ = send_message!(self, "selectText", args);
190 Ok(())
191 }
192
193 pub(crate) async fn bounding_box(&self) -> ArcResult<Option<FloatRect>> {
194 let v = send_message!(self, "boundingBox", Map::new());
195 let v = match first(&v) {
196 None => return Ok(None),
197 Some(v) => v
198 };
199 let f: FloatRect = serde_json::from_value((*v).clone()).map_err(Error::Serde)?;
200 Ok(Some(f))
201 }
202
203 pub(crate) async fn screenshot(&self, args: ScreenshotArgs<'_>) -> ArcResult<Vec<u8>> {
204 let path = args.path.clone();
205 let v = send_message!(self, "screenshot", args);
206 let b64 = only_str(&v)?;
207 let bytes = base64::decode(b64).map_err(Error::InvalidBase64)?;
208 may_save(path.as_deref(), &bytes)?;
209 Ok(bytes)
210 }
211
212 pub(crate) async fn wait_for_element_state(
213 &self,
214 state: ElementState,
215 timeout: Option<f64>
216 ) -> ArcResult<()> {
217 #[skip_serializing_none]
218 #[derive(Serialize)]
219 #[serde(rename_all = "camelCase")]
220 struct Args {
221 state: ElementState,
222 timeout: Option<f64>
223 }
224 let args = Args { state, timeout };
225 let _ = send_message!(self, "waitForElementState", args);
226 Ok(())
227 }
228
229 pub(crate) async fn wait_for_selector(
230 &self,
231 args: WaitForSelectorArgs<'_>
232 ) -> ArcResult<Option<Weak<ElementHandle>>> {
233 let v = send_message!(self, "waitForSelector", args);
234 let guid = match as_only_guid(&v) {
235 Some(g) => g,
236 None => return Ok(None)
237 };
238 let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
239 Ok(Some(e))
240 }
241
242 pub(crate) async fn dispatch_event<T>(
243 &self,
244 r#type: &str,
245 event_init: Option<T>
246 ) -> ArcResult<()>
247 where
248 T: Serialize
249 {
250 #[derive(Serialize)]
251 #[serde(rename_all = "camelCase")]
252 struct Args<'a> {
253 r#type: &'a str,
254 event_init: Value
255 }
256 let event_init = ser::to_value(&event_init).map_err(Error::SerializationPwJson)?;
257 let args = Args { r#type, event_init };
258 let _ = send_message!(self, "dispatchEvent", args);
259 Ok(())
260 }
261
262 pub(crate) async fn select_option(&self, args: SelectOptionArgs) -> ArcResult<Vec<String>> {
263 let v = send_message!(self, "selectOption", args);
264 let first = first(&v).ok_or(Error::InvalidParams)?;
265 let ss = first
266 .as_array()
267 .ok_or(Error::InvalidParams)?
268 .iter()
269 .filter_map(|v| v.as_str())
270 .map(ToOwned::to_owned)
271 .collect();
272 Ok(ss)
273 }
274
275 pub(crate) async fn set_input_files(&self, args: SetInputFilesArgs) -> ArcResult<()> {
276 let _ = send_message!(self, "setInputFiles", args);
277 Ok(())
278 }
279}
280
281pub(super) fn may_save(path: Option<&Path>, bytes: &[u8]) -> Result<(), Error> {
282 let path = match path {
283 Some(path) => path,
284 None => return Ok(())
285 };
286 use std::io::Write;
287 let mut file = std::fs::File::create(path).map_err(Error::from)?;
288 file.write(bytes).map_err(Error::from)?;
289 Ok(())
290}
291
292#[skip_serializing_none]
293#[derive(Serialize, Default)]
294#[serde(rename_all = "camelCase")]
295pub(crate) struct HoverArgs {
296 pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
297 pub(crate) position: Option<Position>,
298 pub(crate) timeout: Option<f64>,
299 pub(crate) force: Option<bool>,
300 pub(crate) trial: Option<bool>
301}
302
303#[skip_serializing_none]
304#[derive(Serialize, Default)]
305#[serde(rename_all = "camelCase")]
306pub(crate) struct ClickArgs {
307 pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
308 pub(crate) position: Option<Position>,
309 pub(crate) delay: Option<f64>,
310 pub(crate) button: Option<MouseButton>,
311 pub(crate) click_count: Option<i32>,
313 pub(crate) timeout: Option<f64>,
314 pub(crate) force: Option<bool>,
315 pub(crate) no_wait_after: Option<bool>,
316 pub(crate) trial: Option<bool>
317}
318
319#[skip_serializing_none]
320#[derive(Serialize, Default)]
321#[serde(rename_all = "camelCase")]
322pub(crate) struct CheckArgs {
323 pub(crate) position: Option<Position>,
324 pub(crate) timeout: Option<f64>,
325 pub(crate) force: Option<bool>,
326 pub(crate) no_wait_after: Option<bool>,
327 pub(crate) trial: Option<bool>
328}
329
330#[skip_serializing_none]
331#[derive(Serialize, Default)]
332#[serde(rename_all = "camelCase")]
333pub(crate) struct TapArgs {
334 pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
335 pub(crate) position: Option<Position>,
336 pub(crate) timeout: Option<f64>,
337 pub(crate) force: Option<bool>,
338 pub(crate) no_wait_after: Option<bool>,
339 pub(crate) trial: Option<bool>
340}
341
342#[skip_serializing_none]
343#[derive(Serialize)]
344#[serde(rename_all = "camelCase")]
345pub(crate) struct FillArgs<'a> {
346 value: &'a str,
347 pub(crate) timeout: Option<f64>,
348 pub(crate) no_wait_after: Option<bool>
349}
350
351impl<'a> FillArgs<'a> {
352 pub(crate) fn new(value: &'a str) -> Self {
353 Self {
354 value,
355 timeout: Some(30000.0),
356 no_wait_after: None
357 }
358 }
359}
360
361macro_rules! type_args {
362 ($t:ident, $f:ident) => {
363 #[skip_serializing_none]
364 #[derive(Serialize)]
365 #[serde(rename_all = "camelCase")]
366 pub(crate) struct $t<'a> {
367 $f: &'a str,
368 pub(crate) delay: Option<f64>,
369 pub(crate) timeout: Option<f64>,
370 pub(crate) no_wait_after: Option<bool>
371 }
372
373 impl<'a> $t<'a> {
374 pub(crate) fn new($f: &'a str) -> Self {
375 Self {
376 $f,
377 delay: None,
378 timeout: Some(30000.0),
379 no_wait_after: None
380 }
381 }
382 }
383 };
384}
385
386type_args! {TypeArgs, text}
387type_args! {PressArgs, key}
388
389#[skip_serializing_none]
390#[derive(Serialize, Default)]
391#[serde(rename_all = "camelCase")]
392pub(crate) struct ScreenshotArgs<'a> {
393 pub(crate) path: Option<&'a Path>,
394 pub(crate) timeout: Option<f64>,
395 pub(crate) r#type: Option<ScreenshotType>,
396 pub(crate) quality: Option<i64>,
397 pub(crate) omit_background: Option<bool>
398}
399
400#[skip_serializing_none]
401#[derive(Serialize)]
402#[serde(rename_all = "camelCase")]
403pub(crate) struct WaitForSelectorArgs<'a> {
404 selector: &'a str,
405 pub(crate) state: Option<WaitForSelectorState>,
406 pub(crate) timeout: Option<f64>
407}
408
409impl<'a> WaitForSelectorArgs<'a> {
410 pub(crate) fn new(selector: &'a str) -> Self {
411 Self {
412 selector,
413 state: None,
414 timeout: Some(30000.0)
415 }
416 }
417}
418
419impl RemoteObject for ElementHandle {
420 fn channel(&self) -> &ChannelOwner { &self.channel }
421 fn channel_mut(&mut self) -> &mut ChannelOwner { &mut self.channel }
422}
423
424#[skip_serializing_none]
425#[derive(Serialize, Default)]
426#[serde(rename_all = "camelCase")]
427pub(crate) struct SelectOptionArgs {
428 pub(crate) options: Option<Vec<Opt>>,
429 pub(crate) elements: Option<Vec<OnlyGuid>>,
430
431 pub(crate) timeout: Option<f64>,
432 pub(crate) no_wait_after: Option<bool>
433}
434
435#[derive(Serialize)]
436pub(crate) enum Opt {
437 Value(String),
438 Index(usize),
439 Label(String)
440}
441
442#[skip_serializing_none]
443#[derive(Serialize, Default)]
444#[serde(rename_all = "camelCase")]
445pub(crate) struct SetInputFilesArgs {
446 pub(crate) files: Vec<File>,
447 pub(crate) timeout: Option<f64>,
448 pub(crate) no_wait_after: Option<bool>
449}