Skip to main content

playwright_rs/protocol/
wait_for.rs

1// WaitForOptions and WaitForState types
2//
3// Provides configuration for wait_for actions, matching Playwright's API.
4
5use serde::Serialize;
6
7/// The state to wait for when using [`Locator::wait_for()`].
8///
9/// Matches Playwright's `WaitForSelectorState` across all language bindings.
10///
11/// See: <https://playwright.dev/docs/api/class-locator#locator-wait-for>
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "lowercase")]
14pub enum WaitForState {
15    /// Wait for the element to be present in the DOM (attached).
16    Attached,
17    /// Wait for the element to be removed from the DOM.
18    Detached,
19    /// Wait for the element to be visible (the default).
20    Visible,
21    /// Wait for the element to be hidden (invisible or not in the DOM).
22    Hidden,
23}
24
25/// Options for [`Locator::wait_for()`].
26///
27/// Configuration for waiting until an element satisfies a given state condition.
28/// If no state is specified, defaults to `Visible`.
29///
30/// Use the builder pattern to construct options:
31///
32/// # Example
33///
34/// ```ignore
35/// use playwright_rs::{WaitForOptions, WaitForState};
36///
37/// // Wait until the element is visible
38/// let options = WaitForOptions::builder()
39///     .state(WaitForState::Visible)
40///     .build();
41///
42/// // Wait until the element is hidden, with a custom timeout
43/// let options = WaitForOptions::builder()
44///     .state(WaitForState::Hidden)
45///     .timeout(5000.0)
46///     .build();
47/// ```
48///
49/// See: <https://playwright.dev/docs/api/class-locator#locator-wait-for>
50#[derive(Debug, Clone, Default)]
51pub struct WaitForOptions {
52    /// The element state to wait for (defaults to `Visible` if not set)
53    pub state: Option<WaitForState>,
54    /// Maximum time in milliseconds
55    pub timeout: Option<f64>,
56}
57
58impl WaitForOptions {
59    /// Create a new builder for WaitForOptions
60    pub fn builder() -> WaitForOptionsBuilder {
61        WaitForOptionsBuilder::default()
62    }
63
64    /// Convert options to JSON value for protocol
65    pub(crate) fn to_json(&self) -> serde_json::Value {
66        let mut json = serde_json::json!({});
67
68        // Default to "visible" when no state is specified (matches Playwright behavior)
69        let state = self.state.unwrap_or(WaitForState::Visible);
70        json["state"] = serde_json::to_value(state).unwrap();
71
72        // Timeout is required in Playwright 1.56.1+
73        if let Some(timeout) = self.timeout {
74            json["timeout"] = serde_json::json!(timeout);
75        } else {
76            json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
77        }
78
79        json
80    }
81}
82
83/// Builder for WaitForOptions
84///
85/// Provides a fluent API for constructing wait_for options.
86#[derive(Debug, Clone, Default)]
87pub struct WaitForOptionsBuilder {
88    state: Option<WaitForState>,
89    timeout: Option<f64>,
90}
91
92impl WaitForOptionsBuilder {
93    /// Set the element state to wait for
94    pub fn state(mut self, state: WaitForState) -> Self {
95        self.state = Some(state);
96        self
97    }
98
99    /// Set timeout in milliseconds
100    pub fn timeout(mut self, timeout: f64) -> Self {
101        self.timeout = Some(timeout);
102        self
103    }
104
105    /// Build the WaitForOptions
106    pub fn build(self) -> WaitForOptions {
107        WaitForOptions {
108            state: self.state,
109            timeout: self.timeout,
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_wait_for_state_serialization() {
120        assert_eq!(
121            serde_json::to_string(&WaitForState::Attached).unwrap(),
122            "\"attached\""
123        );
124        assert_eq!(
125            serde_json::to_string(&WaitForState::Detached).unwrap(),
126            "\"detached\""
127        );
128        assert_eq!(
129            serde_json::to_string(&WaitForState::Visible).unwrap(),
130            "\"visible\""
131        );
132        assert_eq!(
133            serde_json::to_string(&WaitForState::Hidden).unwrap(),
134            "\"hidden\""
135        );
136    }
137
138    #[test]
139    fn test_wait_for_options_default_state() {
140        // When no state is set, to_json() should produce "visible"
141        let options = WaitForOptions::builder().build();
142        let json = options.to_json();
143        assert_eq!(json["state"], "visible");
144        assert!(json["timeout"].is_number());
145    }
146
147    #[test]
148    fn test_wait_for_options_all_states() {
149        for (state, expected) in &[
150            (WaitForState::Attached, "attached"),
151            (WaitForState::Detached, "detached"),
152            (WaitForState::Visible, "visible"),
153            (WaitForState::Hidden, "hidden"),
154        ] {
155            let options = WaitForOptions::builder().state(*state).build();
156            let json = options.to_json();
157            assert_eq!(json["state"], *expected);
158        }
159    }
160
161    #[test]
162    fn test_wait_for_options_timeout() {
163        let options = WaitForOptions::builder().timeout(5000.0).build();
164        let json = options.to_json();
165        assert_eq!(json["timeout"], 5000.0);
166    }
167}