viewpoint_test/expect/
page.rs1use std::time::Duration;
4
5use viewpoint_core::Page;
6
7use crate::error::AssertionError;
8
9const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
11
12pub struct PageAssertions<'a> {
14 page: &'a Page,
15 timeout: Duration,
16 is_negated: bool,
17}
18
19impl<'a> PageAssertions<'a> {
20 pub fn new(page: &'a Page) -> Self {
22 Self {
23 page,
24 timeout: DEFAULT_TIMEOUT,
25 is_negated: false,
26 }
27 }
28
29 #[must_use]
31 pub fn timeout(mut self, timeout: Duration) -> Self {
32 self.timeout = timeout;
33 self
34 }
35
36 #[must_use]
40 pub fn negated(mut self) -> Self {
41 self.is_negated = !self.is_negated;
42 self
43 }
44
45 #[must_use]
50 #[allow(clippy::should_implement_trait)]
51 pub fn not(self) -> Self {
52 self.negated()
53 }
54
55 pub async fn to_have_url(&self, expected: &str) -> Result<(), AssertionError> {
61 let start = std::time::Instant::now();
62
63 loop {
64 let url = self
65 .page
66 .url()
67 .await
68 .map_err(|e| AssertionError::new("Failed to get URL", expected, e.to_string()))?;
69
70 let matches = url == expected;
71 let expected_match = !self.is_negated;
72
73 if matches == expected_match {
74 return Ok(());
75 }
76
77 if start.elapsed() >= self.timeout {
78 return Err(AssertionError::new(
79 if self.is_negated {
80 "Page should not have URL"
81 } else {
82 "Page should have URL"
83 },
84 if self.is_negated {
85 format!("not \"{expected}\"")
86 } else {
87 expected.to_string()
88 },
89 url,
90 ));
91 }
92
93 tokio::time::sleep(Duration::from_millis(100)).await;
94 }
95 }
96
97 pub async fn to_have_url_containing(&self, expected: &str) -> Result<(), AssertionError> {
103 let start = std::time::Instant::now();
104
105 loop {
106 let url = self
107 .page
108 .url()
109 .await
110 .map_err(|e| AssertionError::new("Failed to get URL", expected, e.to_string()))?;
111
112 let contains = url.contains(expected);
113 let expected_match = !self.is_negated;
114
115 if contains == expected_match {
116 return Ok(());
117 }
118
119 if start.elapsed() >= self.timeout {
120 return Err(AssertionError::new(
121 if self.is_negated {
122 "Page URL should not contain"
123 } else {
124 "Page URL should contain"
125 },
126 if self.is_negated {
127 format!("not containing \"{expected}\"")
128 } else {
129 format!("containing \"{expected}\"")
130 },
131 url,
132 ));
133 }
134
135 tokio::time::sleep(Duration::from_millis(100)).await;
136 }
137 }
138
139 pub async fn to_have_title(&self, expected: &str) -> Result<(), AssertionError> {
145 let start = std::time::Instant::now();
146
147 loop {
148 let title = self
149 .page
150 .title()
151 .await
152 .map_err(|e| AssertionError::new("Failed to get title", expected, e.to_string()))?;
153
154 let matches = title == expected;
155 let expected_match = !self.is_negated;
156
157 if matches == expected_match {
158 return Ok(());
159 }
160
161 if start.elapsed() >= self.timeout {
162 return Err(AssertionError::new(
163 if self.is_negated {
164 "Page should not have title"
165 } else {
166 "Page should have title"
167 },
168 if self.is_negated {
169 format!("not \"{expected}\"")
170 } else {
171 expected.to_string()
172 },
173 title,
174 ));
175 }
176
177 tokio::time::sleep(Duration::from_millis(100)).await;
178 }
179 }
180
181 pub async fn to_have_title_containing(&self, expected: &str) -> Result<(), AssertionError> {
187 let start = std::time::Instant::now();
188
189 loop {
190 let title = self
191 .page
192 .title()
193 .await
194 .map_err(|e| AssertionError::new("Failed to get title", expected, e.to_string()))?;
195
196 let contains = title.contains(expected);
197 let expected_match = !self.is_negated;
198
199 if contains == expected_match {
200 return Ok(());
201 }
202
203 if start.elapsed() >= self.timeout {
204 return Err(AssertionError::new(
205 if self.is_negated {
206 "Page title should not contain"
207 } else {
208 "Page title should contain"
209 },
210 if self.is_negated {
211 format!("not containing \"{expected}\"")
212 } else {
213 format!("containing \"{expected}\"")
214 },
215 title,
216 ));
217 }
218
219 tokio::time::sleep(Duration::from_millis(100)).await;
220 }
221 }
222}