Skip to main content

playwright_rs/protocol/
screenshot.rs

1// Screenshot types and options
2//
3// Provides configuration for page and element screenshots, matching Playwright's API.
4
5use serde::Serialize;
6
7/// Screenshot image format
8///
9/// # Example
10///
11/// ```ignore
12/// use playwright_rs::protocol::ScreenshotType;
13///
14/// let screenshot_type = ScreenshotType::Jpeg;
15/// ```
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
17#[serde(rename_all = "lowercase")]
18pub enum ScreenshotType {
19    /// PNG format (lossless, supports transparency)
20    Png,
21    /// JPEG format (lossy compression, smaller file size)
22    Jpeg,
23}
24
25/// Clip region for screenshot
26///
27/// Specifies a rectangular region to capture.
28///
29/// # Example
30///
31/// ```ignore
32/// use playwright_rs::protocol::ScreenshotClip;
33///
34/// let clip = ScreenshotClip {
35///     x: 10.0,
36///     y: 20.0,
37///     width: 300.0,
38///     height: 200.0,
39/// };
40/// ```
41#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
42pub struct ScreenshotClip {
43    /// X coordinate of clip region origin
44    pub x: f64,
45    /// Y coordinate of clip region origin
46    pub y: f64,
47    /// Width of clip region
48    pub width: f64,
49    /// Height of clip region
50    pub height: f64,
51}
52
53/// Screenshot options
54///
55/// Configuration options for page and element screenshots.
56///
57/// Use the builder pattern to construct options:
58///
59/// # Example
60///
61/// ```ignore
62/// use playwright_rs::protocol::{ScreenshotOptions, ScreenshotType, ScreenshotClip};
63///
64/// // JPEG with quality
65/// let options = ScreenshotOptions::builder()
66///     .screenshot_type(ScreenshotType::Jpeg)
67///     .quality(80)
68///     .build();
69///
70/// // Full page screenshot
71/// let options = ScreenshotOptions::builder()
72///     .full_page(true)
73///     .build();
74///
75/// // Clip region
76/// let clip = ScreenshotClip {
77///     x: 10.0,
78///     y: 10.0,
79///     width: 200.0,
80///     height: 100.0,
81/// };
82/// let options = ScreenshotOptions::builder()
83///     .clip(clip)
84///     .build();
85/// ```
86///
87/// See: <https://playwright.dev/docs/api/class-page#page-screenshot>
88#[derive(Debug, Clone, Default)]
89pub struct ScreenshotOptions {
90    /// Image format (png or jpeg)
91    pub screenshot_type: Option<ScreenshotType>,
92    /// JPEG quality (0-100), only applies to jpeg format
93    pub quality: Option<u8>,
94    /// Capture full scrollable page
95    pub full_page: Option<bool>,
96    /// Clip region to capture
97    pub clip: Option<ScreenshotClip>,
98    /// Hide default white background (PNG only)
99    pub omit_background: Option<bool>,
100    /// Screenshot timeout in milliseconds
101    pub timeout: Option<f64>,
102}
103
104impl ScreenshotOptions {
105    /// Create a new builder for ScreenshotOptions
106    pub fn builder() -> ScreenshotOptionsBuilder {
107        ScreenshotOptionsBuilder::default()
108    }
109
110    /// Convert options to JSON value for protocol
111    pub(crate) fn to_json(&self) -> serde_json::Value {
112        let mut json = serde_json::json!({});
113
114        if let Some(screenshot_type) = &self.screenshot_type {
115            json["type"] = serde_json::to_value(screenshot_type)
116                .expect("serialization of ScreenshotType cannot fail");
117        }
118
119        if let Some(quality) = self.quality {
120            json["quality"] = serde_json::json!(quality);
121        }
122
123        if let Some(full_page) = self.full_page {
124            json["fullPage"] = serde_json::json!(full_page);
125        }
126
127        if let Some(clip) = &self.clip {
128            json["clip"] = serde_json::to_value(clip).expect("serialization of clip cannot fail");
129        }
130
131        if let Some(omit_background) = self.omit_background {
132            json["omitBackground"] = serde_json::json!(omit_background);
133        }
134
135        // Timeout is required in Playwright 1.56.1+
136        if let Some(timeout) = self.timeout {
137            json["timeout"] = serde_json::json!(timeout);
138        } else {
139            json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
140        }
141
142        json
143    }
144}
145
146/// Builder for ScreenshotOptions
147///
148/// Provides a fluent API for constructing screenshot options.
149#[derive(Debug, Clone, Default)]
150pub struct ScreenshotOptionsBuilder {
151    screenshot_type: Option<ScreenshotType>,
152    quality: Option<u8>,
153    full_page: Option<bool>,
154    clip: Option<ScreenshotClip>,
155    omit_background: Option<bool>,
156    timeout: Option<f64>,
157}
158
159impl ScreenshotOptionsBuilder {
160    /// Set the screenshot format (png or jpeg)
161    pub fn screenshot_type(mut self, screenshot_type: ScreenshotType) -> Self {
162        self.screenshot_type = Some(screenshot_type);
163        self
164    }
165
166    /// Set JPEG quality (0-100)
167    ///
168    /// Only applies when screenshot_type is Jpeg.
169    pub fn quality(mut self, quality: u8) -> Self {
170        self.quality = Some(quality);
171        self
172    }
173
174    /// Capture full scrollable page beyond viewport
175    pub fn full_page(mut self, full_page: bool) -> Self {
176        self.full_page = Some(full_page);
177        self
178    }
179
180    /// Set clip region to capture
181    pub fn clip(mut self, clip: ScreenshotClip) -> Self {
182        self.clip = Some(clip);
183        self
184    }
185
186    /// Hide default white background (creates transparent PNG)
187    pub fn omit_background(mut self, omit_background: bool) -> Self {
188        self.omit_background = Some(omit_background);
189        self
190    }
191
192    /// Set screenshot timeout in milliseconds
193    pub fn timeout(mut self, timeout: f64) -> Self {
194        self.timeout = Some(timeout);
195        self
196    }
197
198    /// Build the ScreenshotOptions
199    pub fn build(self) -> ScreenshotOptions {
200        ScreenshotOptions {
201            screenshot_type: self.screenshot_type,
202            quality: self.quality,
203            full_page: self.full_page,
204            clip: self.clip,
205            omit_background: self.omit_background,
206            timeout: self.timeout,
207        }
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use super::*;
214
215    #[test]
216    fn test_screenshot_type_serialization() {
217        assert_eq!(
218            serde_json::to_string(&ScreenshotType::Png).unwrap(),
219            "\"png\""
220        );
221        assert_eq!(
222            serde_json::to_string(&ScreenshotType::Jpeg).unwrap(),
223            "\"jpeg\""
224        );
225    }
226
227    #[test]
228    fn test_builder_jpeg_with_quality() {
229        let options = ScreenshotOptions::builder()
230            .screenshot_type(ScreenshotType::Jpeg)
231            .quality(80)
232            .build();
233
234        let json = options.to_json();
235        assert_eq!(json["type"], "jpeg");
236        assert_eq!(json["quality"], 80);
237    }
238
239    #[test]
240    fn test_builder_full_page() {
241        let options = ScreenshotOptions::builder().full_page(true).build();
242
243        let json = options.to_json();
244        assert_eq!(json["fullPage"], true);
245    }
246
247    #[test]
248    fn test_builder_clip() {
249        let clip = ScreenshotClip {
250            x: 10.0,
251            y: 20.0,
252            width: 300.0,
253            height: 200.0,
254        };
255        let options = ScreenshotOptions::builder().clip(clip).build();
256
257        let json = options.to_json();
258        assert_eq!(json["clip"]["x"], 10.0);
259        assert_eq!(json["clip"]["y"], 20.0);
260        assert_eq!(json["clip"]["width"], 300.0);
261        assert_eq!(json["clip"]["height"], 200.0);
262    }
263
264    #[test]
265    fn test_builder_omit_background() {
266        let options = ScreenshotOptions::builder().omit_background(true).build();
267
268        let json = options.to_json();
269        assert_eq!(json["omitBackground"], true);
270    }
271
272    #[test]
273    fn test_builder_multiple_options() {
274        let options = ScreenshotOptions::builder()
275            .screenshot_type(ScreenshotType::Jpeg)
276            .quality(90)
277            .full_page(true)
278            .timeout(5000.0)
279            .build();
280
281        let json = options.to_json();
282        assert_eq!(json["type"], "jpeg");
283        assert_eq!(json["quality"], 90);
284        assert_eq!(json["fullPage"], true);
285        assert_eq!(json["timeout"], 5000.0);
286    }
287}