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}