#web-driver #selenium #proc-macro #macro-derive

thirtyfour-querier-derive

用于thirtyfour WebDriver库的#[derive(Querier)]宏

2个版本

0.1.4 2022年7月20日
0.1.3 2022年7月19日
0.1.2 2022年7月19日
0.1.1 2022年7月19日

#687过程宏

MIT 许可证

16KB
249

一个#[derive(Querier)]宏,用于生成使用thirtyfour通过CSS选择器查询元素集合所需的基本代码。

这个库高度实验性,最初是为内部使用开发的。

示例

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();

依赖关系

宏生成的impl块使用了futuresthirtyfour库。由于过程宏crate不能导出项目,这些依赖项必须由用户手动添加。这可能在未来的版本中改变。

详细信息

#[derive(Querier)]宏生成一个包含名为query的结构体的异步构造函数的impl块,以下是其签名。

pub async fn query<T: ElementQueryable>(driver: &T)
    -> Result<Self, WebDriverError>;
  • 仅支持具有命名字段的struct。

  • 默认情况下,查询是立即执行的。使用#[querier(wait = num_seconds)]添加显式等待。

  • 结构体的每个字段都必须有一个#[querier(...)]属性。属性的值必须与字段的类型匹配,如下所示

    属性 字段类型
    #[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)>

    表中的类型 Q 可以是任何具有 #[derive(Querier)] 特性的类型。

完整示例

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://127.0.0.1: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"
    );
}

依赖关系

~3.5–5MB
~96K SLoC