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