Skip to main content

playwright_cdp/
options.rs

1//! Builder option structs mirroring Playwright's option objects.
2
3use crate::types::{
4    KeyboardModifier, MouseButton, Position, ProxySettings, ScreenshotClip, ScreenshotType,
5    Viewport, DEFAULT_TIMEOUT_MS,
6};
7use std::collections::HashMap;
8use std::time::Duration;
9
10/// Browser launch options. See: <https://playwright.dev/docs/api/class-browsertype#browser-type-launch>
11#[derive(Debug, Clone, Default)]
12#[non_exhaustive]
13pub struct LaunchOptions {
14    pub headless: Option<bool>,
15    pub executable_path: Option<String>,
16    pub channel: Option<String>,
17    pub args: Option<Vec<String>>,
18    pub env: Option<HashMap<String, String>>,
19    pub proxy: Option<ProxySettings>,
20    pub slow_mo: Option<f64>,
21    pub timeout: Option<f64>,
22    pub downloads_path: Option<String>,
23    pub traces_dir: Option<String>,
24    pub devtools: Option<bool>,
25    pub chromium_sandbox: Option<bool>,
26}
27
28impl LaunchOptions {
29    pub fn new() -> Self {
30        Self::default()
31    }
32    pub fn headless(mut self, v: bool) -> Self {
33        self.headless = Some(v);
34        self
35    }
36    pub fn executable_path(mut self, v: impl Into<String>) -> Self {
37        self.executable_path = Some(v.into());
38        self
39    }
40    pub fn channel(mut self, v: impl Into<String>) -> Self {
41        self.channel = Some(v.into());
42        self
43    }
44    pub fn args(mut self, v: Vec<String>) -> Self {
45        self.args = Some(v);
46        self
47    }
48    pub fn proxy(mut self, v: ProxySettings) -> Self {
49        self.proxy = Some(v);
50        self
51    }
52    pub fn timeout_ms(mut self, v: f64) -> Self {
53        self.timeout = Some(v);
54        self
55    }
56    pub fn devtools(mut self, v: bool) -> Self {
57        self.devtools = Some(v);
58        self
59    }
60
61    /// Resolved action/launch timeout in milliseconds.
62    pub fn timeout_ms_or_default(&self) -> f64 {
63        self.timeout.unwrap_or(DEFAULT_TIMEOUT_MS)
64    }
65}
66
67/// Options for `connect_over_cdp`.
68#[derive(Debug, Clone, Default)]
69#[non_exhaustive]
70pub struct ConnectOverCdpOptions {
71    pub headers: Option<HashMap<String, String>>,
72    pub slow_mo: Option<f64>,
73    pub timeout: Option<f64>,
74    pub no_defaults: Option<bool>,
75}
76
77impl ConnectOverCdpOptions {
78    pub fn new() -> Self {
79        Self::default()
80    }
81    pub fn headers(mut self, v: HashMap<String, String>) -> Self {
82        self.headers = Some(v);
83        self
84    }
85    pub fn timeout_ms(mut self, v: f64) -> Self {
86        self.timeout = Some(v);
87        self
88    }
89}
90
91/// When to consider a navigation finished.
92#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
93pub enum WaitUntil {
94    /// Consider navigation complete when the `load` event fires.
95    #[default]
96    Load,
97    /// `DOMContentLoaded`.
98    DomContentLoaded,
99    /// Heuristic: no in-flight network requests for ~500ms after `load`.
100    NetworkIdle,
101    /// Resolved as soon as the navigation is committed.
102    Commit,
103}
104
105impl WaitUntil {
106    pub fn as_str(&self) -> &'static str {
107        match self {
108            WaitUntil::Load => "load",
109            WaitUntil::DomContentLoaded => "DOMContentLoaded",
110            WaitUntil::NetworkIdle => "networkidle",
111            WaitUntil::Commit => "commit",
112        }
113    }
114}
115
116/// Options for navigation methods (`goto`, `reload`, ...).
117#[derive(Debug, Clone, Default)]
118#[non_exhaustive]
119pub struct GotoOptions {
120    pub timeout: Option<Duration>,
121    pub wait_until: Option<WaitUntil>,
122    pub referer: Option<String>,
123}
124
125impl GotoOptions {
126    pub fn new() -> Self {
127        Self::default()
128    }
129    pub fn timeout(mut self, v: Duration) -> Self {
130        self.timeout = Some(v);
131        self
132    }
133    pub fn wait_until(mut self, v: WaitUntil) -> Self {
134        self.wait_until = Some(v);
135        self
136    }
137    pub fn referer(mut self, v: impl Into<String>) -> Self {
138        self.referer = Some(v.into());
139        self
140    }
141    pub fn wait_until_or_default(&self) -> WaitUntil {
142        self.wait_until.unwrap_or_default()
143    }
144}
145
146/// Options for `Locator::click` / `dblclick`.
147#[derive(Debug, Clone, Default)]
148#[non_exhaustive]
149pub struct ClickOptions {
150    pub button: Option<MouseButton>,
151    pub click_count: Option<u32>,
152    pub delay: Option<f64>,
153    pub force: Option<bool>,
154    pub modifiers: Option<Vec<KeyboardModifier>>,
155    pub no_wait_after: Option<bool>,
156    pub position: Option<Position>,
157    pub timeout: Option<f64>,
158    pub trial: Option<bool>,
159}
160
161impl ClickOptions {
162    pub fn new() -> Self {
163        Self::default()
164    }
165    pub fn timeout_ms(mut self, v: f64) -> Self {
166        self.timeout = Some(v);
167        self
168    }
169    pub fn force(mut self, v: bool) -> Self {
170        self.force = Some(v);
171        self
172    }
173}
174
175/// Options for `Locator::fill` / `clear`.
176#[derive(Debug, Clone, Default)]
177#[non_exhaustive]
178pub struct FillOptions {
179    pub force: Option<bool>,
180    pub timeout: Option<f64>,
181}
182
183impl FillOptions {
184    pub fn new() -> Self {
185        Self::default()
186    }
187    pub fn timeout_ms(mut self, v: f64) -> Self {
188        self.timeout = Some(v);
189        self
190    }
191}
192
193/// Options for `Locator::press`.
194#[derive(Debug, Clone, Default)]
195#[non_exhaustive]
196pub struct PressOptions {
197    pub delay: Option<f64>,
198    pub timeout: Option<f64>,
199}
200
201/// Options for `Keyboard::type_` (sequential key presses).
202#[derive(Debug, Clone, Default)]
203#[non_exhaustive]
204pub struct PressSequentiallyOptions {
205    pub delay: Option<f64>,
206    pub timeout: Option<f64>,
207}
208
209/// Options for `Mouse::click` / `dblclick` / `down` / `up` / `move_to`.
210#[derive(Debug, Clone, Default)]
211#[non_exhaustive]
212pub struct MouseOptions {
213    pub button: Option<MouseButton>,
214    pub click_count: Option<u32>,
215    pub delay: Option<f64>,
216}
217
218/// Options for `Locator::hover`.
219#[derive(Debug, Clone, Default)]
220#[non_exhaustive]
221pub struct HoverOptions {
222    pub force: Option<bool>,
223    pub modifiers: Option<Vec<KeyboardModifier>>,
224    pub no_wait_after: Option<bool>,
225    pub position: Option<Position>,
226    pub timeout: Option<f64>,
227    pub trial: Option<bool>,
228}
229
230/// Options for `Locator::wait_for`.
231#[derive(Debug, Clone, Default)]
232#[non_exhaustive]
233pub struct WaitForOptions {
234    pub state: Option<WaitForState>,
235    pub timeout: Option<f64>,
236}
237
238/// Element state to wait for.
239#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
240pub enum WaitForState {
241    #[default]
242    Visible,
243    Hidden,
244    Attached,
245    Detached,
246}
247
248/// Options for `Page::screenshot` / `Locator::screenshot`.
249#[derive(Debug, Clone, Default)]
250#[non_exhaustive]
251pub struct ScreenshotOptions {
252    pub path: Option<String>,
253    pub r#type: Option<ScreenshotType>,
254    pub quality: Option<u8>,
255    pub full_page: Option<bool>,
256    pub clip: Option<ScreenshotClip>,
257    pub omit_background: Option<bool>,
258    pub timeout: Option<f64>,
259}
260
261impl ScreenshotOptions {
262    pub fn new() -> Self {
263        Self::default()
264    }
265    pub fn path(mut self, v: impl Into<String>) -> Self {
266        self.path = Some(v.into());
267        self
268    }
269    pub fn full_page(mut self, v: bool) -> Self {
270        self.full_page = Some(v);
271        self
272    }
273    pub fn r#type(mut self, v: ScreenshotType) -> Self {
274        self.r#type = Some(v);
275        self
276    }
277    pub fn omit_background(mut self, v: bool) -> Self {
278        self.omit_background = Some(v);
279        self
280    }
281}
282
283/// Options for `get_by_role`.
284#[derive(Debug, Clone, Default)]
285#[non_exhaustive]
286pub struct GetByRoleOptions {
287    pub checked: Option<bool>,
288    pub disabled: Option<bool>,
289    pub selected: Option<bool>,
290    pub expanded: Option<bool>,
291    pub include_hidden: Option<bool>,
292    pub level: Option<u32>,
293    pub name: Option<String>,
294    pub description: Option<String>,
295    pub exact: Option<bool>,
296    pub pressed: Option<bool>,
297}
298
299impl GetByRoleOptions {
300    pub fn new() -> Self {
301        Self::default()
302    }
303    pub fn name(mut self, v: impl Into<String>) -> Self {
304        self.name = Some(v.into());
305        self
306    }
307    pub fn exact(mut self, v: bool) -> Self {
308        self.exact = Some(v);
309        self
310    }
311}
312
313/// Whether a new page should be opened with a specific viewport.
314#[derive(Debug, Clone, Default)]
315#[non_exhaustive]
316pub struct NewContextOptions {
317    pub viewport: Option<Viewport>,
318    pub user_agent: Option<String>,
319    pub locale: Option<String>,
320    pub extra_http_headers: Option<HashMap<String, String>>,
321    pub ignore_https_errors: Option<bool>,
322}
323
324/// A selection criterion for `Locator::select_option`.
325#[derive(Debug, Clone)]
326#[non_exhaustive]
327pub enum SelectOption {
328    /// Match by the option's `value` attribute.
329    Value(String),
330    /// Match by the option's visible label text.
331    Label(String),
332    /// Match by index (0-based).
333    Index(u32),
334}
335
336impl SelectOption {
337    pub fn value(v: impl Into<String>) -> Self {
338        Self::Value(v.into())
339    }
340    pub fn label(v: impl Into<String>) -> Self {
341        Self::Label(v.into())
342    }
343}
344
345/// Options for `Locator::check` / `uncheck` / `set_checked`.
346#[derive(Debug, Clone, Default)]
347#[non_exhaustive]
348pub struct CheckOptions {
349    pub force: Option<bool>,
350    pub position: Option<Position>,
351    pub timeout: Option<f64>,
352    pub trial: Option<bool>,
353}
354
355/// Options for `Locator::select_option`.
356#[derive(Debug, Clone, Default)]
357#[non_exhaustive]
358pub struct SelectOptions {
359    pub force: Option<bool>,
360    pub timeout: Option<f64>,
361}
362
363/// Options for `Locator::filter` (minimal).
364#[derive(Debug, Clone, Default)]
365#[non_exhaustive]
366pub struct FilterOptions {
367    pub has_text: Option<String>,
368    pub has_not_text: Option<String>,
369}
370
371/// Emulated media (for `Page::emulate_media`).
372#[derive(Debug, Clone, Default)]
373#[non_exhaustive]
374pub struct EmulateMediaOptions {
375    pub media: Option<Media>,
376    pub color_scheme: Option<ColorScheme>,
377    pub reduced_motion: Option<ReducedMotion>,
378}
379
380/// Emulated `prefers-media` value.
381#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
382pub enum Media {
383    #[default]
384    Screen,
385    Print,
386}
387
388/// Emulated `prefers-color-scheme` value.
389#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
390pub enum ColorScheme {
391    Light,
392    Dark,
393    #[default]
394    NoPreference,
395}
396
397/// Emulated `prefers-reduced-motion` value.
398#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
399pub enum ReducedMotion {
400    #[default]
401    NoPreference,
402    Reduce,
403}
404
405/// Options for `drag_to` / `drag_and_drop` (minimal).
406#[derive(Debug, Clone, Default)]
407#[non_exhaustive]
408pub struct DragToOptions {
409    pub force: Option<bool>,
410    pub timeout: Option<f64>,
411}
412
413/// Options for `Page::pdf` (minimal subset of CDP `Page.printToPDF`).
414#[derive(Debug, Clone, Default)]
415#[non_exhaustive]
416pub struct PdfOptions {
417    pub format: Option<PaperFormat>,
418    pub landscape: Option<bool>,
419    pub print_background: Option<bool>,
420    pub scale: Option<f64>,
421    pub margin: Option<PdfMargin>,
422    pub prefer_css_page_size: Option<bool>,
423}
424
425impl PdfOptions {
426    pub fn new() -> Self {
427        Self::default()
428    }
429    pub fn format(mut self, v: PaperFormat) -> Self {
430        self.format = Some(v);
431        self
432    }
433    pub fn landscape(mut self, v: bool) -> Self {
434        self.landscape = Some(v);
435        self
436    }
437}
438
439/// Standard paper sizes.
440#[derive(Debug, Clone, Copy, PartialEq)]
441pub enum PaperFormat {
442    Letter,
443    Legal,
444    Tabloid,
445    Ledger,
446    A0,
447    A1,
448    A2,
449    A3,
450    A4,
451    A5,
452    A6,
453}
454
455impl PaperFormat {
456    /// `(width, height)` in inches.
457    pub fn inches(self) -> (f64, f64) {
458        match self {
459            PaperFormat::Letter => (8.5, 11.0),
460            PaperFormat::Legal => (8.5, 14.0),
461            PaperFormat::Tabloid => (11.0, 17.0),
462            PaperFormat::Ledger => (17.0, 11.0),
463            PaperFormat::A0 => (33.1, 46.8),
464            PaperFormat::A1 => (23.4, 33.1),
465            PaperFormat::A2 => (16.54, 23.4),
466            PaperFormat::A3 => (11.7, 16.54),
467            PaperFormat::A4 => (8.27, 11.69),
468            PaperFormat::A5 => (5.83, 8.27),
469            PaperFormat::A6 => (4.13, 5.83),
470        }
471    }
472}
473
474/// PDF page margins in inches.
475#[derive(Debug, Clone, Copy, Default)]
476#[non_exhaustive]
477pub struct PdfMargin {
478    pub top: Option<f64>,
479    pub bottom: Option<f64>,
480    pub left: Option<f64>,
481    pub right: Option<f64>,
482}
483
484/// Options for [`Tracing::start`](crate::Tracing::start).
485///
486/// Minimal subset of Playwright's `tracing.start()` options. Captures a Chrome
487/// performance trace via the CDP `Tracing` domain (browser-level).
488#[derive(Debug, Clone, Default)]
489#[non_exhaustive]
490pub struct TracingStartOptions {
491    /// Trace categories to enable (CDP `Tracing.start` `categories`). If
492    /// omitted, Chrome's defaults are used.
493    pub categories: Option<Vec<String>>,
494    /// Where to write the trace JSON file once [`Tracing::stop`] is called.
495    pub path: Option<String>,
496    /// When true, captures screenshots (adds the
497    /// `disabled-by-default-devtools.screenshot` category).
498    pub screenshots: Option<bool>,
499}
500
501impl TracingStartOptions {
502    pub fn new() -> Self {
503        Self::default()
504    }
505    pub fn categories(mut self, v: Vec<String>) -> Self {
506        self.categories = Some(v);
507        self
508    }
509    pub fn path(mut self, v: impl Into<String>) -> Self {
510        self.path = Some(v.into());
511        self
512    }
513    pub fn screenshots(mut self, v: bool) -> Self {
514        self.screenshots = Some(v);
515        self
516    }
517}
518
519/// Options for `Page::wait_for_function` / `Frame::wait_for_function`.
520///
521/// Polls `expression` until it yields a truthy value (or `timeout` elapses).
522/// See: <https://playwright.dev/docs/api/class-page#page-wait-for-function>
523#[derive(Debug, Clone, Default)]
524#[non_exhaustive]
525pub struct WaitForFunctionOptions {
526    /// Maximum time to wait, in milliseconds. Defaults to the page's default
527    /// timeout (30s) when `None`.
528    pub timeout: Option<f64>,
529    /// Time to wait between evaluations, in milliseconds. Defaults to 100ms.
530    pub polling_interval: Option<f64>,
531}
532
533impl WaitForFunctionOptions {
534    pub fn new() -> Self {
535        Self::default()
536    }
537    /// Set the maximum wait time in milliseconds.
538    pub fn timeout_ms(mut self, v: f64) -> Self {
539        self.timeout = Some(v);
540        self
541    }
542    /// Set the time between polls in milliseconds (default 100).
543    pub fn polling_interval_ms(mut self, v: f64) -> Self {
544        self.polling_interval = Some(v);
545        self
546    }
547}
548
549/// Options for [`crate::APIRequestContext`] requests.
550///
551/// Mirrors the relevant subset of Playwright's API request options. `data`
552/// (JSON body) and `form` (URL-encoded form) are mutually exclusive; if both
553/// are set, `data` wins.
554///
555/// See: <https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-get>
556#[derive(Debug, Clone, Default)]
557#[non_exhaustive]
558pub struct APIRequestOptions {
559    /// Per-request headers (merged on top of the context's default headers).
560    pub headers: Option<HashMap<String, String>>,
561    /// URL query parameters.
562    pub params: Option<Vec<(String, String)>>,
563    /// JSON request body. Sent as `application/json`.
564    pub data: Option<serde_json::Value>,
565    /// URL-encoded form body. Sent as `application/x-www-form-urlencoded`.
566    pub form: Option<HashMap<String, String>>,
567    /// Per-request timeout, in milliseconds.
568    pub timeout: Option<f64>,
569}
570
571impl APIRequestOptions {
572    pub fn new() -> Self {
573        Self::default()
574    }
575
576    /// Set the per-request headers (replaces any previously set headers).
577    pub fn headers(mut self, v: HashMap<String, String>) -> Self {
578        self.headers = Some(v);
579        self
580    }
581
582    /// Add a single header.
583    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
584        self.headers
585            .get_or_insert_with(HashMap::new)
586            .insert(name.into(), value.into());
587        self
588    }
589
590    /// Set the JSON body.
591    pub fn data(mut self, v: serde_json::Value) -> Self {
592        self.data = Some(v);
593        self
594    }
595
596    /// Set the URL-encoded form body.
597    pub fn form(mut self, v: HashMap<String, String>) -> Self {
598        self.form = Some(v);
599        self
600    }
601
602    /// Set the URL query parameters.
603    pub fn params(mut self, v: Vec<(String, String)>) -> Self {
604        self.params = Some(v);
605        self
606    }
607
608    /// Set the per-request timeout in milliseconds.
609    pub fn timeout_ms(mut self, v: f64) -> Self {
610        self.timeout = Some(v);
611        self
612    }
613}