use crate::IntoArcStr;
use crate::error::WebDriverResult;
use crate::{ElementPredicate, WebElement};
use std::sync::Arc;
use stringmatch::Needle;
pub(crate) fn handle_errors(
result: WebDriverResult<bool>,
ignore_errors: bool,
) -> WebDriverResult<bool> {
match result {
Ok(x) => Ok(x),
Err(..) if ignore_errors => Ok(false),
Err(e) => Err(e),
}
}
pub(crate) fn negate(result: WebDriverResult<bool>, ignore_errors: bool) -> WebDriverResult<bool> {
handle_errors(result.map(|x| !x), ignore_errors)
}
pub fn element_is_enabled(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { handle_errors(elem.is_enabled().await, ignore_errors) }
}
pub fn element_is_not_enabled(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { negate(elem.is_enabled().await, ignore_errors) }
}
pub fn element_is_selected(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { handle_errors(elem.is_selected().await, ignore_errors) }
}
pub fn element_is_not_selected(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { negate(elem.is_selected().await, ignore_errors) }
}
pub fn element_is_displayed(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { handle_errors(elem.is_displayed().await, ignore_errors) }
}
pub fn element_is_not_displayed(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { negate(elem.is_displayed().await, ignore_errors) }
}
pub fn element_is_clickable(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { handle_errors(elem.is_clickable().await, ignore_errors) }
}
pub fn element_is_not_clickable(ignore_errors: bool) -> impl ElementPredicate {
move |elem: WebElement| async move { negate(elem.is_clickable().await, ignore_errors) }
}
pub fn element_has_class<N>(class_name: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let class_name = class_name.clone();
async move {
match elem.class_name().await {
Ok(Some(x)) => Ok(class_name.is_match(&x)),
Ok(None) => Ok(false),
Err(e) => handle_errors(Err(e), ignore_errors),
}
}
}
}
pub fn element_lacks_class<N>(class_name: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let class_name = class_name.clone();
async move {
match elem.class_name().await {
Ok(Some(x)) => Ok(!class_name.is_match(&x)),
Ok(None) => Ok(true),
Err(e) => handle_errors(Err(e), ignore_errors),
}
}
}
}
pub fn element_has_text<N>(text: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let text = text.clone();
async move { handle_errors(elem.text().await.map(|x| text.is_match(&x)), ignore_errors) }
}
}
pub fn element_lacks_text<N>(text: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let text = text.clone();
async move { handle_errors(elem.text().await.map(|x| !text.is_match(&x)), ignore_errors) }
}
}
pub fn element_has_value<N>(value: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let value = value.clone();
async move {
match elem.value().await {
Ok(Some(x)) => Ok(value.is_match(&x)),
Ok(None) => Ok(false),
Err(e) => handle_errors(Err(e), ignore_errors),
}
}
}
}
pub fn element_lacks_value<N>(value: N, ignore_errors: bool) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let value = value.clone();
async move {
match elem.value().await {
Ok(Some(x)) => Ok(!value.is_match(&x)),
Ok(None) => Ok(true),
Err(e) => handle_errors(Err(e), ignore_errors),
}
}
}
}
pub(crate) fn collect_arg_slice<S, N, I>(desired_attributes: I) -> Arc<[(Arc<str>, N)]>
where
I: IntoIterator<Item = (S, N)>,
S: IntoArcStr,
N: Needle + Send + Sync + 'static,
{
desired_attributes.into_iter().map(|(a, b)| (a.into(), b)).collect()
}
macro_rules! elem_matches {
(@inner_many_opt $elm: expr, $desired: expr, $ignore_errors: expr, $field: ident, |$val: ident, $name: ident| $check: expr) => {async move {
for (name, $val) in &*$desired {
match $elm.$field(name).await {
Ok(Some($name)) => {
if $check {
return Ok(false);
}
}
Ok(None) => return Ok(false),
Err(e) => return handle_errors(Err(e), $ignore_errors),
}
}
Ok(true)
}};
(@inner_many_css $elm: expr, $desired: expr, $ignore_errors: expr, $field: ident, |$val: ident, $name: ident| $check: expr) => {async move {
for (name, $val) in &*$desired {
match $elm.$field(name).await {
Ok($name) => {
if $check {
return Ok(false);
}
}
Err(e) => return handle_errors(Err(e), $ignore_errors),
}
}
Ok(true)
}};
(@inner_single_opt $elm: expr, $name: expr, $ignore_errors: expr , $field: ident, |$ret: ident| $check: expr) => {
async move {
match $elm.$field($name).await {
Ok(Some($ret)) => Ok($check),
Ok(None) => Ok(false),
Err(e) => handle_errors(Err(e), $ignore_errors),
}
}
};
(@inner_single_css $elm: expr, $name: expr, $ignore_errors: expr , $field: ident, |$ret: ident| $check: expr) => {
async move {
handle_errors(
$elm.$field($name).await.map(|$ret| $check),
$ignore_errors,
)
}
};
(many [$name: ident] $field: ident => $plural: ident) => {
pastey::paste! {
#[doc = concat!("Predicate that returns true for elements that have all the ",stringify!($plural)," specified with the")]
pub fn [<element_has_ $plural>]<N>(
[<desired_ $plural>]: Arc<[(Arc<str>, N)]>,
ignore_errors: bool,
) -> impl ElementPredicate
where
N: Needle + Send + Sync + 'static,
{
move |elem: WebElement| {
let desired = [<desired_ $plural>].clone();
elem_matches!(@[<inner_many_ $name>] elem, desired, ignore_errors, $field, |val, x| !val.is_match(&x))
}
}
#[doc = concat!("Predicate that returns true for elements that do not have any of the specified ",stringify!($plural)," specified with the")]
pub fn [<element_lacks_ $plural>]<N>(
[<desired_ $plural>]: Arc<[(Arc<str>, N)]>,
ignore_errors: bool,
) -> impl ElementPredicate
where
N: Needle + Send + Sync + 'static,
{
move |elem: WebElement| {
let desired = [<desired_ $plural>].clone();
elem_matches!(@[<inner_many_ $name>] elem, desired, ignore_errors, $field, |value, x| value.is_match(&x))
}
}
}
};
(single [$name: ident] $field: ident => $single: ident) => {
pastey::paste! {
#[doc = concat!("Predicate that returns true for elements that have the specified ",stringify!($plural)," with the specified")]
pub fn [<element_has_ $single>]<N>(
[<$single _name>]: Arc<str>,
value: N,
ignore_errors: bool,
) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let name = [<$single _name>].clone();
let value = value.clone();
elem_matches!(@[<inner_single_ $name>] elem, name, ignore_errors, $field, |x| value.is_match(&x))
}
}
#[doc = concat!("Predicate that returns true for elements that do not contain the specified ",stringify!($plural)," with the specified")]
pub fn [<element_lacks_ $single>]<N>(
[<$single _name>]: Arc<str>,
value: N,
ignore_errors: bool,
) -> impl ElementPredicate
where
N: Needle + Clone + Send + Sync + 'static,
{
move |elem: WebElement| {
let name = [<$single _name>].clone();
let value = value.clone();
elem_matches!(@[<inner_single_ $name>] elem, name, ignore_errors, $field, |x| !value.is_match(&x))
}
}
}
};
([$name: ident] $field: ident => $single: ident, $plural: ident) => {
elem_matches!(many [$name] $field => $plural);
elem_matches!(single [$name] $field => $single);
}
}
elem_matches!([opt] attr => attribute, attributes);
elem_matches!([opt] prop => property, properties);
elem_matches!([css] css_value => css_property, css_properties);