Skip to main content

limit_cli/tools/browser/client_ext/
waiting.rs

1//! Waiting operations
2
3use crate::tools::browser::executor::BrowserError;
4
5/// Waiting operations for browser client
6pub trait WaitingExt {
7    /// Wait for a condition (text, element, or timeout)
8    fn wait_for(
9        &self,
10        condition: &str,
11    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
12
13    /// Wait for text to appear on page
14    fn wait_for_text(
15        &self,
16        text: &str,
17    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
18
19    /// Wait for URL pattern match
20    fn wait_for_url(
21        &self,
22        pattern: &str,
23    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
24
25    /// Wait for page load state (networkidle, domcontentloaded, load)
26    fn wait_for_load(
27        &self,
28        state: &str,
29    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
30
31    /// Wait for download to complete, returns download path
32    fn wait_for_download(
33        &self,
34        path: Option<&str>,
35    ) -> impl std::future::Future<Output = Result<String, BrowserError>> + Send;
36
37    /// Wait for JavaScript function to return truthy value
38    fn wait_for_fn(
39        &self,
40        js: &str,
41    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
42
43    /// Wait for element state (visible, hidden, attached, detached, enabled, disabled)
44    fn wait_for_state(
45        &self,
46        selector: &str,
47        state: &str,
48    ) -> impl std::future::Future<Output = Result<(), BrowserError>> + Send;
49}
50
51impl WaitingExt for super::super::BrowserClient {
52    async fn wait_for(&self, condition: &str) -> Result<(), BrowserError> {
53        if condition.is_empty() {
54            return Err(BrowserError::InvalidArguments(
55                "Condition cannot be empty".to_string(),
56            ));
57        }
58
59        let output = self.executor().execute(&["wait", condition]).await?;
60
61        if output.success {
62            Ok(())
63        } else {
64            Err(BrowserError::Other(format!(
65                "Wait condition not met: {}",
66                output.stderr
67            )))
68        }
69    }
70
71    async fn wait_for_text(&self, text: &str) -> Result<(), BrowserError> {
72        if text.is_empty() {
73            return Err(BrowserError::InvalidArguments(
74                "Text cannot be empty".to_string(),
75            ));
76        }
77
78        let output = self.executor().execute(&["wait", "--text", text]).await?;
79
80        if output.success {
81            Ok(())
82        } else {
83            Err(BrowserError::Other(format!(
84                "Text not found: {}",
85                output.stderr
86            )))
87        }
88    }
89
90    async fn wait_for_url(&self, pattern: &str) -> Result<(), BrowserError> {
91        if pattern.is_empty() {
92            return Err(BrowserError::InvalidArguments(
93                "URL pattern cannot be empty".to_string(),
94            ));
95        }
96
97        let output = self.executor().execute(&["wait", "--url", pattern]).await?;
98
99        if output.success {
100            Ok(())
101        } else {
102            Err(BrowserError::Other(format!(
103                "URL pattern not matched: {}",
104                output.stderr
105            )))
106        }
107    }
108
109    async fn wait_for_load(&self, state: &str) -> Result<(), BrowserError> {
110        let valid_states = ["networkidle", "domcontentloaded", "load"];
111        if !valid_states.contains(&state) {
112            return Err(BrowserError::InvalidArguments(format!(
113                "Invalid load state '{}'. Valid states: {}",
114                state,
115                valid_states.join(", ")
116            )));
117        }
118
119        let output = self.executor().execute(&["wait", "--load", state]).await?;
120
121        if output.success {
122            Ok(())
123        } else {
124            Err(BrowserError::Other(format!(
125                "Load state not reached: {}",
126                output.stderr
127            )))
128        }
129    }
130
131    async fn wait_for_download(&self, path: Option<&str>) -> Result<String, BrowserError> {
132        let output = if let Some(p) = path {
133            self.executor().execute(&["wait", "--download", p]).await?
134        } else {
135            self.executor().execute(&["wait", "--download"]).await?
136        };
137
138        if output.success {
139            Ok(output.stdout.trim().to_string())
140        } else {
141            Err(BrowserError::Other(format!(
142                "Download wait failed: {}",
143                output.stderr
144            )))
145        }
146    }
147
148    async fn wait_for_fn(&self, js: &str) -> Result<(), BrowserError> {
149        if js.is_empty() {
150            return Err(BrowserError::InvalidArguments(
151                "JavaScript function cannot be empty".to_string(),
152            ));
153        }
154
155        let output = self.executor().execute(&["wait", "--fn", js]).await?;
156
157        if output.success {
158            Ok(())
159        } else {
160            Err(BrowserError::Other(format!(
161                "JavaScript condition not met: {}",
162                output.stderr
163            )))
164        }
165    }
166
167    async fn wait_for_state(&self, selector: &str, state: &str) -> Result<(), BrowserError> {
168        let valid_states = [
169            "visible", "hidden", "attached", "detached", "enabled", "disabled",
170        ];
171        if !valid_states.contains(&state) {
172            return Err(BrowserError::InvalidArguments(format!(
173                "Invalid state '{}'. Valid states: {}",
174                state,
175                valid_states.join(", ")
176            )));
177        }
178
179        if selector.is_empty() {
180            return Err(BrowserError::InvalidArguments(
181                "Selector cannot be empty".to_string(),
182            ));
183        }
184
185        let output = self
186            .executor()
187            .execute(&["wait", "--state", state, selector])
188            .await?;
189
190        if output.success {
191            Ok(())
192        } else {
193            Err(BrowserError::Other(format!(
194                "Element state not reached: {}",
195                output.stderr
196            )))
197        }
198    }
199}