Skip to content

Commit

Permalink
Add title queries
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielleHuisman committed Sep 4, 2024
1 parent 203b3b2 commit c03893c
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 6 deletions.
78 changes: 72 additions & 6 deletions packages/dom/src/get_queries_for_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use web_sys::HtmlElement;

use crate::{
error::QueryError,
queries::{get_by_alt_text, query_by_alt_text},
get_by_placeholder_text, get_by_test_id, get_by_title,
queries::{get_by_alt_text, get_by_display_value, query_by_alt_text, query_by_display_value},
query_by_placeholder_text, query_by_test_id, query_by_title,
types::{Matcher, MatcherOptions},
};

Expand All @@ -11,20 +13,84 @@ pub struct BoundFunctions {
}

impl BoundFunctions {
pub fn get_by_alt_text<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_alt_text(&self.element, matcher, options)
}

pub fn get_by_display_value<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_display_value(&self.element, matcher, options)
}

pub fn get_by_placeholder_text<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_placeholder_text(&self.element, matcher, options)
}

pub fn get_by_test_id<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_test_id(&self.element, matcher, options)
}

pub fn get_by_title<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_title(&self.element, matcher, options)
}

pub fn query_by_alt_text<M: Into<Matcher>>(
&self,
alt: M,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
query_by_alt_text(&self.element, alt, options)
query_by_alt_text(&self.element, matcher, options)
}

pub fn get_by_alt_text<M: Into<Matcher>>(
pub fn query_by_display_value<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
query_by_display_value(&self.element, matcher, options)
}

pub fn query_by_placeholder_text<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
query_by_placeholder_text(&self.element, matcher, options)
}

pub fn query_by_test_id<M: Into<Matcher>>(
&self,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
query_by_test_id(&self.element, matcher, options)
}

pub fn query_by_title<M: Into<Matcher>>(
&self,
alt: M,
matcher: M,
options: MatcherOptions,
) -> Result<Option<HtmlElement>, QueryError> {
get_by_alt_text(&self.element, alt, options)
query_by_title(&self.element, matcher, options)
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/dom/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ mod alt_text;
mod display_value;
mod placeholder_text;
mod test_id;
mod title;

pub use alt_text::*;
pub use display_value::*;
pub use placeholder_text::*;
pub use test_id::*;
pub use title::*;
79 changes: 79 additions & 0 deletions packages/dom/src/queries/title.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use wasm_bindgen::JsCast;
use web_sys::{Element, HtmlElement};

use crate::{
build_queries,
error::QueryError,
get_node_text,
matches::{fuzzy_matches, make_normalizer, matches},
types::{Matcher, MatcherOptions},
util::node_list_to_vec,
NormalizerOptions,
};

fn is_svg_title(node: &HtmlElement) -> bool {
node.tag_name().to_lowercase() == "title"
&& node
.parent_node()
.and_then(|parent_node| parent_node.dyn_into::<Element>().ok())
.is_some_and(|parent_node| parent_node.tag_name().to_lowercase() == "svg")
}

pub fn _query_all_by_title<M: Into<Matcher>>(
container: &HtmlElement,
text: M,
options: MatcherOptions,
) -> Result<Vec<HtmlElement>, QueryError> {
let text = text.into();
let matcher = match options.exact.unwrap_or(true) {
true => matches,
false => fuzzy_matches,
};
let match_normalizer = make_normalizer(NormalizerOptions {
trim: options.trim,
collapse_whitespace: options.collapse_whitespace,
normalizer: options.normalizer,
})?;

Ok(node_list_to_vec::<HtmlElement>(
container
.query_selector_all("[title], svg > title")
.map_err(QueryError::JsError)?,
)
.into_iter()
.filter(|node| {
matcher(
node.get_attribute("title"),
Some(node),
&text,
match_normalizer.as_ref(),
) || (is_svg_title(node)
&& matcher(
Some(get_node_text(node)),
Some(node),
&text,
match_normalizer.as_ref(),
))
})
.collect())
}

fn get_multiple_error(_container: &HtmlElement, title: Matcher) -> String {
format!("Found multiple elements with the title: {title}")
}

fn get_missing_error(_container: &HtmlElement, title: Matcher) -> String {
format!("Unable to find an element with the title: {title}")
}

build_queries!(
_query_all_by_title,
get_multiple_error,
get_missing_error,
title
);

pub use internal::{
find_all_by_title, find_by_title, get_all_by_title, get_by_title, query_all_by_title,
query_by_title,
};
12 changes: 12 additions & 0 deletions packages/dom/tests/element_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ fn get_throws_a_useful_error_message() -> Result<(), QueryError> {
)),
container_queries.get_by_display_value("LucyRicardo", MatcherOptions::default())
);
assert_eq!(
Err(QueryError::Element(
"Unable to find an element with the title: LucyRicardo\n\
\n\
Ignored nodes: comments, script, style\n\
<div>\n\
<div />\n\
</div>"
.into()
)),
container_queries.get_by_title("LucyRicardo", MatcherOptions::default())
);

after_each();

Expand Down

0 comments on commit c03893c

Please sign in to comment.