firefox_webdriver/driver/
options.rs1#[derive(Debug, Clone, Default, PartialEq, Eq)]
29pub struct FirefoxOptions {
30 pub headless: bool,
32
33 pub window_size: Option<(u32, u32)>,
35
36 pub kiosk: bool,
38
39 pub devtools: bool,
41
42 pub private: bool,
44
45 pub extra_args: Vec<String>,
47}
48
49impl FirefoxOptions {
54 #[inline]
56 #[must_use]
57 pub const fn new() -> Self {
58 Self {
59 headless: false,
60 window_size: None,
61 kiosk: false,
62 devtools: false,
63 private: false,
64 extra_args: Vec::new(),
65 }
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn headless() -> Self {
72 Self {
73 headless: true,
74 ..Default::default()
75 }
76 }
77}
78
79impl FirefoxOptions {
84 #[inline]
86 #[must_use]
87 pub fn with_headless(mut self) -> Self {
88 self.headless = true;
89 self
90 }
91
92 #[inline]
94 #[must_use]
95 pub fn with_window_size(mut self, width: u32, height: u32) -> Self {
96 self.window_size = Some((width, height));
97 self
98 }
99
100 #[inline]
102 #[must_use]
103 pub fn with_kiosk(mut self) -> Self {
104 self.kiosk = true;
105 self
106 }
107
108 #[inline]
110 #[must_use]
111 pub fn with_devtools(mut self) -> Self {
112 self.devtools = true;
113 self
114 }
115
116 #[inline]
118 #[must_use]
119 pub fn with_private(mut self) -> Self {
120 self.private = true;
121 self
122 }
123
124 #[inline]
126 #[must_use]
127 pub fn with_arg(mut self, arg: impl Into<String>) -> Self {
128 self.extra_args.push(arg.into());
129 self
130 }
131
132 #[inline]
134 #[must_use]
135 pub fn with_args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
136 self.extra_args.extend(args.into_iter().map(Into::into));
137 self
138 }
139}
140
141impl FirefoxOptions {
146 #[must_use]
148 pub fn to_args(&self) -> Vec<String> {
149 let mut args = Vec::with_capacity(8 + self.extra_args.len());
150
151 if self.headless {
152 args.push("--headless".to_string());
153 }
154
155 if let Some((width, height)) = self.window_size {
156 args.push("--window-size".to_string());
157 args.push(format!("{width},{height}"));
158 }
159
160 if self.kiosk {
161 args.push("--kiosk".to_string());
162 }
163
164 if self.devtools {
165 args.push("--devtools".to_string());
166 }
167
168 if self.private {
169 args.push("--private-window".to_string());
170 }
171
172 args.extend(self.extra_args.clone());
173 args
174 }
175
176 pub fn validate(&self) -> Result<(), String> {
182 if let Some((width, height)) = self.window_size
183 && (width == 0 || height == 0)
184 {
185 return Err("Window dimensions must be greater than zero".to_string());
186 }
187 Ok(())
188 }
189
190 #[inline]
192 #[must_use]
193 pub const fn is_headless(&self) -> bool {
194 self.headless
195 }
196
197 #[inline]
199 #[must_use]
200 pub const fn is_private(&self) -> bool {
201 self.private
202 }
203}
204
205#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_new_creates_default() {
215 let options = FirefoxOptions::new();
216 assert!(!options.headless);
217 assert!(options.window_size.is_none());
218 assert!(!options.kiosk);
219 assert!(!options.devtools);
220 assert!(!options.private);
221 assert!(options.extra_args.is_empty());
222 }
223
224 #[test]
225 fn test_headless_constructor() {
226 let options = FirefoxOptions::headless();
227 assert!(options.headless);
228 assert!(options.is_headless());
229 }
230
231 #[test]
232 fn test_builder_chain() {
233 let options = FirefoxOptions::new()
234 .with_headless()
235 .with_window_size(1920, 1080)
236 .with_devtools()
237 .with_private();
238
239 assert!(options.headless);
240 assert_eq!(options.window_size, Some((1920, 1080)));
241 assert!(options.devtools);
242 assert!(options.private);
243 }
244
245 #[test]
246 fn test_to_args_headless() {
247 let options = FirefoxOptions::new().with_headless();
248 let args = options.to_args();
249 assert!(args.contains(&"--headless".to_string()));
250 }
251
252 #[test]
253 fn test_to_args_window_size() {
254 let options = FirefoxOptions::new().with_window_size(800, 600);
255 let args = options.to_args();
256 assert!(args.contains(&"--window-size".to_string()));
257 assert!(args.contains(&"800,600".to_string()));
258 }
259
260 #[test]
261 fn test_to_args_all_options() {
262 let options = FirefoxOptions::new()
263 .with_headless()
264 .with_window_size(1024, 768)
265 .with_kiosk()
266 .with_devtools()
267 .with_private()
268 .with_arg("--custom");
269
270 let args = options.to_args();
271 assert!(args.contains(&"--headless".to_string()));
272 assert!(args.contains(&"--kiosk".to_string()));
273 assert!(args.contains(&"--devtools".to_string()));
274 assert!(args.contains(&"--private-window".to_string()));
275 assert!(args.contains(&"--custom".to_string()));
276 }
277
278 #[test]
279 fn test_with_args_multiple() {
280 let options = FirefoxOptions::new().with_args(["--arg1", "--arg2"]);
281 assert_eq!(options.extra_args.len(), 2);
282 }
283
284 #[test]
285 fn test_validate_valid() {
286 let options = FirefoxOptions::new().with_window_size(800, 600);
287 assert!(options.validate().is_ok());
288 }
289
290 #[test]
291 fn test_validate_zero_width() {
292 let options = FirefoxOptions::new().with_window_size(0, 600);
293 assert!(options.validate().is_err());
294 }
295
296 #[test]
297 fn test_validate_zero_height() {
298 let options = FirefoxOptions::new().with_window_size(800, 0);
299 assert!(options.validate().is_err());
300 }
301}