playwright/imp/
element_handle.rs

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    /// Is ignored if dblclick
312    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}