testing_library_dom/
matches.rs

1use std::rc::Rc;
2
3use regex::Regex;
4use web_sys::Element;
5
6use crate::{
7    error::QueryError, DefaultNormalizerOptions, Matcher, NormalizerFn, NormalizerOptions,
8};
9
10pub fn fuzzy_matches(
11    text_to_match: Option<String>,
12    node: Option<&Element>,
13    matcher: &Matcher,
14    normalizer: &NormalizerFn,
15) -> bool {
16    if let Some(text_to_match) = text_to_match {
17        let normalized_text = normalizer(text_to_match);
18
19        match matcher {
20            Matcher::Function(matcher) => matcher(normalized_text, node),
21            Matcher::Regex(matcher) => match_regex(matcher, normalized_text),
22            Matcher::Number(matcher) => normalized_text == matcher.to_string(),
23            Matcher::String(matcher) => normalized_text.to_lowercase() == matcher.to_lowercase(),
24        }
25    } else {
26        false
27    }
28}
29
30pub fn matches(
31    text_to_match: Option<String>,
32    node: Option<&Element>,
33    matcher: &Matcher,
34    normalizer: &NormalizerFn,
35) -> bool {
36    if let Some(text_to_match) = text_to_match {
37        let normalized_text = normalizer(text_to_match);
38
39        match matcher {
40            Matcher::Function(matcher) => matcher(normalized_text, node),
41            Matcher::Regex(matcher) => match_regex(matcher, normalized_text),
42            Matcher::Number(matcher) => normalized_text == matcher.to_string(),
43            Matcher::String(matcher) => normalized_text == *matcher,
44        }
45    } else {
46        false
47    }
48}
49
50pub fn get_default_normalizer(
51    DefaultNormalizerOptions {
52        trim,
53        collapse_whitespace,
54    }: DefaultNormalizerOptions,
55) -> Rc<NormalizerFn> {
56    let trim = trim.unwrap_or(true);
57    let collapse_whitespace = collapse_whitespace.unwrap_or(true);
58
59    Rc::new(move |text| {
60        let mut normalized_text = text;
61
62        if trim {
63            normalized_text = normalized_text.trim().to_string();
64        }
65
66        if collapse_whitespace {
67            normalized_text = Regex::new(r"\s+")
68                .expect("Regex should be valid.")
69                .replace_all(&normalized_text, " ")
70                .to_string();
71        }
72
73        normalized_text
74    })
75}
76
77/// Constructs a normalizer to pass to matches functions.
78pub fn make_normalizer(
79    NormalizerOptions {
80        trim,
81        collapse_whitespace,
82        normalizer,
83    }: NormalizerOptions,
84) -> Result<Rc<NormalizerFn>, QueryError> {
85    if let Some(normalizer) = normalizer {
86        if trim.is_some() || collapse_whitespace.is_some() {
87            Err(QueryError::Configuration("\n\
88                `trim` and `collapse_whitespace` are not supported with a normalizer. \n\
89                If you want to use the default trim and `collapse_whitespace logic in your normalizer, \n\
90                use `get_default_normalizer(DefaultNormalizerOptions {trim, collapse_whitespace})` and compose that into your normalizer.\
91            ".into()))
92        } else {
93            Ok(normalizer)
94        }
95    } else {
96        // No custom normalizer specified. Just use default.
97        Ok(get_default_normalizer(DefaultNormalizerOptions {
98            trim,
99            collapse_whitespace,
100        }))
101    }
102}
103
104fn match_regex(matcher: &Regex, text: String) -> bool {
105    // TODO: if statement?
106    matcher.is_match(&text)
107}