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