2 releases
0.1.4 | Jul 20, 2022 |
---|---|
0.1.3 | Jul 19, 2022 |
0.1.2 |
|
0.1.1 |
|
#976 in Procedural macros
16KB
249 lines
A #[derive(Querier)]
derive macro for generating the boilerplate code needed to query a
collection of elements by CSS selectors using
thirtyfour.
This library is highly experimental, and is initially developed for internal use.
Example
use thirtyfour::prelude::*;
use thirtyfour_querier_derive::Querier;
#[derive(Querier)]
struct PageElements {
#[querier(css = "#first")]
first: WebElement,
#[querier(css = "#second")]
second: WebElement,
#[querier(all, css = "div")]
all_divs: WebElement,
}
let page_elements = PageElements::query(&driver).await.unwrap();
Dependencies
The impl
blocks generated by the macro uses futures
and thirtyfour
libraries.
Since the a proc macro crate can't export items, these dependencies has to be added manually
by the user.
This may change in future versions.
Details
The #[derive(Querier)]
macro generates an impl
block containing an async constructor for
the structure named query
, with the following signature.
pub async fn query<T: ElementQueryable>(driver: &T)
-> Result<Self, WebDriverError>;
-
Only structs with named fields are supported.
-
By default, the queries are performed without waiting. Use
#[querier(wait = num_seconds)]
to add an explicit wait. -
Each field of the structure must have a
#[querier(...)]
attribute. The content of the attribute must match the type of the field in this way:Attribute Field Type #[querier(css = "...")]
WebElement
#[querier(maybe, css = "...")]
Option<WebElement>
#[querier(all, css = "...")]
Vec<WebElement>
#[querier(nested, css = "...")]
(WebElement, Q)
#[querier(maybe, nested, css = "...")]
Option<(WebElement, Q)>
#[querier(all, nested, css = "...")]
Vec<(WebElement, Q)>
The type
Q
in the table can be any type that also has#[derive(Querier)]
.
Full Example
use thirtyfour_querier_derive::Querier;
use thirtyfour::prelude::*;
const HTML: &str = r#"
data:text/html;charset=utf-8,<html>
<body>
<div id="single-element"></div>
<div class="many-elements">
<div class="nested-element"></div>
<div class="nested-element"></div>
</div>
<div class="many-elements">
<div class="nested-element"></div>
<div class="nested-element"></div>
</div>
<div class="not-queried nested-element"></div>
</body>
</html>
"#;
#[derive(Debug, Querier)]
#[allow(dead_code)]
struct Page {
#[querier(css = "#single-element")]
single_elem: WebElement,
#[querier(wait = 5, css = "#single-element")]
single_elem_with_wait: WebElement,
#[querier(maybe, css = "#missing-element")]
missing_elem: Option<WebElement>,
#[querier(all, css = ".many-elements")]
many_elems: Vec<WebElement>,
#[querier(all, nested, css = ".many-elements")]
many_elems_nested: Vec<(WebElement, SubElement)>,
}
#[derive(Debug, Querier)]
struct SubElement {
#[querier(all, css = ".nested-element")]
nested_elems: Vec<WebElement>,
}
#[tokio::main]
async fn main() {
let driver = WebDriver::new("http://localhost:9100", DesiredCapabilities::chrome())
.await
.unwrap();
// Load the html string
driver.get(HTML).await.unwrap();
// Query the elements specified in `struct Page`
let page = Page::query(&driver).await.unwrap();
// Count number of `.nested-element` within `many-element`s (should be 4)
let mut nest_elem_count = 0;
for (_, elem) in page.many_elems_nested {
nest_elem_count += elem.nested_elems.len();
}
assert_eq!(
nest_elem_count, 4,
"Number of nested-element within many-element is 4"
);
}
Dependencies
~4–5MB
~98K SLoC