use crate::elements::Element;
use crate::error::{CmdError, ErrorStatus};
use crate::wd::Locator;
use crate::Client;
use std::time::{Duration, Instant};
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
const DEFAULT_PERIOD: Duration = Duration::from_millis(250);
#[derive(Debug)]
pub struct Wait<'c> {
client: &'c Client,
timeout: Option<Duration>,
period: Duration,
}
macro_rules! wait_on {
($self:ident, $ready:expr) => {{
let start = Instant::now();
loop {
match $self.timeout {
Some(timeout) if start.elapsed() > timeout => break Err(CmdError::WaitTimeout),
_ => {}
}
match $ready? {
Some(result) => break Ok(result),
None => {
tokio::time::sleep($self.period).await;
}
};
}
}};
}
impl<'c> Wait<'c> {
pub fn new(client: &'c Client) -> Self {
Self {
client,
timeout: Some(DEFAULT_TIMEOUT),
period: DEFAULT_PERIOD,
}
}
#[must_use]
pub fn at_most(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn forever(mut self) -> Self {
self.timeout = None;
self
}
#[must_use]
pub fn every(mut self, period: Duration) -> Self {
self.period = period;
self
}
pub async fn for_element(self, search: Locator<'_>) -> Result<Element, CmdError> {
wait_on!(self, {
match self.client.by(search.into_parameters()).await {
Ok(element) => Ok(Some(element)),
Err(CmdError::Standard(w)) if w.error == ErrorStatus::NoSuchElement => Ok(None),
Err(err) => Err(err),
}
})
}
pub async fn for_url(self, url: url::Url) -> Result<(), CmdError> {
wait_on!(self, {
Ok::<_, CmdError>(if self.client.current_url().await? == url {
Some(())
} else {
None
})
})
}
}