browser_commander/utilities/
wait.rs1use crate::core::engine::{EngineAdapter, EngineError};
7use crate::core::navigation::is_navigation_error;
8use std::time::Duration;
9use tokio_util::sync::CancellationToken;
10
11#[derive(Debug, Clone)]
13pub struct WaitResult {
14 pub completed: bool,
16 pub aborted: bool,
18}
19
20impl WaitResult {
21 pub fn completed() -> Self {
23 Self {
24 completed: true,
25 aborted: false,
26 }
27 }
28
29 pub fn aborted() -> Self {
31 Self {
32 completed: false,
33 aborted: true,
34 }
35 }
36}
37
38pub async fn wait(duration: Duration, _reason: Option<&str>) -> WaitResult {
49 tokio::time::sleep(duration).await;
50 WaitResult::completed()
51}
52
53pub async fn wait_with_cancel(
65 duration: Duration,
66 cancel_token: &CancellationToken,
67 _reason: Option<&str>,
68) -> WaitResult {
69 if cancel_token.is_cancelled() {
71 return WaitResult::aborted();
72 }
73
74 tokio::select! {
75 _ = tokio::time::sleep(duration) => {
76 WaitResult::completed()
77 }
78 _ = cancel_token.cancelled() => {
79 WaitResult::aborted()
80 }
81 }
82}
83
84pub async fn evaluate(
95 adapter: &dyn EngineAdapter,
96 script: &str,
97) -> Result<serde_json::Value, EngineError> {
98 adapter.evaluate(script).await
99}
100
101pub async fn safe_evaluate(
113 adapter: &dyn EngineAdapter,
114 script: &str,
115 default: serde_json::Value,
116) -> SafeEvaluateResult {
117 match adapter.evaluate(script).await {
118 Ok(value) => SafeEvaluateResult {
119 success: true,
120 value,
121 navigation_error: false,
122 },
123 Err(e) if is_navigation_error(&e.to_string()) => SafeEvaluateResult {
124 success: false,
125 value: default,
126 navigation_error: true,
127 },
128 Err(_) => SafeEvaluateResult {
129 success: false,
130 value: default,
131 navigation_error: false,
132 },
133 }
134}
135
136#[derive(Debug, Clone)]
138pub struct SafeEvaluateResult {
139 pub success: bool,
141 pub value: serde_json::Value,
143 pub navigation_error: bool,
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn wait_result_completed() {
153 let result = WaitResult::completed();
154 assert!(result.completed);
155 assert!(!result.aborted);
156 }
157
158 #[test]
159 fn wait_result_aborted() {
160 let result = WaitResult::aborted();
161 assert!(!result.completed);
162 assert!(result.aborted);
163 }
164
165 #[tokio::test]
166 async fn wait_completes() {
167 let start = std::time::Instant::now();
168 let result = wait(Duration::from_millis(50), Some("test wait")).await;
169 let elapsed = start.elapsed();
170
171 assert!(result.completed);
172 assert!(!result.aborted);
173 assert!(elapsed >= Duration::from_millis(50));
174 }
175
176 #[tokio::test]
177 async fn wait_with_cancel_completes_normally() {
178 let token = CancellationToken::new();
179 let result = wait_with_cancel(Duration::from_millis(10), &token, Some("test wait")).await;
180
181 assert!(result.completed);
182 assert!(!result.aborted);
183 }
184
185 #[tokio::test]
186 async fn wait_with_cancel_aborts_on_cancel() {
187 let token = CancellationToken::new();
188
189 token.cancel();
191
192 let result = wait_with_cancel(
193 Duration::from_secs(10), &token,
195 Some("test wait"),
196 )
197 .await;
198
199 assert!(!result.completed);
200 assert!(result.aborted);
201 }
202
203 #[tokio::test]
204 async fn wait_with_cancel_aborts_during_wait() {
205 let token = CancellationToken::new();
206 let token_clone = token.clone();
207
208 tokio::spawn(async move {
210 tokio::time::sleep(Duration::from_millis(50)).await;
211 token_clone.cancel();
212 });
213
214 let start = std::time::Instant::now();
215 let result = wait_with_cancel(
216 Duration::from_secs(10), &token,
218 Some("test wait"),
219 )
220 .await;
221 let elapsed = start.elapsed();
222
223 assert!(!result.completed);
224 assert!(result.aborted);
225 assert!(elapsed < Duration::from_secs(1));
227 }
228
229 #[test]
230 fn safe_evaluate_result_success() {
231 let result = SafeEvaluateResult {
232 success: true,
233 value: serde_json::json!(42),
234 navigation_error: false,
235 };
236 assert!(result.success);
237 assert!(!result.navigation_error);
238 assert_eq!(result.value, serde_json::json!(42));
239 }
240
241 #[test]
242 fn safe_evaluate_result_navigation_error() {
243 let result = SafeEvaluateResult {
244 success: false,
245 value: serde_json::Value::Null,
246 navigation_error: true,
247 };
248 assert!(!result.success);
249 assert!(result.navigation_error);
250 assert!(result.value.is_null());
251 }
252}