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