viewpoint_core/browser/
context_builder.rs

1//! Browser context builder for creating contexts with custom configuration.
2
3use std::time::Duration;
4
5use crate::context::{
6    ColorScheme, ContextOptionsBuilder, ForcedColors, Permission, ReducedMotion, StorageState,
7};
8use crate::devices::DeviceDescriptor;
9use crate::error::BrowserError;
10use crate::page::VideoOptions;
11use crate::BrowserContext;
12
13use super::Browser;
14
15/// Builder for creating a new browser context with options.
16#[derive(Debug)]
17pub struct NewContextBuilder<'a> {
18    browser: &'a Browser,
19    builder: ContextOptionsBuilder,
20}
21
22impl<'a> NewContextBuilder<'a> {
23    pub(super) fn new(browser: &'a Browser) -> Self {
24        Self {
25            browser,
26            builder: ContextOptionsBuilder::new(),
27        }
28    }
29
30    /// Set storage state from a file path.
31    #[must_use]
32    pub fn storage_state_path(mut self, path: impl Into<std::path::PathBuf>) -> Self {
33        self.builder = self.builder.storage_state_path(path);
34        self
35    }
36
37    /// Set storage state from an object.
38    #[must_use]
39    pub fn storage_state(mut self, state: StorageState) -> Self {
40        self.builder = self.builder.storage_state(state);
41        self
42    }
43
44    /// Set geolocation.
45    #[must_use]
46    pub fn geolocation(mut self, latitude: f64, longitude: f64) -> Self {
47        self.builder = self.builder.geolocation(latitude, longitude);
48        self
49    }
50
51    /// Set geolocation with accuracy.
52    #[must_use]
53    pub fn geolocation_with_accuracy(
54        mut self,
55        latitude: f64,
56        longitude: f64,
57        accuracy: f64,
58    ) -> Self {
59        self.builder = self
60            .builder
61            .geolocation_with_accuracy(latitude, longitude, accuracy);
62        self
63    }
64
65    /// Grant permissions.
66    #[must_use]
67    pub fn permissions(mut self, permissions: Vec<Permission>) -> Self {
68        self.builder = self.builder.permissions(permissions);
69        self
70    }
71
72    /// Set HTTP credentials.
73    #[must_use]
74    pub fn http_credentials(
75        mut self,
76        username: impl Into<String>,
77        password: impl Into<String>,
78    ) -> Self {
79        self.builder = self.builder.http_credentials(username, password);
80        self
81    }
82
83    /// Set extra HTTP headers.
84    #[must_use]
85    pub fn extra_http_headers(
86        mut self,
87        headers: std::collections::HashMap<String, String>,
88    ) -> Self {
89        self.builder = self.builder.extra_http_headers(headers);
90        self
91    }
92
93    /// Add an extra HTTP header.
94    #[must_use]
95    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
96        self.builder = self.builder.header(name, value);
97        self
98    }
99
100    /// Set offline mode.
101    #[must_use]
102    pub fn offline(mut self, offline: bool) -> Self {
103        self.builder = self.builder.offline(offline);
104        self
105    }
106
107    /// Set default timeout.
108    #[must_use]
109    pub fn default_timeout(mut self, timeout: Duration) -> Self {
110        self.builder = self.builder.default_timeout(timeout);
111        self
112    }
113
114    /// Set default navigation timeout.
115    #[must_use]
116    pub fn default_navigation_timeout(mut self, timeout: Duration) -> Self {
117        self.builder = self.builder.default_navigation_timeout(timeout);
118        self
119    }
120
121    /// Enable touch emulation.
122    #[must_use]
123    pub fn has_touch(mut self, has_touch: bool) -> Self {
124        self.builder = self.builder.has_touch(has_touch);
125        self
126    }
127
128    /// Set locale.
129    #[must_use]
130    pub fn locale(mut self, locale: impl Into<String>) -> Self {
131        self.builder = self.builder.locale(locale);
132        self
133    }
134
135    /// Set timezone.
136    #[must_use]
137    pub fn timezone_id(mut self, timezone_id: impl Into<String>) -> Self {
138        self.builder = self.builder.timezone_id(timezone_id);
139        self
140    }
141
142    /// Set user agent.
143    #[must_use]
144    pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
145        self.builder = self.builder.user_agent(user_agent);
146        self
147    }
148
149    /// Set viewport size.
150    #[must_use]
151    pub fn viewport(mut self, width: i32, height: i32) -> Self {
152        self.builder = self.builder.viewport(width, height);
153        self
154    }
155
156    /// Set color scheme.
157    #[must_use]
158    pub fn color_scheme(mut self, color_scheme: ColorScheme) -> Self {
159        self.builder = self.builder.color_scheme(color_scheme);
160        self
161    }
162
163    /// Set reduced motion preference.
164    #[must_use]
165    pub fn reduced_motion(mut self, reduced_motion: ReducedMotion) -> Self {
166        self.builder = self.builder.reduced_motion(reduced_motion);
167        self
168    }
169
170    /// Set forced colors preference.
171    #[must_use]
172    pub fn forced_colors(mut self, forced_colors: ForcedColors) -> Self {
173        self.builder = self.builder.forced_colors(forced_colors);
174        self
175    }
176
177    /// Set device scale factor (device pixel ratio).
178    #[must_use]
179    pub fn device_scale_factor(mut self, scale_factor: f64) -> Self {
180        self.builder = self.builder.device_scale_factor(scale_factor);
181        self
182    }
183
184    /// Set mobile mode.
185    #[must_use]
186    pub fn is_mobile(mut self, is_mobile: bool) -> Self {
187        self.builder = self.builder.is_mobile(is_mobile);
188        self
189    }
190
191    /// Apply a device descriptor to configure the context.
192    ///
193    /// This sets viewport, user agent, device scale factor, touch, and mobile mode
194    /// based on the device descriptor.
195    ///
196    /// # Example
197    ///
198    /// ```no_run
199    /// use viewpoint_core::{Browser, devices};
200    ///
201    /// # async fn example() -> Result<(), viewpoint_core::CoreError> {
202    /// let browser = Browser::launch().headless(true).launch().await?;
203    ///
204    /// let context = browser.new_context_builder()
205    ///     .device(devices::IPHONE_13)
206    ///     .build()
207    ///     .await?;
208    /// # Ok(())
209    /// # }
210    /// ```
211    #[must_use]
212    pub fn device(mut self, device: DeviceDescriptor) -> Self {
213        self.builder = self.builder.device(device);
214        self
215    }
216
217    /// Enable video recording for pages in this context.
218    ///
219    /// Videos are recorded for each page and saved to the specified directory.
220    ///
221    /// # Example
222    ///
223    /// ```no_run
224    /// use viewpoint_core::{Browser, page::VideoOptions};
225    ///
226    /// # async fn example() -> Result<(), viewpoint_core::CoreError> {
227    /// let browser = Browser::launch().headless(true).launch().await?;
228    /// let context = browser.new_context_builder()
229    ///     .record_video(VideoOptions::new("./videos"))
230    ///     .build()
231    ///     .await?;
232    /// # Ok(())
233    /// # }
234    /// ```
235    #[must_use]
236    pub fn record_video(mut self, options: VideoOptions) -> Self {
237        self.builder = self.builder.record_video(options);
238        self
239    }
240
241    /// Build and create the browser context.
242    ///
243    /// # Errors
244    ///
245    /// Returns an error if context creation fails.
246    pub async fn build(self) -> Result<BrowserContext, BrowserError> {
247        self.browser
248            .new_context_with_options(self.builder.build())
249            .await
250    }
251}