1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! # Components
//!
//! Components allow you to wrap elements or groups of elements to abstract the
//! element selectors and focus more on the logic and flow of your website or web app.
//!
//! This approach may be familiar to anyone who has used a
//! [Page Object Model](https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models/) before.
//! However, a `Component` can wrap any node in the DOM, not just "pages".
//!
//! It uses smart element resolvers that can lazily resolve elements within the component and cache them for further
//! use. You can also nest components, making them an extremely powerful feature for automating any modern web app.
//!
//! ### Example
//!
//! Given the following HTML structure:
//!
//! ```html
//! <div id="checkbox-section">
//! <label>
//! <input type="checkbox" id="checkbox-option-1" />
//! Option 1
//! </label>
//!
//! <label>
//! <input type="checkbox" id="checkbox-disabled" disabled />
//! Option 2
//! </label>
//!
//! <label>
//! <input type="checkbox" id="checkbox-hidden" style="display: none;" />
//! Option 3
//! </label>
//! </div>
//! ```
//!
//! ```ignore
//! /// This component shows how to wrap a simple web component.
//! #[derive(Debug, Clone, Component)]
//! pub struct CheckboxComponent {
//! base: WebElement, // This is the <label> element
//! #[by(css = "input[type='checkbox']")]
//! input: ElementResolver<WebElement>, // This is the <input /> element
//! }
//!
//! impl CheckboxComponent {
//! /// Return true if the checkbox is ticked.
//! pub async fn is_ticked(&self) -> WebDriverResult<bool> {
//! let elem = self.input.resolve().await?;
//! let prop = elem.prop("checked").await?;
//! Ok(prop.unwrap_or_default() == "true")
//! }
//!
//! /// Tick the checkbox if it is clickable and isn't already ticked.
//! pub async fn tick(&self) -> WebDriverResult<()> {
//! // This checks that the element is present before returning the element.
//! // If the element had become stale, this would implicitly re-query the element.
//! let elem = self.input.resolve_present().await?;
//! if elem.is_clickable().await? && !self.is_ticked().await? {
//! elem.click().await?;
//! // Now make sure it's ticked.
//! assert!(self.is_ticked().await?);
//! }
//!
//! Ok(())
//! }
//! }
//!
//! /// This component shows how to nest components inside others.
//! #[derive(Debug, Clone, Component)]
//! pub struct CheckboxSectionComponent {
//! base: WebElement, // This is the outer <div>
//! #[by(tag = "label", allow_empty)]
//! boxes: ElementResolver<Vec<CheckboxComponent>>, // ElementResolver works with Components too.
//! // Other fields will be initialised with Default::default().
//! my_field: bool,
//! }
//! ```
//!
//! So how do you construct a Component?
//!
//! Simple! The `Component` derive automatically implements `From<WebElement>`.
//!
//! ```ignore
//! let elem = driver.query(By::Id("checkbox-section")).await?;
//! let component = CheckboxSectionComponent::from(elem);
//!
//! // Now you can get the checkbox components easily like this.
//! let checkboxes = component.boxes.resolve().await?;
//! for checkbox in checkboxes {
//! checkbox.tick().await?;
//! }
//! ```
//!
//! This allows you to wrap any component using `ElementResolver` to resolve elements and nested
//! components easily.
//!
/// Wrapper for `<select>` elements.
/// Component wrappers.
pub use *;
pub use *;