use std::sync::Arc;
use thirtyfour::error::WebDriverError;
use thirtyfour::prelude::*;
pub type WebDriverResult<T> = Result<T, WebDriverError>;
#[derive(Clone)]
pub struct WebDriverContext {
driver: Arc<WebDriver>,
}
impl WebDriverContext {
pub fn new(driver: Arc<WebDriver>) -> Self {
Self { driver }
}
pub fn from_driver(driver: WebDriver) -> Self {
Self {
driver: Arc::new(driver),
}
}
pub fn driver(&self) -> &Arc<WebDriver> {
&self.driver
}
pub async fn navigate(&self, url: &str) -> WebDriverResult<()> {
self.driver.goto(url).await
}
pub async fn url(&self) -> WebDriverResult<String> {
Ok(self.driver.current_url().await?.to_string())
}
pub async fn html(&self) -> WebDriverResult<String> {
self.driver.source().await
}
pub async fn title(&self) -> WebDriverResult<String> {
self.driver.title().await
}
pub async fn screenshot(&self) -> WebDriverResult<Vec<u8>> {
self.driver.screenshot_as_png().await
}
pub async fn find_element(&self, selector: &str) -> WebDriverResult<WebElement> {
self.driver.find(By::Css(selector)).await
}
pub async fn find_elements(&self, selector: &str) -> WebDriverResult<Vec<WebElement>> {
self.driver.find_all(By::Css(selector)).await
}
pub async fn click(&self, selector: &str) -> WebDriverResult<()> {
let element = self.find_element(selector).await?;
element.click().await
}
pub async fn type_text(&self, selector: &str, text: &str) -> WebDriverResult<()> {
let element = self.find_element(selector).await?;
element.send_keys(text).await
}
pub async fn clear(&self, selector: &str) -> WebDriverResult<()> {
let element = self.find_element(selector).await?;
element.clear().await
}
pub async fn get_text(&self, selector: &str) -> WebDriverResult<String> {
let element = self.find_element(selector).await?;
element.text().await
}
pub async fn get_attribute(
&self,
selector: &str,
attr: &str,
) -> WebDriverResult<Option<String>> {
let element = self.find_element(selector).await?;
element.attr(attr).await
}
pub async fn execute<T: serde::de::DeserializeOwned>(
&self,
script: &str,
) -> WebDriverResult<T> {
let ret = self.driver.execute(script, vec![]).await?;
ret.convert()
}
pub async fn execute_script(&self, script: &str) -> WebDriverResult<()> {
self.driver.execute(script, vec![]).await?;
Ok(())
}
pub async fn wait_for(&self, selector: &str, timeout_secs: u64) -> WebDriverResult<WebElement> {
let elem = self
.driver
.query(By::Css(selector))
.wait(
std::time::Duration::from_secs(timeout_secs),
std::time::Duration::from_millis(100),
)
.first()
.await?;
Ok(elem)
}
pub async fn wait_for_clickable(
&self,
selector: &str,
timeout_secs: u64,
) -> WebDriverResult<WebElement> {
let elem = self
.driver
.query(By::Css(selector))
.wait(
std::time::Duration::from_secs(timeout_secs),
std::time::Duration::from_millis(100),
)
.and_clickable()
.first()
.await?;
Ok(elem)
}
pub async fn new_tab(&self) -> WebDriverResult<WindowHandle> {
self.driver.new_tab().await
}
pub async fn new_window(&self) -> WebDriverResult<WindowHandle> {
self.driver.new_window().await
}
pub async fn switch_to_window(&self, handle: &WindowHandle) -> WebDriverResult<()> {
self.driver.switch_to_window(handle.clone()).await
}
pub async fn windows(&self) -> WebDriverResult<Vec<WindowHandle>> {
self.driver.windows().await
}
pub async fn current_window(&self) -> WebDriverResult<WindowHandle> {
self.driver.window().await
}
pub async fn close_window(&self) -> WebDriverResult<()> {
self.driver.close_window().await
}
pub async fn refresh(&self) -> WebDriverResult<()> {
self.driver.refresh().await
}
pub async fn back(&self) -> WebDriverResult<()> {
self.driver.back().await
}
pub async fn forward(&self) -> WebDriverResult<()> {
self.driver.forward().await
}
pub async fn set_window_size(&self, width: u32, height: u32) -> WebDriverResult<()> {
self.driver.set_window_rect(0, 0, width, height).await?;
Ok(())
}
pub async fn maximize_window(&self) -> WebDriverResult<()> {
self.driver.maximize_window().await
}
pub async fn minimize_window(&self) -> WebDriverResult<()> {
self.driver.minimize_window().await
}
pub async fn cookies(&self) -> WebDriverResult<Vec<Cookie>> {
self.driver.get_all_cookies().await
}
pub async fn delete_cookie(&self, name: &str) -> WebDriverResult<()> {
self.driver.delete_cookie(name).await
}
pub async fn delete_all_cookies(&self) -> WebDriverResult<()> {
self.driver.delete_all_cookies().await
}
}
impl std::fmt::Debug for WebDriverContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WebDriverContext")
.field("driver", &"WebDriver { ... }")
.finish()
}
}
pub use thirtyfour::{By, Cookie, WebDriver, WebElement, WindowHandle};