viewpoint_test/expect/
soft_locator.rs

1//! Soft locator assertion methods.
2//!
3//! This module contains all the assertion methods for `SoftLocatorAssertions`.
4
5use std::sync::{Arc, Mutex};
6
7use viewpoint_core::AriaSnapshot;
8
9use super::locator::LocatorAssertions;
10use super::soft::SoftAssertionError;
11
12/// Soft assertions for locators.
13///
14/// These assertions collect failures instead of failing immediately.
15pub struct SoftLocatorAssertions<'a> {
16    pub(super) assertions: LocatorAssertions<'a>,
17    pub(super) errors: Arc<Mutex<Vec<SoftAssertionError>>>,
18}
19
20/// Helper macro to reduce boilerplate in soft assertion methods.
21macro_rules! soft_assert {
22    ($self:expr, $method:ident, $assertion_name:expr) => {
23        match $self.assertions.$method().await {
24            Ok(()) => {}
25            Err(e) => {
26                $self.errors.lock().unwrap().push(
27                    SoftAssertionError::new($assertion_name, e.to_string())
28                );
29            }
30        }
31    };
32    ($self:expr, $method:ident, $assertion_name:expr, expected: $expected:expr) => {
33        match $self.assertions.$method(&$expected).await {
34            Ok(()) => {}
35            Err(e) => {
36                $self.errors.lock().unwrap().push(
37                    SoftAssertionError::new($assertion_name, e.to_string())
38                        .with_expected($expected.to_string())
39                );
40            }
41        }
42    };
43}
44
45impl SoftLocatorAssertions<'_> {
46    /// Assert element is visible (soft).
47    pub async fn to_be_visible(&self) {
48        soft_assert!(self, to_be_visible, "to_be_visible");
49    }
50
51    /// Assert element is hidden (soft).
52    pub async fn to_be_hidden(&self) {
53        soft_assert!(self, to_be_hidden, "to_be_hidden");
54    }
55
56    /// Assert element is enabled (soft).
57    pub async fn to_be_enabled(&self) {
58        soft_assert!(self, to_be_enabled, "to_be_enabled");
59    }
60
61    /// Assert element is disabled (soft).
62    pub async fn to_be_disabled(&self) {
63        soft_assert!(self, to_be_disabled, "to_be_disabled");
64    }
65
66    /// Assert element is checked (soft).
67    pub async fn to_be_checked(&self) {
68        soft_assert!(self, to_be_checked, "to_be_checked");
69    }
70
71    /// Assert element has text (soft).
72    pub async fn to_have_text(&self, expected: impl AsRef<str>) {
73        let expected_str = expected.as_ref().to_string();
74        soft_assert!(self, to_have_text, "to_have_text", expected: expected_str);
75    }
76
77    /// Assert element contains text (soft).
78    pub async fn to_contain_text(&self, expected: impl AsRef<str>) {
79        let expected_str = expected.as_ref().to_string();
80        soft_assert!(self, to_contain_text, "to_contain_text", expected: expected_str);
81    }
82
83    /// Assert element has value (soft).
84    pub async fn to_have_value(&self, expected: impl AsRef<str>) {
85        let expected_str = expected.as_ref().to_string();
86        soft_assert!(self, to_have_value, "to_have_value", expected: expected_str);
87    }
88
89    /// Assert element has attribute (soft).
90    pub async fn to_have_attribute(&self, name: impl AsRef<str>, value: impl AsRef<str>) {
91        let name_str = name.as_ref().to_string();
92        let value_str = value.as_ref().to_string();
93        match self.assertions.to_have_attribute(&name_str, &value_str).await {
94            Ok(()) => {}
95            Err(e) => {
96                self.errors.lock().unwrap().push(
97                    SoftAssertionError::new(
98                        format!("to_have_attribute({name_str})"),
99                        e.to_string(),
100                    )
101                    .with_expected(&value_str)
102                );
103            }
104        }
105    }
106
107    /// Assert element has class (soft).
108    pub async fn to_have_class(&self, class_name: impl AsRef<str>) {
109        let class_str = class_name.as_ref().to_string();
110        soft_assert!(self, to_have_class, "to_have_class", expected: class_str);
111    }
112
113    /// Assert element has id (soft).
114    pub async fn to_have_id(&self, expected: impl AsRef<str>) {
115        let expected_str = expected.as_ref().to_string();
116        soft_assert!(self, to_have_id, "to_have_id", expected: expected_str);
117    }
118
119    /// Assert element count (soft).
120    pub async fn to_have_count(&self, expected: usize) {
121        match self.assertions.to_have_count(expected).await {
122            Ok(()) => {}
123            Err(e) => {
124                self.errors.lock().unwrap().push(
125                    SoftAssertionError::new("to_have_count", e.to_string())
126                        .with_expected(expected.to_string())
127                );
128            }
129        }
130    }
131
132    /// Assert element count is greater than a value (soft).
133    pub async fn to_have_count_greater_than(&self, n: usize) {
134        match self.assertions.to_have_count_greater_than(n).await {
135            Ok(()) => {}
136            Err(e) => {
137                self.errors.lock().unwrap().push(
138                    SoftAssertionError::new("to_have_count_greater_than", e.to_string())
139                        .with_expected(format!("> {n}"))
140                );
141            }
142        }
143    }
144
145    /// Assert element count is less than a value (soft).
146    pub async fn to_have_count_less_than(&self, n: usize) {
147        match self.assertions.to_have_count_less_than(n).await {
148            Ok(()) => {}
149            Err(e) => {
150                self.errors.lock().unwrap().push(
151                    SoftAssertionError::new("to_have_count_less_than", e.to_string())
152                        .with_expected(format!("< {n}"))
153                );
154            }
155        }
156    }
157
158    /// Assert element count is at least a value (soft).
159    pub async fn to_have_count_at_least(&self, n: usize) {
160        match self.assertions.to_have_count_at_least(n).await {
161            Ok(()) => {}
162            Err(e) => {
163                self.errors.lock().unwrap().push(
164                    SoftAssertionError::new("to_have_count_at_least", e.to_string())
165                        .with_expected(format!(">= {n}"))
166                );
167            }
168        }
169    }
170
171    /// Assert element count is at most a value (soft).
172    pub async fn to_have_count_at_most(&self, n: usize) {
173        match self.assertions.to_have_count_at_most(n).await {
174            Ok(()) => {}
175            Err(e) => {
176                self.errors.lock().unwrap().push(
177                    SoftAssertionError::new("to_have_count_at_most", e.to_string())
178                        .with_expected(format!("<= {n}"))
179                );
180            }
181        }
182    }
183
184    /// Assert element's ARIA snapshot matches expected structure (soft).
185    pub async fn to_match_aria_snapshot(&self, expected: &AriaSnapshot) {
186        match self.assertions.to_match_aria_snapshot(expected).await {
187            Ok(()) => {}
188            Err(e) => {
189                self.errors.lock().unwrap().push(
190                    SoftAssertionError::new("to_match_aria_snapshot", e.to_string())
191                        .with_expected(expected.to_yaml())
192                );
193            }
194        }
195    }
196
197    /// Assert element's ARIA snapshot matches expected YAML string (soft).
198    pub async fn to_match_aria_snapshot_yaml(&self, expected_yaml: &str) {
199        match self.assertions.to_match_aria_snapshot_yaml(expected_yaml).await {
200            Ok(()) => {}
201            Err(e) => {
202                self.errors.lock().unwrap().push(
203                    SoftAssertionError::new("to_match_aria_snapshot_yaml", e.to_string())
204                        .with_expected(expected_yaml.to_string())
205                );
206            }
207        }
208    }
209
210    /// Assert elements have texts (soft).
211    pub async fn to_have_texts(&self, expected: &[&str]) {
212        match self.assertions.to_have_texts(expected).await {
213            Ok(()) => {}
214            Err(e) => {
215                self.errors.lock().unwrap().push(
216                    SoftAssertionError::new("to_have_texts", e.to_string())
217                        .with_expected(format!("{expected:?}"))
218                );
219            }
220        }
221    }
222
223    /// Assert elements contain texts (soft).
224    pub async fn to_contain_texts(&self, expected: &[&str]) {
225        match self.assertions.to_contain_texts(expected).await {
226            Ok(()) => {}
227            Err(e) => {
228                self.errors.lock().unwrap().push(
229                    SoftAssertionError::new("to_contain_texts", e.to_string())
230                        .with_expected(format!("{expected:?}"))
231                );
232            }
233        }
234    }
235
236    /// Assert element has all specified classes (soft).
237    pub async fn to_have_classes(&self, expected_classes: &[&str]) {
238        match self.assertions.to_have_classes(expected_classes).await {
239            Ok(()) => {}
240            Err(e) => {
241                self.errors.lock().unwrap().push(
242                    SoftAssertionError::new("to_have_classes", e.to_string())
243                        .with_expected(format!("{expected_classes:?}"))
244                );
245            }
246        }
247    }
248
249    /// Assert multi-select element has specified values (soft).
250    pub async fn to_have_values(&self, expected: &[&str]) {
251        match self.assertions.to_have_values(expected).await {
252            Ok(()) => {}
253            Err(e) => {
254                self.errors.lock().unwrap().push(
255                    SoftAssertionError::new("to_have_values", e.to_string())
256                        .with_expected(format!("{expected:?}"))
257                );
258            }
259        }
260    }
261}