playwright/api/
element_handle.rs

1use crate::{
2    api::Frame,
3    imp::{
4        core::*,
5        element_handle::{
6            CheckArgs, ClickArgs, ElementHandle as Impl, FillArgs, HoverArgs, Opt, PressArgs,
7            ScreenshotArgs, SelectOptionArgs, SetInputFilesArgs, TapArgs, TypeArgs,
8            WaitForSelectorArgs
9        },
10        prelude::*,
11        utils::{
12            ElementState, File, FloatRect, KeyboardModifier, MouseButton, Position, ScreenshotType,
13            WaitForSelectorState
14        }
15    }
16};
17
18/// ElementHandle represents an in-page DOM element. ElementHandles can be created with the [`method: Page.querySelector`]
19/// method.
20///
21/// ```js
22/// const { chromium } = require('playwright');  // Or 'firefox' or 'webkit'.
23///
24/// (async () => {
25///  const browser = await chromium.launch();
26///  const page = await browser.newPage();
27///  await page.goto('https://example.com');
28///  const hrefElement = await page.$('a');
29///  await hrefElement.click();
30///  // ...
31/// })();
32/// ```
33///
34/// ElementHandle prevents DOM element from garbage collection unless the handle is disposed with
35/// [`method: JSHandle.dispose`]. ElementHandles are auto-disposed when their origin frame gets navigated.
36///
37/// ElementHandle instances can be used as an argument in [`method: Page.evalOnSelector`] and [`method: Page.evaluate`]
38/// methods.
39#[derive(Debug)]
40pub struct ElementHandle {
41    inner: Weak<Impl>
42}
43
44impl PartialEq for ElementHandle {
45    fn eq(&self, other: &Self) -> bool {
46        let a = self.inner.upgrade();
47        let b = other.inner.upgrade();
48        a.and_then(|a| b.map(|b| (a, b)))
49            .map(|(a, b)| a.guid() == b.guid())
50            .unwrap_or_default()
51    }
52}
53
54macro_rules! is_checked {
55    ($f: ident) => {
56        pub async fn $f(&self) -> ArcResult<bool> { upgrade(&self.inner)?.$f().await }
57    };
58}
59
60impl ElementHandle {
61    pub(crate) fn new(inner: Weak<Impl>) -> Self { Self { inner } }
62
63    pub(crate) fn guid(&self) -> Result<Str<Guid>, Error> {
64        Ok(upgrade(&self.inner)?.guid().to_owned())
65    }
66
67    /// The method finds an element matching the specified selector in the `ElementHandle`'s subtree.
68    /// If no elements match the selector, returns `null`.
69    pub async fn query_selector(&self, selector: &str) -> ArcResult<Option<ElementHandle>> {
70        Ok(upgrade(&self.inner)?
71            .query_selector(selector)
72            .await?
73            .map(ElementHandle::new))
74    }
75
76    /// The method finds all elements matching the specified selector in the `ElementHandle`s subtree.
77    /// If no elements match the selector, returns empty array.
78    pub async fn query_selector_all(&self, selector: &str) -> ArcResult<Vec<ElementHandle>> {
79        let es = upgrade(&self.inner)?.query_selector_all(selector).await?;
80        Ok(es.into_iter().map(ElementHandle::new).collect())
81    }
82
83    /// Returns the `element.innerText`.
84    pub async fn inner_text(&self) -> ArcResult<String> { upgrade(&self.inner)?.inner_text().await }
85
86    /// Returns the `element.innerHTML`.
87    pub async fn inner_html(&self) -> ArcResult<String> { upgrade(&self.inner)?.inner_html().await }
88
89    is_checked! {is_checked}
90    is_checked! {is_disabled}
91    is_checked! {is_editable}
92    is_checked! {is_enabled}
93    is_checked! {is_hidden}
94    is_checked! {is_visible}
95
96    /// Returns the frame containing the given element.
97    pub async fn owner_frame(&self) -> ArcResult<Option<Frame>> {
98        Ok(upgrade(&self.inner)?.owner_frame().await?.map(Frame::new))
99    }
100
101    /// Returns the content frame for element handles referencing iframe nodes, or `null` otherwise
102    pub async fn content_frame(&self) -> ArcResult<Option<Frame>> {
103        Ok(upgrade(&self.inner)?.content_frame().await?.map(Frame::new))
104    }
105
106    /// Returns element attribute value.
107    pub async fn get_attribute(&self, name: &str) -> ArcResult<Option<String>> {
108        upgrade(&self.inner)?.get_attribute(name).await
109    }
110
111    /// Returns the `node.textContent`.
112    pub async fn text_content(&self) -> ArcResult<Option<String>> {
113        upgrade(&self.inner)?.text_content().await
114    }
115
116    /// This method hovers over the element by performing the following steps:
117    /// 1. Wait for [actionability](https://playwright.dev/docs/actionability/) checks on the element, unless `force` option is set.
118    /// 1. Scroll the element into view if needed.
119    /// 1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified `position`.
120    /// 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
121    ///
122    /// If the element is detached from the DOM at any moment during the action, this method throws.
123    ///
124    /// When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. Passing
125    /// zero timeout disables this.
126    pub fn hover_builder(&self) -> HoverBuilder { HoverBuilder::new(self.inner.clone()) }
127
128    pub fn click_builder(&self) -> ClickBuilder { ClickBuilder::new(self.inner.clone()) }
129
130    /// This method double clicks an element matching `selector` by performing the following steps:
131    /// 1. Find an element matching `selector`. If there is none, wait until a matching element is attached to the DOM.
132    /// 1. Wait for [actionability](https://playwright.dev/docs/actionability/) checks on the matched element, unless `force` option is set. If the
133    ///   element is detached during the checks, the whole action is retried.
134    /// 1. Scroll the element into view if needed.
135    /// 1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified `position`.
136    /// 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. Note that if the
137    ///   first click of the `dblclick()` triggers a navigation event, this method will throw.
138    ///
139    /// When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. Passing
140    /// zero timeout disables this.
141    ///
142    /// > NOTE: `frame.dblclick()` dispatches two `click` events and a single `dblclick` event.
143    pub fn dblclick_builder(&self) -> DblClickBuilder { DblClickBuilder::new(self.inner.clone()) }
144
145    /// This method checks the element by performing the following steps:
146    /// 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already checked,
147    ///   this method returns immediately.
148    /// 1. Wait for actionability checks on the element, unless `force` option is set.
149    /// 1. Scroll the element into view if needed.
150    /// 1. Use [`property: Page.mouse`] to click in the center of the element.
151    /// 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
152    /// 1. Ensure that the element is now checked. If not, this method throws.
153    ///
154    /// If the element is detached from the DOM at any moment during the action, this method throws.
155    ///
156    /// When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. Passing
157    /// zero timeout disables this.
158    pub fn check_builder(&self) -> CheckBuilder { CheckBuilder::new(self.inner.clone()) }
159
160    /// This method checks the element by performing the following steps:
161    /// 1. Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already
162    ///   unchecked, this method returns immediately.
163    /// 1. Wait for [actionability](https://playwright.dev/docs/actionability/) checks on the element, unless `force` option is set.
164    /// 1. Scroll the element into view if needed.
165    /// 1. Use [`property: Page.mouse`] to click in the center of the element.
166    /// 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
167    /// 1. Ensure that the element is now unchecked. If not, this method throws.
168    ///
169    /// If the element is detached from the DOM at any moment during the action, this method throws.
170    ///
171    /// When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. Passing
172    /// zero timeout disables this.
173    pub fn uncheck_builder(&self) -> UncheckBuilder { UncheckBuilder::new(self.inner.clone()) }
174
175    /// This method taps the element by performing the following steps:
176    /// 1. Wait for [actionability](https://playwright.dev/docs/actionability/) checks on the element, unless `force` option is set.
177    /// 1. Scroll the element into view if needed.
178    /// 1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified `position`.
179    /// 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
180    ///
181    /// If the element is detached from the DOM at any moment during the action, this method throws.
182    ///
183    /// When all steps combined have not finished during the specified `timeout`, this method throws a `TimeoutError`. Passing
184    /// zero timeout disables this.
185    ///
186    /// > NOTE: `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true.
187    pub fn tap_builder(&self) -> TapBuilder { TapBuilder::new(self.inner.clone()) }
188
189    /// This method waits for [actionability](https://playwright.dev/docs/actionability/) checks, focuses the element, fills it and triggers an `input`
190    /// event after filling. Note that you can pass an empty string to clear the input field.
191    ///
192    /// If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error.
193    /// However, if the element is inside the `<label>` element that has an associated
194    /// [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be filled
195    /// instead.
196    ///
197    /// To send fine-grained keyboard events, use [ElementHandle::type_builder](ElementHandle::type_builder)
198    pub fn fill_builder<'a>(&self, value: &'a str) -> FillBuilder<'a> {
199        FillBuilder::new(self.inner.clone(), value)
200    }
201
202    /// Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element.
203    pub async fn focus(&self) -> ArcResult<()> { upgrade(&self.inner)?.focus().await }
204
205    /// Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
206    ///
207    /// To press a special key, like `Control` or `ArrowDown`, use [`method: ElementHandle.press`].
208    ///
209    /// ```js
210    /// await elementHandle.type('Hello'); // Types instantly
211    /// await elementHandle.type('World', {delay: 100}); // Types slower, like a user
212    /// ```
213    ///
214    /// An example of typing into a text field and then submitting the form:
215    ///
216    /// ```js
217    /// const elementHandle = await page.$('input');
218    /// await elementHandle.type('some text');
219    /// await elementHandle.press('Enter');
220    /// ```
221    pub fn type_builder<'a>(&self, text: &'a str) -> TypeBuilder<'a> {
222        TypeBuilder::new(self.inner.clone(), text)
223    }
224
225    /// Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
226    ///
227    /// `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
228    /// value or a single character to generate the text for. A superset of the `key` values can be found
229    /// [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
230    ///
231    /// `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
232    /// `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
233    ///
234    /// Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
235    ///
236    /// Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
237    ///
238    /// If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
239    /// texts.
240    ///
241    /// Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When specified with the
242    /// modifier, modifier is pressed and being held while the subsequent key is being pressed.
243    pub fn press_builder<'a>(&self, key: &'a str) -> PressBuilder<'a> {
244        PressBuilder::new(self.inner.clone(), key)
245    }
246
247    /// This method waits for actionability checks, then tries to scroll element into view, unless it is
248    /// completely visible as defined by
249    /// [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)'s `ratio`.
250    ///
251    /// Throws when `elementHandle` does not point to an element
252    /// [connected](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected) to a Document or a ShadowRoot.
253    pub async fn scroll_into_view_if_needed(&self, timeout: Option<f64>) -> ArcResult<()> {
254        upgrade(&self.inner)?
255            .scroll_into_view_if_needed(timeout)
256            .await
257    }
258
259    /// This method waits for actionability checks, then focuses the element and selects all its text
260    /// content.
261    pub async fn select_text(&self, timeout: Option<f64>) -> ArcResult<()> {
262        upgrade(&self.inner)?.select_text(timeout).await
263    }
264
265    /// This method returns the bounding box of the element, or `null` if the element is not visible. The bounding box is
266    /// calculated relative to the main frame viewport - which is usually the same as the browser window.
267    ///
268    /// Scrolling affects the returned bonding box, similarly to
269    /// [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). That
270    /// means `x` and/or `y` may be negative.
271    ///
272    /// Elements from child frames return the bounding box relative to the main frame, unlike the
273    /// [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
274    ///
275    /// Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the following
276    /// snippet should click the center of the element.
277    ///
278    /// ```js
279    /// const box = await elementHandle.boundingBox();
280    /// await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
281    /// ```
282    pub async fn bounding_box(&self) -> ArcResult<Option<FloatRect>> {
283        upgrade(&self.inner)?.bounding_box().await
284    }
285
286    /// Returns the buffer with the captured screenshot.
287    ///
288    /// This method waits for the actionability checks, then scrolls element into view before taking a
289    /// screenshot. If the element is detached from DOM, the method throws an error.
290    pub async fn screenshot_builder(&self) -> ScreenshotBuilder<'_> {
291        ScreenshotBuilder::new(self.inner.clone())
292    }
293
294    /// Returns when the element satisfies the `state`.
295    pub async fn wait_for_element_state(
296        &self,
297        state: ElementState,
298        timeout: Option<f64>
299    ) -> ArcResult<()> {
300        upgrade(&self.inner)?
301            .wait_for_element_state(state, timeout)
302            .await
303    }
304
305    /// Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or
306    /// `detached`.
307    ///
308    /// Wait for the `selector` to satisfy `state` option (either appear/disappear from dom, or become visible/hidden). If at
309    /// the moment of calling the method `selector` already satisfies the condition, the method will return immediately. If the
310    /// selector doesn't satisfy the condition for the `timeout` milliseconds, the function will throw.
311    ///
312    /// This method works across navigations:
313    ///
314    /// ```js
315    /// const { chromium } = require('playwright');  // Or 'firefox' or 'webkit'.
316    ///
317    /// (async () => {
318    ///  const browser = await chromium.launch();
319    ///  const page = await browser.newPage();
320    ///  for (let currentURL of ['https://google.com', 'https://bbc.com']) {
321    ///    await page.goto(currentURL);
322    ///    const element = await page.mainFrame().waitForSelector('img');
323    ///    console.log('Loaded image: ' + await element.getAttribute('src'));
324    ///  }
325    ///  await browser.close();
326    /// })();
327    /// ```
328    pub fn wait_for_selector_builder<'a>(&self, selector: &'a str) -> WaitForSelectorBuilder<'a> {
329        WaitForSelectorBuilder::new(self.inner.clone(), selector)
330    }
331
332    /// The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the element,
333    /// `click` is dispatched. This is equivalent to calling
334    /// [element.click()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click).
335    ///
336    /// ```js
337    /// await elementHandle.dispatchEvent('click');
338    /// ```
339    ///
340    /// Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
341    /// and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
342    ///
343    /// Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial properties:
344    /// - [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent)
345    /// - [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent)
346    /// - [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent)
347    /// - [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent)
348    /// - [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent)
349    /// - [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)
350    /// - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
351    ///
352    /// You can also specify `JSHandle` as the property value if you want live objects to be passed into the event:
353    ///
354    /// ```js
355    ///// Note you can only create DataTransfer in Chromium and Firefox
356    /// const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
357    /// await elementHandle.dispatchEvent('dragstart', { dataTransfer });
358    /// ```
359    pub async fn dispatch_event<T>(&self, r#type: &str, event_init: Option<T>) -> ArcResult<()>
360    where
361        T: Serialize
362    {
363        upgrade(&self.inner)?
364            .dispatch_event(r#type, event_init)
365            .await
366    }
367
368    /// This method waits for [actionability](https://playwright.dev/docs/actionability/) checks, waits until all specified options are present in the
369    /// `<select>` element and selects these options.
370    ///
371    /// If the target element is not a `<select>` element, this method throws an error. However, if the element is inside the
372    /// `<label>` element that has an associated
373    /// [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be used instead.
374    ///
375    /// Returns the array of option values that have been successfully selected.
376    ///
377    /// Triggers a `change` and `input` event once all the provided options have been selected.
378    ///
379    /// ```js
380    ///// single selection matching the value
381    /// handle.selectOption('blue');
382    ///// single selection matching the label
383    /// handle.selectOption({ label: 'Blue' });
384    ///// multiple selection
385    /// handle.selectOption(['red', 'green', 'blue']);
386    /// ```
387    pub fn select_option_builder(&self) -> SelectOptionBuilder {
388        SelectOptionBuilder::new(self.inner.clone())
389    }
390
391    /// This method expects `elementHandle` to point to an
392    /// [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
393    ///
394    /// Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
395    /// are resolved relative to the the current working directory. For empty array, clears the selected files.
396    pub fn set_input_files_builder(&self, file: File) -> SetInputFilesBuilder {
397        SetInputFilesBuilder::new(self.inner.clone(), file)
398    }
399
400    // eval_on_selector
401    // eval_on_selector_all
402}
403
404// TODO: JsHandle
405impl ElementHandle {}
406
407pub struct HoverBuilder {
408    inner: Weak<Impl>,
409    args: HoverArgs
410}
411
412impl HoverBuilder {
413    pub(crate) fn new(inner: Weak<Impl>) -> Self {
414        let args = HoverArgs::default();
415        Self { inner, args }
416    }
417
418    pub async fn goto(self) -> Result<(), Arc<Error>> {
419        let Self { inner, args } = self;
420        upgrade(&inner)?.hover(args).await
421    }
422
423    setter! {
424        /// Whether to bypass the [actionability](https://playwright.dev/docs/actionability/) checks. Defaults to `false`.
425        force: Option<bool>,
426        /// Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current
427        /// modifiers back. If not specified, currently pressed modifiers are used.
428        modifiers: Option<Vec<KeyboardModifier>>,
429        /// A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
430        /// element.
431        position: Option<Position>,
432        timeout: Option<f64>,
433        /// When set, this method only performs the [actionability](https://playwright.dev/docs/actionability/) checks and skips the action. Defaults to
434        /// `false`. Useful to wait until the element is ready for the action without performing it.
435        trial: Option<bool>
436    }
437}
438
439macro_rules! clicker {
440    ($t: ident, $f: ident) => {
441        pub struct $t {
442            inner: Weak<Impl>,
443            args: ClickArgs
444        }
445
446        impl $t {
447            pub(crate) fn new(inner: Weak<Impl>) -> Self {
448                let args = ClickArgs::default();
449                Self { inner, args }
450            }
451
452            pub async fn $f(self) -> Result<(), Arc<Error>> {
453                let Self { inner, args } = self;
454                let _ = upgrade(&inner)?.$f(args).await?;
455                Ok(())
456            }
457
458            setter! {
459                /// Defaults to `left`.
460                button: Option<MouseButton>,
461                /// Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0.
462                delay: Option<f64>,
463                /// Whether to bypass the [actionability](https://playwright.dev/docs/actionability/) checks. Defaults to `false`.
464                force: Option<bool>,
465                /// Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current
466                /// modifiers back. If not specified, currently pressed modifiers are used.
467                modifiers: Option<Vec<KeyboardModifier>>,
468                /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
469                /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
470                /// inaccessible pages. Defaults to `false`.
471                no_wait_after: Option<bool>,
472                /// A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
473                /// element.
474                position: Option<Position>,
475                timeout: Option<f64>,
476                /// When set, this method only performs the [actionability](https://playwright.dev/docs/actionability/) checks and skips the action. Defaults to
477                /// `false`. Useful to wait until the element is ready for the action without performing it.
478                trial: Option<bool>
479            }
480        }
481    };
482}
483
484clicker!(ClickBuilder, click);
485clicker!(DblClickBuilder, dblclick);
486
487macro_rules! check_builder {
488    ($t: ident, $m: ident) => {
489        pub struct $t {
490            inner: Weak<Impl>,
491            args: CheckArgs
492        }
493
494        impl $t {
495            pub(crate) fn new(inner: Weak<Impl>) -> Self {
496                let args = CheckArgs::default();
497                Self { inner, args }
498            }
499
500            pub async fn $m(self) -> Result<(), Arc<Error>> {
501                let Self { inner, args } = self;
502                let _ = upgrade(&inner)?.$m(args).await?;
503                Ok(())
504            }
505
506            setter! {
507                /// A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the element.
508                position: Option<Position>,
509                /// Whether to bypass the actionability checks. Defaults to `false`.
510                force: Option<bool>,
511                /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
512                /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
513                /// inaccessible pages. Defaults to `false`.
514                no_wait_after: Option<bool>,
515                timeout: Option<f64>,
516                /// When set, this method only performs the [actionability](https://playwright.dev/docs/actionability/) checks and skips the action. Defaults to
517                /// `false`. Useful to wait until the element is ready for the action without performing it.
518                trial: Option<bool>
519            }
520        }
521    };
522}
523
524check_builder!(CheckBuilder, check);
525check_builder!(UncheckBuilder, uncheck);
526
527pub struct TapBuilder {
528    inner: Weak<Impl>,
529    args: TapArgs
530}
531
532impl TapBuilder {
533    pub(crate) fn new(inner: Weak<Impl>) -> Self {
534        let args = TapArgs::default();
535        Self { inner, args }
536    }
537
538    pub async fn tap(self) -> Result<(), Arc<Error>> {
539        let Self { inner, args } = self;
540        let _ = upgrade(&inner)?.tap(args).await?;
541        Ok(())
542    }
543
544    setter! {
545        /// Whether to bypass the actionability checks. Defaults to `false`.
546        force: Option<bool>,
547        /// Modifier keys to press. Ensures that only these modifiers are pressed during the operation, and then restores current
548        /// modifiers back. If not specified, currently pressed modifiers are used.
549        modifiers: Option<Vec<KeyboardModifier>>,
550        /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
551        /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
552        /// inaccessible pages. Defaults to `false`.
553        no_wait_after: Option<bool>,
554        /// A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
555        /// element.
556        position: Option<Position>,
557        timeout: Option<f64>,
558        /// When set, this method only performs the [actionability](https://playwright.dev/docs/actionability/) checks and skips the action. Defaults to
559        /// `false`. Useful to wait until the element is ready for the action without performing it.
560        trial: Option<bool>
561    }
562}
563
564pub struct FillBuilder<'a> {
565    inner: Weak<Impl>,
566    args: FillArgs<'a>
567}
568
569impl<'a> FillBuilder<'a> {
570    pub(crate) fn new(inner: Weak<Impl>, value: &'a str) -> Self {
571        let args = FillArgs::new(value);
572        Self { inner, args }
573    }
574
575    pub async fn fill(self) -> Result<(), Arc<Error>> {
576        let Self { inner, args } = self;
577        let _ = upgrade(&inner)?.fill(args).await?;
578        Ok(())
579    }
580
581    setter! {
582        /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
583        /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
584        /// inaccessible pages. Defaults to `false`.
585        no_wait_after: Option<bool>,
586        timeout: Option<f64>
587    }
588}
589
590macro_rules! type_builder {
591    ($t: ident, $a: ident, $f: ident, $m: ident) => {
592        pub struct $t<'a> {
593            inner: Weak<Impl>,
594            args: $a<'a>
595        }
596
597        impl<'a> $t<'a> {
598            pub(crate) fn new(inner: Weak<Impl>, $f: &'a str) -> Self {
599                let args = $a::new($f);
600                Self { inner, args }
601            }
602
603            pub async fn $m(self) -> Result<(), Arc<Error>> {
604                let Self { inner, args } = self;
605                let _ = upgrade(&inner)?.$m(args).await?;
606                Ok(())
607            }
608
609            setter! {
610                /// Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0.
611                delay: Option<f64>,
612                /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
613                /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
614                /// inaccessible pages. Defaults to `false`.
615                no_wait_after: Option<bool>,
616                timeout: Option<f64>
617            }
618        }
619    };
620}
621
622type_builder!(TypeBuilder, TypeArgs, text, r#type);
623type_builder!(PressBuilder, PressArgs, key, press);
624
625pub struct ScreenshotBuilder<'a> {
626    inner: Weak<Impl>,
627    args: ScreenshotArgs<'a>
628}
629
630impl<'a> ScreenshotBuilder<'a> {
631    pub(crate) fn new(inner: Weak<Impl>) -> Self {
632        let args = ScreenshotArgs::default();
633        Self { inner, args }
634    }
635
636    pub async fn screenshot(self) -> ArcResult<Vec<u8>> {
637        let Self { inner, args } = self;
638        upgrade(&inner)?.screenshot(args).await
639    }
640
641    /// Specify screenshot type, defaults to `png`.
642    pub fn r#type(mut self, x: ScreenshotType) -> Self {
643        self.args.r#type = Some(x);
644        self
645    }
646
647    setter! {
648        /// Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images.
649        /// Defaults to `false`.
650        omit_background: Option<bool>,
651        /// The file path to save the image to. The screenshot type will be inferred from file extension. If `path` is a relative
652        /// path, then it is resolved relative to the current working directory. If no path is provided, the image won't be saved to
653        /// the disk.
654        path: Option<&'a Path>,
655        quality: Option<i64>,
656        timeout: Option<f64>
657    }
658
659    pub fn clear_type(mut self) -> Self {
660        self.args.r#type = None;
661        self
662    }
663}
664
665pub struct WaitForSelectorBuilder<'a> {
666    inner: Weak<Impl>,
667    args: WaitForSelectorArgs<'a>
668}
669
670impl<'a> WaitForSelectorBuilder<'a> {
671    pub(crate) fn new(inner: Weak<Impl>, selector: &'a str) -> Self {
672        let args = WaitForSelectorArgs::new(selector);
673        Self { inner, args }
674    }
675
676    pub async fn wait_for_selector(self) -> Result<(), Arc<Error>> {
677        let Self { inner, args } = self;
678        let _ = upgrade(&inner)?.wait_for_selector(args).await?;
679        Ok(())
680    }
681
682    setter! {
683        state: Option<WaitForSelectorState>,
684        timeout: Option<f64>
685    }
686}
687
688pub struct SelectOptionBuilder {
689    inner: Weak<Impl>,
690    args: SelectOptionArgs,
691    err: Option<Error>
692}
693
694impl SelectOptionBuilder {
695    pub(crate) fn new(inner: Weak<Impl>) -> Self {
696        let args = SelectOptionArgs::default();
697        Self {
698            inner,
699            args,
700            err: None
701        }
702    }
703
704    pub async fn select_option(self) -> Result<Vec<String>, Arc<Error>> {
705        let Self { inner, args, err } = self;
706        if let Some(e) = err {
707            return Err(e.into());
708        }
709        upgrade(&inner)?.select_option(args).await
710    }
711
712    pub fn add_element(mut self, x: &ElementHandle) -> Self {
713        let guid = match x.guid() {
714            Ok(i) => i,
715            Err(e) => {
716                if self.err.is_none() {
717                    self.err = Some(e);
718                }
719                return self;
720            }
721        };
722        let x = OnlyGuid { guid };
723        if let Some(e) = &mut self.args.elements {
724            e.push(x);
725        } else {
726            self.args.elements = Some(vec![x]);
727        }
728        self
729    }
730
731    pub fn add_value(mut self, x: String) -> Self {
732        let x = Opt::Value(x);
733        if let Some(o) = &mut self.args.options {
734            o.push(x);
735        } else {
736            self.args.options = Some(vec![x]);
737        }
738        self
739    }
740
741    pub fn add_index(mut self, x: usize) -> Self {
742        let x = Opt::Index(x);
743        if let Some(o) = &mut self.args.options {
744            o.push(x);
745        } else {
746            self.args.options = Some(vec![x]);
747        }
748        self
749    }
750
751    pub fn add_label(mut self, x: String) -> Self {
752        let x = Opt::Label(x);
753        if let Some(o) = &mut self.args.options {
754            o.push(x);
755        } else {
756            self.args.options = Some(vec![x]);
757        }
758        self
759    }
760
761    setter! {
762        /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
763        /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
764        /// inaccessible pages. Defaults to `false`.
765        no_wait_after: Option<bool>,
766        timeout: Option<f64>
767    }
768
769    pub fn clear_elements(mut self) -> Self {
770        self.args.elements = None;
771        self
772    }
773
774    pub fn clear_options(mut self) -> Self {
775        self.args.options = None;
776        self
777    }
778}
779
780pub struct SetInputFilesBuilder {
781    inner: Weak<Impl>,
782    args: SetInputFilesArgs
783}
784
785impl SetInputFilesBuilder {
786    pub(crate) fn new(inner: Weak<Impl>, file: File) -> Self {
787        let args = SetInputFilesArgs {
788            files: vec![file],
789            ..SetInputFilesArgs::default()
790        };
791        Self { inner, args }
792    }
793
794    pub async fn set_input_files(self) -> Result<(), Arc<Error>> {
795        let Self { inner, args } = self;
796        upgrade(&inner)?.set_input_files(args).await
797    }
798
799    pub fn add_file(mut self, x: File) -> Self {
800        self.args.files.push(x);
801        self
802    }
803
804    setter! {
805        /// Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
806        /// opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
807        /// inaccessible pages. Defaults to `false`.
808        no_wait_after: Option<bool>,
809        timeout: Option<f64>
810    }
811
812    pub fn clear_files(mut self) -> Self {
813        self.args.files = vec![];
814        self
815    }
816}
817
818mod ser {
819    use super::*;
820    use serde::{ser, ser::SerializeStruct};
821
822    impl Serialize for ElementHandle {
823        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
824        where
825            S: ser::Serializer
826        {
827            let mut s = serializer.serialize_struct("fff9ae7f-9070-480f-9a8a-3d4b66923f7d", 1)?;
828            let guid = &self.guid().map_err(<S::Error as ser::Error>::custom)?;
829            s.serialize_field("guid", &guid)?;
830            s.end()
831        }
832    }
833}