use crate::tools::browser::executor::BrowserError;
pub trait WaitingExt {
fn wait_for(
&self,
condition: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
fn wait_for_text(
&self,
text: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
fn wait_for_url(
&self,
pattern: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
fn wait_for_load(
&self,
state: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
fn wait_for_download(
&self,
path: Option<&str>,
) -> impl std::future::Future<Output = Result<String, BrowserError>> + Send;
fn wait_for_fn(
&self,
js: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
fn wait_for_state(
&self,
selector: &str,
state: &str,
) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
}
impl WaitingExt for super::super::BrowserClient {
async fn wait_for(&self, condition: &str) -> Result<(), BrowserError> {
if condition.is_empty() {
return Err(BrowserError::InvalidArguments(
"Condition cannot be empty".to_string(),
));
}
let output = self.executor().execute(&["wait", condition]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Wait condition not met: {}",
output.stderr
)))
}
}
async fn wait_for_text(&self, text: &str) -> Result<(), BrowserError> {
if text.is_empty() {
return Err(BrowserError::InvalidArguments(
"Text cannot be empty".to_string(),
));
}
let output = self.executor().execute(&["wait", "--text", text]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Text not found: {}",
output.stderr
)))
}
}
async fn wait_for_url(&self, pattern: &str) -> Result<(), BrowserError> {
if pattern.is_empty() {
return Err(BrowserError::InvalidArguments(
"URL pattern cannot be empty".to_string(),
));
}
let output = self.executor().execute(&["wait", "--url", pattern]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"URL pattern not matched: {}",
output.stderr
)))
}
}
async fn wait_for_load(&self, state: &str) -> Result<(), BrowserError> {
let valid_states = ["networkidle", "domcontentloaded", "load"];
if !valid_states.contains(&state) {
return Err(BrowserError::InvalidArguments(format!(
"Invalid load state '{}'. Valid states: {}",
state,
valid_states.join(", ")
)));
}
let output = self.executor().execute(&["wait", "--load", state]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Load state not reached: {}",
output.stderr
)))
}
}
async fn wait_for_download(&self, path: Option<&str>) -> Result<String, BrowserError> {
let output = if let Some(p) = path {
self.executor().execute(&["wait", "--download", p]).await?
} else {
self.executor().execute(&["wait", "--download"]).await?
};
if output.success {
Ok(output.stdout.trim().to_string())
} else {
Err(BrowserError::Other(format!(
"Download wait failed: {}",
output.stderr
)))
}
}
async fn wait_for_fn(&self, js: &str) -> Result<(), BrowserError> {
if js.is_empty() {
return Err(BrowserError::InvalidArguments(
"JavaScript function cannot be empty".to_string(),
));
}
let output = self.executor().execute(&["wait", "--fn", js]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"JavaScript condition not met: {}",
output.stderr
)))
}
}
async fn wait_for_state(&self, selector: &str, state: &str) -> Result<(), BrowserError> {
let valid_states = [
"visible", "hidden", "attached", "detached", "enabled", "disabled",
];
if !valid_states.contains(&state) {
return Err(BrowserError::InvalidArguments(format!(
"Invalid state '{}'. Valid states: {}",
state,
valid_states.join(", ")
)));
}
if selector.is_empty() {
return Err(BrowserError::InvalidArguments(
"Selector cannot be empty".to_string(),
));
}
let output = self
.executor()
.execute(&["wait", "--state", state, selector])
.await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Element state not reached: {}",
output.stderr
)))
}
}
}