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()`](crate::protocol::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()`](crate::protocol::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"] =
71            serde_json::to_value(state).expect("serialization of WaitForState cannot fail");
72
73        // Timeout is required in Playwright 1.56.1+
74        if let Some(timeout) = self.timeout {
75            json["timeout"] = serde_json::json!(timeout);
76        } else {
77            json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
78        }
79
80        json
81    }
82}
83
84/// Builder for WaitForOptions
85///
86/// Provides a fluent API for constructing wait_for options.
87#[derive(Debug, Clone, Default)]
88pub struct WaitForOptionsBuilder {
89    state: Option<WaitForState>,
90    timeout: Option<f64>,
91}
92
93impl WaitForOptionsBuilder {
94    /// Set the element state to wait for
95    pub fn state(mut self, state: WaitForState) -> Self {
96        self.state = Some(state);
97        self
98    }
99
100    /// Set timeout in milliseconds
101    pub fn timeout(mut self, timeout: f64) -> Self {
102        self.timeout = Some(timeout);
103        self
104    }
105
106    /// Build the WaitForOptions
107    pub fn build(self) -> WaitForOptions {
108        WaitForOptions {
109            state: self.state,
110            timeout: self.timeout,
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_wait_for_state_serialization() {
121        assert_eq!(
122            serde_json::to_string(&WaitForState::Attached).unwrap(),
123            "\"attached\""
124        );
125        assert_eq!(
126            serde_json::to_string(&WaitForState::Detached).unwrap(),
127            "\"detached\""
128        );
129        assert_eq!(
130            serde_json::to_string(&WaitForState::Visible).unwrap(),
131            "\"visible\""
132        );
133        assert_eq!(
134            serde_json::to_string(&WaitForState::Hidden).unwrap(),
135            "\"hidden\""
136        );
137    }
138
139    #[test]
140    fn test_wait_for_options_default_state() {
141        // When no state is set, to_json() should produce "visible"
142        let options = WaitForOptions::builder().build();
143        let json = options.to_json();
144        assert_eq!(json["state"], "visible");
145        assert!(json["timeout"].is_number());
146    }
147
148    #[test]
149    fn test_wait_for_options_all_states() {
150        for (state, expected) in &[
151            (WaitForState::Attached, "attached"),
152            (WaitForState::Detached, "detached"),
153            (WaitForState::Visible, "visible"),
154            (WaitForState::Hidden, "hidden"),
155        ] {
156            let options = WaitForOptions::builder().state(*state).build();
157            let json = options.to_json();
158            assert_eq!(json["state"], *expected);
159        }
160    }
161
162    #[test]
163    fn test_wait_for_options_timeout() {
164        let options = WaitForOptions::builder().timeout(5000.0).build();
165        let json = options.to_json();
166        assert_eq!(json["timeout"], 5000.0);
167    }
168}