playwright_core/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/// Select options
346///
347/// Configuration options for select_option() action.
348///
349/// See: <https://playwright.dev/docs/api/class-locator#locator-select-option>
350#[derive(Debug, Clone, Default)]
351pub struct SelectOptions {
352    /// Whether to bypass actionability checks
353    pub force: Option<bool>,
354    /// Maximum time in milliseconds
355    pub timeout: Option<f64>,
356}
357
358impl SelectOptions {
359    /// Create a new builder for SelectOptions
360    pub fn builder() -> SelectOptionsBuilder {
361        SelectOptionsBuilder::default()
362    }
363
364    /// Convert options to JSON value for protocol
365    pub(crate) fn to_json(&self) -> serde_json::Value {
366        let mut json = serde_json::json!({});
367
368        if let Some(force) = self.force {
369            json["force"] = serde_json::json!(force);
370        }
371
372        // Timeout is required in Playwright 1.56.1+
373        if let Some(timeout) = self.timeout {
374            json["timeout"] = serde_json::json!(timeout);
375        } else {
376            json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
377        }
378
379        json
380    }
381}
382
383/// Builder for SelectOptions
384#[derive(Debug, Clone, Default)]
385pub struct SelectOptionsBuilder {
386    force: Option<bool>,
387    timeout: Option<f64>,
388}
389
390impl SelectOptionsBuilder {
391    /// Bypass actionability checks
392    pub fn force(mut self, force: bool) -> Self {
393        self.force = Some(force);
394        self
395    }
396
397    /// Set timeout in milliseconds
398    pub fn timeout(mut self, timeout: f64) -> Self {
399        self.timeout = Some(timeout);
400        self
401    }
402
403    /// Build the SelectOptions
404    pub fn build(self) -> SelectOptions {
405        SelectOptions {
406            force: self.force,
407            timeout: self.timeout,
408        }
409    }
410}
411
412/// Keyboard options
413///
414/// Configuration options for keyboard.press() and keyboard.type_text() methods.
415///
416/// See: <https://playwright.dev/docs/api/class-keyboard#keyboard-press>
417#[derive(Debug, Clone, Default)]
418pub struct KeyboardOptions {
419    /// Time to wait between key presses in milliseconds
420    pub delay: Option<f64>,
421}
422
423impl KeyboardOptions {
424    /// Create a new builder for KeyboardOptions
425    pub fn builder() -> KeyboardOptionsBuilder {
426        KeyboardOptionsBuilder::default()
427    }
428
429    /// Convert options to JSON value for protocol
430    pub(crate) fn to_json(&self) -> serde_json::Value {
431        let mut json = serde_json::json!({});
432
433        if let Some(delay) = self.delay {
434            json["delay"] = serde_json::json!(delay);
435        }
436
437        json
438    }
439}
440
441/// Builder for KeyboardOptions
442#[derive(Debug, Clone, Default)]
443pub struct KeyboardOptionsBuilder {
444    delay: Option<f64>,
445}
446
447impl KeyboardOptionsBuilder {
448    /// Set delay between key presses in milliseconds
449    pub fn delay(mut self, delay: f64) -> Self {
450        self.delay = Some(delay);
451        self
452    }
453
454    /// Build the KeyboardOptions
455    pub fn build(self) -> KeyboardOptions {
456        KeyboardOptions { delay: self.delay }
457    }
458}
459
460/// Mouse options
461///
462/// Configuration options for mouse methods.
463///
464/// See: <https://playwright.dev/docs/api/class-mouse>
465#[derive(Debug, Clone, Default)]
466pub struct MouseOptions {
467    /// Mouse button to use
468    pub button: Option<super::click::MouseButton>,
469    /// Number of clicks
470    pub click_count: Option<u32>,
471    /// Time to wait between mousedown and mouseup in milliseconds
472    pub delay: Option<f64>,
473    /// Number of intermediate mousemove events (for move operations)
474    pub steps: Option<u32>,
475}
476
477impl MouseOptions {
478    /// Create a new builder for MouseOptions
479    pub fn builder() -> MouseOptionsBuilder {
480        MouseOptionsBuilder::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(button) = &self.button {
488            json["button"] = serde_json::to_value(button).unwrap();
489        }
490
491        if let Some(click_count) = self.click_count {
492            json["clickCount"] = serde_json::json!(click_count);
493        }
494
495        if let Some(delay) = self.delay {
496            json["delay"] = serde_json::json!(delay);
497        }
498
499        if let Some(steps) = self.steps {
500            json["steps"] = serde_json::json!(steps);
501        }
502
503        json
504    }
505}
506
507/// Builder for MouseOptions
508#[derive(Debug, Clone, Default)]
509pub struct MouseOptionsBuilder {
510    button: Option<super::click::MouseButton>,
511    click_count: Option<u32>,
512    delay: Option<f64>,
513    steps: Option<u32>,
514}
515
516impl MouseOptionsBuilder {
517    /// Set the mouse button
518    pub fn button(mut self, button: super::click::MouseButton) -> Self {
519        self.button = Some(button);
520        self
521    }
522
523    /// Set the number of clicks
524    pub fn click_count(mut self, click_count: u32) -> Self {
525        self.click_count = Some(click_count);
526        self
527    }
528
529    /// Set delay between mousedown and mouseup in milliseconds
530    pub fn delay(mut self, delay: f64) -> Self {
531        self.delay = Some(delay);
532        self
533    }
534
535    /// Set number of intermediate mousemove events
536    pub fn steps(mut self, steps: u32) -> Self {
537        self.steps = Some(steps);
538        self
539    }
540
541    /// Build the MouseOptions
542    pub fn build(self) -> MouseOptions {
543        MouseOptions {
544            button: self.button,
545            click_count: self.click_count,
546            delay: self.delay,
547            steps: self.steps,
548        }
549    }
550}
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555    use crate::protocol::click::MouseButton;
556
557    #[test]
558    fn test_fill_options_builder() {
559        let options = FillOptions::builder().force(true).timeout(5000.0).build();
560
561        let json = options.to_json();
562        assert_eq!(json["force"], true);
563        assert_eq!(json["timeout"], 5000.0);
564    }
565
566    #[test]
567    fn test_press_options_builder() {
568        let options = PressOptions::builder().delay(100.0).timeout(3000.0).build();
569
570        let json = options.to_json();
571        assert_eq!(json["delay"], 100.0);
572        assert_eq!(json["timeout"], 3000.0);
573    }
574
575    #[test]
576    fn test_check_options_builder() {
577        let options = CheckOptions::builder()
578            .force(true)
579            .position(Position { x: 5.0, y: 10.0 })
580            .timeout(2000.0)
581            .trial(true)
582            .build();
583
584        let json = options.to_json();
585        assert_eq!(json["force"], true);
586        assert_eq!(json["position"]["x"], 5.0);
587        assert_eq!(json["position"]["y"], 10.0);
588        assert_eq!(json["timeout"], 2000.0);
589        assert_eq!(json["trial"], true);
590    }
591
592    #[test]
593    fn test_hover_options_builder() {
594        let options = HoverOptions::builder()
595            .force(true)
596            .modifiers(vec![KeyboardModifier::Shift])
597            .position(Position { x: 10.0, y: 20.0 })
598            .timeout(4000.0)
599            .trial(false)
600            .build();
601
602        let json = options.to_json();
603        assert_eq!(json["force"], true);
604        assert_eq!(json["modifiers"], serde_json::json!(["Shift"]));
605        assert_eq!(json["position"]["x"], 10.0);
606        assert_eq!(json["position"]["y"], 20.0);
607        assert_eq!(json["timeout"], 4000.0);
608        assert_eq!(json["trial"], false);
609    }
610
611    #[test]
612    fn test_select_options_builder() {
613        let options = SelectOptions::builder().force(true).timeout(6000.0).build();
614
615        let json = options.to_json();
616        assert_eq!(json["force"], true);
617        assert_eq!(json["timeout"], 6000.0);
618    }
619
620    #[test]
621    fn test_keyboard_options_builder() {
622        let options = KeyboardOptions::builder().delay(50.0).build();
623
624        let json = options.to_json();
625        assert_eq!(json["delay"], 50.0);
626    }
627
628    #[test]
629    fn test_mouse_options_builder() {
630        let options = MouseOptions::builder()
631            .button(MouseButton::Right)
632            .click_count(2)
633            .delay(100.0)
634            .steps(10)
635            .build();
636
637        let json = options.to_json();
638        assert_eq!(json["button"], "right");
639        assert_eq!(json["clickCount"], 2);
640        assert_eq!(json["delay"], 100.0);
641        assert_eq!(json["steps"], 10);
642    }
643}