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