testing_library_dom/queries/
text.rs1use web_sys::HtmlElement;
2
3use crate::{
4 build_queries,
5 config::get_config,
6 error::QueryError,
7 get_node_text::get_node_text,
8 matches::{fuzzy_matches, make_normalizer, matches},
9 types::{Ignore, Matcher, NormalizerOptions, SelectorMatcherOptions},
10 util::node_list_to_vec,
11};
12
13pub fn _query_all_by_text<M: Into<Matcher>>(
14 container: &HtmlElement,
15 text: M,
16 options: SelectorMatcherOptions,
17) -> Result<Vec<HtmlElement>, QueryError> {
18 let text = text.into();
19 let selector = options.selector.unwrap_or("*".into());
20 let ignore = options.ignore.unwrap_or(get_config().default_ignore.into());
21 let matcher = match options.exact.unwrap_or(true) {
22 true => matches,
23 false => fuzzy_matches,
24 };
25 let match_normalizer = make_normalizer(NormalizerOptions {
26 trim: options.trim,
27 collapse_whitespace: options.collapse_whitespace,
28 normalizer: options.normalizer,
29 })?;
30
31 let mut base_array = vec![];
32 if container.matches(&selector).map_err(QueryError::JsError)? {
33 base_array.push(container.clone());
34 }
35
36 Ok(base_array
37 .into_iter()
38 .chain(node_list_to_vec::<HtmlElement>(
39 container
40 .query_selector_all(&selector)
41 .map_err(QueryError::JsError)?,
42 ))
43 .filter(|node| match &ignore {
44 Ignore::False => true,
45 Ignore::String(ignore) => !node.matches(ignore).unwrap_or(false),
46 })
47 .filter(|node| {
48 matcher(
49 Some(get_node_text(node)),
50 Some(node),
51 &text,
52 match_normalizer.as_ref(),
53 )
54 })
55 .collect())
56}
57
58fn get_multiple_error(
59 _container: &HtmlElement,
60 text: Matcher,
61 _options: SelectorMatcherOptions,
62) -> Result<String, QueryError> {
63 Ok(format!("Found multiple elements with the text: {text}"))
64}
65
66fn get_missing_error(
67 _container: &HtmlElement,
68 text: Matcher,
69 options: SelectorMatcherOptions,
70) -> Result<String, QueryError> {
71 let match_normalizer = make_normalizer(NormalizerOptions {
72 trim: options.trim,
73 collapse_whitespace: options.collapse_whitespace,
74 normalizer: options.normalizer,
75 })?;
76 let text = text.to_string();
77 let normalized_text = match_normalizer(text.clone());
78 let is_normalized_different = normalized_text != text;
79
80 let selector = options.selector.unwrap_or("*".into());
81 let is_custom_selector = selector != "*";
82
83 Ok(format!(
84 "Unable to find an element with the text: {}{}. \
85 This could be because the text is broken up by multiple elements. \
86 In this case, you can provide a function for your text matcher to make your matcher more flexible.",
87 match is_normalized_different {
88 true => format!("{normalized_text} (normalized from '{text}')"),
89 false => text,
90 },
91 match is_custom_selector {
92 true => format!(", which matches selector '{selector}'"),
93 false => "".into(),
94 }
95 ))
96}
97
98build_queries!(
99 _query_all_by_text,
100 get_multiple_error,
101 get_missing_error,
102 text,
103 crate::types::Matcher,
104 crate::types::SelectorMatcherOptions
105);
106
107pub use internal::{
108 find_all_by_text, find_by_text, get_all_by_text, get_by_text, query_all_by_text, query_by_text,
109};