Skip to main content

playwright_rs/protocol/
action_options.rs

1// Action options for various Locator methods
2//
3// Provides configuration for fill, press, check, hover, and select actions.
4
5use super::click::{KeyboardModifier, Position};
6
7/// Fill options
8///
9/// Configuration options for fill() action.
10///
11/// See: <https://playwright.dev/docs/api/class-locator#locator-fill>
12#[derive(Debug, Clone, Default, serde::Serialize)]
13#[serde(rename_all = "camelCase")]
14#[non_exhaustive]
15pub struct FillOptions {
16    /// Whether to bypass actionability checks
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub force: Option<bool>,
19    /// Maximum time in milliseconds
20    #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
21    pub timeout: Option<f64>,
22}
23
24impl FillOptions {
25    /// Create a new builder for FillOptions
26    pub fn builder() -> FillOptionsBuilder {
27        FillOptionsBuilder::default()
28    }
29
30    /// Convert options to JSON value for protocol
31    pub(crate) fn to_json(&self) -> serde_json::Value {
32        serde_json::to_value(self).expect("FillOptions serialization cannot fail")
33    }
34}
35
36/// Builder for FillOptions
37#[derive(Debug, Clone, Default)]
38pub struct FillOptionsBuilder {
39    force: Option<bool>,
40    timeout: Option<f64>,
41}
42
43impl FillOptionsBuilder {
44    /// Bypass actionability checks
45    pub fn force(mut self, force: bool) -> Self {
46        self.force = Some(force);
47        self
48    }
49
50    /// Set timeout in milliseconds
51    pub fn timeout(mut self, timeout: f64) -> Self {
52        self.timeout = Some(timeout);
53        self
54    }
55
56    /// Build the FillOptions
57    pub fn build(self) -> FillOptions {
58        FillOptions {
59            force: self.force,
60            timeout: self.timeout,
61        }
62    }
63}
64
65/// Press options
66///
67/// Configuration options for press() action.
68///
69/// See: <https://playwright.dev/docs/api/class-locator#locator-press>
70#[derive(Debug, Clone, Default, serde::Serialize)]
71#[serde(rename_all = "camelCase")]
72#[non_exhaustive]
73pub struct PressOptions {
74    /// Time to wait between keydown and keyup in milliseconds
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub delay: Option<f64>,
77    /// Maximum time in milliseconds
78    #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
79    pub timeout: Option<f64>,
80}
81
82impl PressOptions {
83    /// Create a new builder for PressOptions
84    pub fn builder() -> PressOptionsBuilder {
85        PressOptionsBuilder::default()
86    }
87
88    /// Convert options to JSON value for protocol
89    pub(crate) fn to_json(&self) -> serde_json::Value {
90        serde_json::to_value(self).expect("PressOptions serialization cannot fail")
91    }
92}
93
94/// Builder for PressOptions
95#[derive(Debug, Clone, Default)]
96pub struct PressOptionsBuilder {
97    delay: Option<f64>,
98    timeout: Option<f64>,
99}
100
101impl PressOptionsBuilder {
102    /// Set delay between keydown and keyup in milliseconds
103    pub fn delay(mut self, delay: f64) -> Self {
104        self.delay = Some(delay);
105        self
106    }
107
108    /// Set timeout in milliseconds
109    pub fn timeout(mut self, timeout: f64) -> Self {
110        self.timeout = Some(timeout);
111        self
112    }
113
114    /// Build the PressOptions
115    pub fn build(self) -> PressOptions {
116        PressOptions {
117            delay: self.delay,
118            timeout: self.timeout,
119        }
120    }
121}
122
123/// Check options
124///
125/// Configuration options for check() and uncheck() actions.
126///
127/// See: <https://playwright.dev/docs/api/class-locator#locator-check>
128#[derive(Debug, Clone, Default, serde::Serialize)]
129#[serde(rename_all = "camelCase")]
130#[non_exhaustive]
131pub struct CheckOptions {
132    /// Whether to bypass actionability checks
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub force: Option<bool>,
135    /// Position to click relative to element top-left corner
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub position: Option<Position>,
138    /// Maximum time in milliseconds
139    #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
140    pub timeout: Option<f64>,
141    /// Perform actionability checks without checking
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub trial: Option<bool>,
144}
145
146impl CheckOptions {
147    /// Create a new builder for CheckOptions
148    pub fn builder() -> CheckOptionsBuilder {
149        CheckOptionsBuilder::default()
150    }
151
152    /// Convert options to JSON value for protocol
153    pub(crate) fn to_json(&self) -> serde_json::Value {
154        serde_json::to_value(self).expect("CheckOptions serialization cannot fail")
155    }
156}
157
158/// Builder for CheckOptions
159#[derive(Debug, Clone, Default)]
160pub struct CheckOptionsBuilder {
161    force: Option<bool>,
162    position: Option<Position>,
163    timeout: Option<f64>,
164    trial: Option<bool>,
165}
166
167impl CheckOptionsBuilder {
168    /// Bypass actionability checks
169    pub fn force(mut self, force: bool) -> Self {
170        self.force = Some(force);
171        self
172    }
173
174    /// Set position to click relative to element top-left corner
175    pub fn position(mut self, position: Position) -> Self {
176        self.position = Some(position);
177        self
178    }
179
180    /// Set timeout in milliseconds
181    pub fn timeout(mut self, timeout: f64) -> Self {
182        self.timeout = Some(timeout);
183        self
184    }
185
186    /// Perform actionability checks without checking
187    pub fn trial(mut self, trial: bool) -> Self {
188        self.trial = Some(trial);
189        self
190    }
191
192    /// Build the CheckOptions
193    pub fn build(self) -> CheckOptions {
194        CheckOptions {
195            force: self.force,
196            position: self.position,
197            timeout: self.timeout,
198            trial: self.trial,
199        }
200    }
201}
202
203/// Hover options
204///
205/// Configuration options for hover() action.
206///
207/// See: <https://playwright.dev/docs/api/class-locator#locator-hover>
208#[derive(Debug, Clone, Default, serde::Serialize)]
209#[serde(rename_all = "camelCase")]
210#[non_exhaustive]
211pub struct HoverOptions {
212    /// Whether to bypass actionability checks
213    #[serde(skip_serializing_if = "Option::is_none")]
214    pub force: Option<bool>,
215    /// Modifier keys to press during hover
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub modifiers: Option<Vec<KeyboardModifier>>,
218    /// Position to hover relative to element top-left corner
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub position: Option<Position>,
221    /// Maximum time in milliseconds
222    #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
223    pub timeout: Option<f64>,
224    /// Perform actionability checks without hovering
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub trial: Option<bool>,
227}
228
229impl HoverOptions {
230    /// Create a new builder for HoverOptions
231    pub fn builder() -> HoverOptionsBuilder {
232        HoverOptionsBuilder::default()
233    }
234
235    /// Convert options to JSON value for protocol
236    pub(crate) fn to_json(&self) -> serde_json::Value {
237        serde_json::to_value(self).expect("HoverOptions serialization cannot fail")
238    }
239}
240
241/// Builder for HoverOptions
242#[derive(Debug, Clone, Default)]
243pub struct HoverOptionsBuilder {
244    force: Option<bool>,
245    modifiers: Option<Vec<KeyboardModifier>>,
246    position: Option<Position>,
247    timeout: Option<f64>,
248    trial: Option<bool>,
249}
250
251impl HoverOptionsBuilder {
252    /// Bypass actionability checks
253    pub fn force(mut self, force: bool) -> Self {
254        self.force = Some(force);
255        self
256    }
257
258    /// Set modifier keys to press during hover
259    pub fn modifiers(mut self, modifiers: Vec<KeyboardModifier>) -> Self {
260        self.modifiers = Some(modifiers);
261        self
262    }
263
264    /// Set position to hover relative to element top-left corner
265    pub fn position(mut self, position: Position) -> Self {
266        self.position = Some(position);
267        self
268    }
269
270    /// Set timeout in milliseconds
271    pub fn timeout(mut self, timeout: f64) -> Self {
272        self.timeout = Some(timeout);
273        self
274    }
275
276    /// Perform actionability checks without hovering
277    pub fn trial(mut self, trial: bool) -> Self {
278        self.trial = Some(trial);
279        self
280    }
281
282    /// Build the HoverOptions
283    pub fn build(self) -> HoverOptions {
284        HoverOptions {
285            force: self.force,
286            modifiers: self.modifiers,
287            position: self.position,
288            timeout: self.timeout,
289            trial: self.trial,
290        }
291    }
292}
293
294/// Options for [`Locator::press_sequentially()`](crate::protocol::Locator::press_sequentially).
295///
296/// Controls timing between key presses when typing characters one by one.
297///
298/// See: <https://playwright.dev/docs/api/class-locator#locator-press-sequentially>
299#[derive(Debug, Clone, Default)]
300#[non_exhaustive]
301pub struct PressSequentiallyOptions {
302    /// Delay between key presses in milliseconds. Defaults to 0.
303    pub delay: Option<f64>,
304}
305
306impl PressSequentiallyOptions {
307    /// Create a new builder for PressSequentiallyOptions
308    pub fn builder() -> PressSequentiallyOptionsBuilder {
309        PressSequentiallyOptionsBuilder::default()
310    }
311
312    /// Convert options to JSON value for protocol
313    pub(crate) fn to_json(&self) -> serde_json::Value {
314        let mut json = serde_json::json!({});
315
316        if let Some(delay) = self.delay {
317            json["delay"] = serde_json::json!(delay);
318        }
319
320        // Timeout is required in Playwright 1.56.1+
321        json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
322
323        json
324    }
325}
326
327/// Builder for PressSequentiallyOptions
328#[derive(Debug, Clone, Default)]
329pub struct PressSequentiallyOptionsBuilder {
330    delay: Option<f64>,
331}
332
333impl PressSequentiallyOptionsBuilder {
334    /// Set delay between key presses in milliseconds
335    pub fn delay(mut self, delay: f64) -> Self {
336        self.delay = Some(delay);
337        self
338    }
339
340    /// Build the PressSequentiallyOptions
341    pub fn build(self) -> PressSequentiallyOptions {
342        PressSequentiallyOptions { delay: self.delay }
343    }
344}
345
346/// Select options
347///
348/// Configuration options for select_option() action.
349///
350/// See: <https://playwright.dev/docs/api/class-locator#locator-select-option>
351#[derive(Debug, Clone, Default, serde::Serialize)]
352#[serde(rename_all = "camelCase")]
353#[non_exhaustive]
354pub struct SelectOptions {
355    /// Whether to bypass actionability checks
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub force: Option<bool>,
358    /// Maximum time in milliseconds
359    #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
360    pub timeout: Option<f64>,
361}
362
363impl SelectOptions {
364    /// Create a new builder for SelectOptions
365    pub fn builder() -> SelectOptionsBuilder {
366        SelectOptionsBuilder::default()
367    }
368
369    /// Convert options to JSON value for protocol
370    pub(crate) fn to_json(&self) -> serde_json::Value {
371        serde_json::to_value(self).expect("SelectOptions serialization cannot fail")
372    }
373}
374
375/// Builder for SelectOptions
376#[derive(Debug, Clone, Default)]
377pub struct SelectOptionsBuilder {
378    force: Option<bool>,
379    timeout: Option<f64>,
380}
381
382impl SelectOptionsBuilder {
383    /// Bypass actionability checks
384    pub fn force(mut self, force: bool) -> Self {
385        self.force = Some(force);
386        self
387    }
388
389    /// Set timeout in milliseconds
390    pub fn timeout(mut self, timeout: f64) -> Self {
391        self.timeout = Some(timeout);
392        self
393    }
394
395    /// Build the SelectOptions
396    pub fn build(self) -> SelectOptions {
397        SelectOptions {
398            force: self.force,
399            timeout: self.timeout,
400        }
401    }
402}
403
404/// Keyboard options
405///
406/// Configuration options for keyboard.press() and keyboard.type_text() methods.
407///
408/// See: <https://playwright.dev/docs/api/class-keyboard#keyboard-press>
409#[derive(Debug, Clone, Default, serde::Serialize)]
410#[serde(rename_all = "camelCase")]
411#[non_exhaustive]
412pub struct KeyboardOptions {
413    /// Time to wait between key presses in milliseconds
414    #[serde(skip_serializing_if = "Option::is_none")]
415    pub delay: Option<f64>,
416}
417
418impl KeyboardOptions {
419    /// Create a new builder for KeyboardOptions
420    pub fn builder() -> KeyboardOptionsBuilder {
421        KeyboardOptionsBuilder::default()
422    }
423
424    /// Convert options to JSON value for protocol
425    pub(crate) fn to_json(&self) -> serde_json::Value {
426        serde_json::to_value(self).expect("KeyboardOptions serialization cannot fail")
427    }
428}
429
430/// Builder for KeyboardOptions
431#[derive(Debug, Clone, Default)]
432pub struct KeyboardOptionsBuilder {
433    delay: Option<f64>,
434}
435
436impl KeyboardOptionsBuilder {
437    /// Set delay between key presses in milliseconds
438    pub fn delay(mut self, delay: f64) -> Self {
439        self.delay = Some(delay);
440        self
441    }
442
443    /// Build the KeyboardOptions
444    pub fn build(self) -> KeyboardOptions {
445        KeyboardOptions { delay: self.delay }
446    }
447}
448
449/// Mouse options
450///
451/// Configuration options for mouse methods.
452///
453/// See: <https://playwright.dev/docs/api/class-mouse>
454#[derive(Debug, Clone, Default, serde::Serialize)]
455#[serde(rename_all = "camelCase")]
456#[non_exhaustive]
457pub struct MouseOptions {
458    /// Mouse button to use
459    #[serde(skip_serializing_if = "Option::is_none")]
460    pub button: Option<super::click::MouseButton>,
461    /// Number of clicks
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub click_count: Option<u32>,
464    /// Time to wait between mousedown and mouseup in milliseconds
465    #[serde(skip_serializing_if = "Option::is_none")]
466    pub delay: Option<f64>,
467    /// Number of intermediate mousemove events (for move operations)
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub steps: Option<u32>,
470}
471
472impl MouseOptions {
473    /// Create a new builder for MouseOptions
474    pub fn builder() -> MouseOptionsBuilder {
475        MouseOptionsBuilder::default()
476    }
477
478    /// Convert options to JSON value for protocol
479    pub(crate) fn to_json(&self) -> serde_json::Value {
480        serde_json::to_value(self).expect("MouseOptions serialization cannot fail")
481    }
482}
483
484/// Builder for MouseOptions
485#[derive(Debug, Clone, Default)]
486pub struct MouseOptionsBuilder {
487    button: Option<super::click::MouseButton>,
488    click_count: Option<u32>,
489    delay: Option<f64>,
490    steps: Option<u32>,
491}
492
493impl MouseOptionsBuilder {
494    /// Set the mouse button
495    pub fn button(mut self, button: super::click::MouseButton) -> Self {
496        self.button = Some(button);
497        self
498    }
499
500    /// Set the number of clicks
501    pub fn click_count(mut self, click_count: u32) -> Self {
502        self.click_count = Some(click_count);
503        self
504    }
505
506    /// Set delay between mousedown and mouseup in milliseconds
507    pub fn delay(mut self, delay: f64) -> Self {
508        self.delay = Some(delay);
509        self
510    }
511
512    /// Set number of intermediate mousemove events
513    pub fn steps(mut self, steps: u32) -> Self {
514        self.steps = Some(steps);
515        self
516    }
517
518    /// Build the MouseOptions
519    pub fn build(self) -> MouseOptions {
520        MouseOptions {
521            button: self.button,
522            click_count: self.click_count,
523            delay: self.delay,
524            steps: self.steps,
525        }
526    }
527}
528
529#[cfg(test)]
530mod tests {
531    use super::*;
532    use crate::protocol::click::MouseButton;
533
534    #[test]
535    fn test_fill_options_builder() {
536        let options = FillOptions::builder().force(true).timeout(5000.0).build();
537
538        let json = options.to_json();
539        assert_eq!(json["force"], true);
540        assert_eq!(json["timeout"], 5000.0);
541    }
542
543    #[test]
544    fn test_press_options_builder() {
545        let options = PressOptions::builder().delay(100.0).timeout(3000.0).build();
546
547        let json = options.to_json();
548        assert_eq!(json["delay"], 100.0);
549        assert_eq!(json["timeout"], 3000.0);
550    }
551
552    #[test]
553    fn test_check_options_builder() {
554        let options = CheckOptions::builder()
555            .force(true)
556            .position(Position { x: 5.0, y: 10.0 })
557            .timeout(2000.0)
558            .trial(true)
559            .build();
560
561        let json = options.to_json();
562        assert_eq!(json["force"], true);
563        assert_eq!(json["position"]["x"], 5.0);
564        assert_eq!(json["position"]["y"], 10.0);
565        assert_eq!(json["timeout"], 2000.0);
566        assert_eq!(json["trial"], true);
567    }
568
569    #[test]
570    fn test_hover_options_builder() {
571        let options = HoverOptions::builder()
572            .force(true)
573            .modifiers(vec![KeyboardModifier::Shift])
574            .position(Position { x: 10.0, y: 20.0 })
575            .timeout(4000.0)
576            .trial(false)
577            .build();
578
579        let json = options.to_json();
580        assert_eq!(json["force"], true);
581        assert_eq!(json["modifiers"], serde_json::json!(["Shift"]));
582        assert_eq!(json["position"]["x"], 10.0);
583        assert_eq!(json["position"]["y"], 20.0);
584        assert_eq!(json["timeout"], 4000.0);
585        assert_eq!(json["trial"], false);
586    }
587
588    #[test]
589    fn test_select_options_builder() {
590        let options = SelectOptions::builder().force(true).timeout(6000.0).build();
591
592        let json = options.to_json();
593        assert_eq!(json["force"], true);
594        assert_eq!(json["timeout"], 6000.0);
595    }
596
597    #[test]
598    fn test_keyboard_options_builder() {
599        let options = KeyboardOptions::builder().delay(50.0).build();
600
601        let json = options.to_json();
602        assert_eq!(json["delay"], 50.0);
603    }
604
605    #[test]
606    fn test_mouse_options_builder() {
607        let options = MouseOptions::builder()
608            .button(MouseButton::Right)
609            .click_count(2)
610            .delay(100.0)
611            .steps(10)
612            .build();
613
614        let json = options.to_json();
615        assert_eq!(json["button"], "right");
616        assert_eq!(json["clickCount"], 2);
617        assert_eq!(json["delay"], 100.0);
618        assert_eq!(json["steps"], 10);
619    }
620}