1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct BrowserConfig {
10 pub webdriver_url: String,
12
13 pub browser: BrowserType,
15
16 pub headless: bool,
18
19 pub viewport_width: u32,
21
22 pub viewport_height: u32,
24
25 pub page_load_timeout_secs: u64,
27
28 pub script_timeout_secs: u64,
30
31 pub implicit_wait_secs: u64,
33
34 pub user_agent: Option<String>,
36
37 pub browser_args: Vec<String>,
39
40 #[serde(default)]
43 pub require_explicit_start: bool,
44
45 #[serde(default)]
49 pub chrome_options: BTreeMap<String, serde_json::Value>,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "lowercase")]
55pub enum BrowserType {
56 Chrome,
57 Firefox,
58 Safari,
59 Edge,
60}
61
62impl Default for BrowserConfig {
63 fn default() -> Self {
64 Self {
65 webdriver_url: "http://localhost:4444".to_string(),
66 browser: BrowserType::Chrome,
67 headless: true,
68 viewport_width: 1920,
69 viewport_height: 1080,
70 page_load_timeout_secs: 30,
71 script_timeout_secs: 30,
72 implicit_wait_secs: 10,
73 user_agent: None,
74 browser_args: Vec::new(),
75 chrome_options: Default::default(),
76 require_explicit_start: false,
77 }
78 }
79}
80
81impl BrowserConfig {
82 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn webdriver_url(mut self, url: impl Into<String>) -> Self {
89 self.webdriver_url = url.into();
90 self
91 }
92
93 pub fn browser(mut self, browser: BrowserType) -> Self {
95 self.browser = browser;
96 self
97 }
98
99 pub fn headless(mut self, headless: bool) -> Self {
101 self.headless = headless;
102 self
103 }
104
105 pub fn viewport(mut self, width: u32, height: u32) -> Self {
107 self.viewport_width = width;
108 self.viewport_height = height;
109 self
110 }
111
112 pub fn page_load_timeout(mut self, secs: u64) -> Self {
114 self.page_load_timeout_secs = secs;
115 self
116 }
117
118 pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
120 self.user_agent = Some(ua.into());
121 self
122 }
123
124 pub fn add_arg(mut self, arg: impl Into<String>) -> Self {
126 self.browser_args.push(arg.into());
127 self
128 }
129
130 pub fn require_explicit_start(mut self, required: bool) -> Self {
141 self.require_explicit_start = required;
142 self
143 }
144
145 pub fn chrome_option(mut self, name: impl Into<String>, value: serde_json::Value) -> Self {
161 self.chrome_options.insert(name.into(), value);
162 self
163 }
164
165 pub fn observable(self) -> Self {
170 self.headless(false).viewport(1280, 720)
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_default_config() {
180 let config = BrowserConfig::default();
181 assert_eq!(config.webdriver_url, "http://localhost:4444");
182 assert!(config.headless);
183 assert_eq!(config.viewport_width, 1920);
184 }
185
186 #[test]
187 fn test_builder() {
188 let config =
189 BrowserConfig::new().browser(BrowserType::Firefox).headless(false).viewport(1280, 720);
190
191 assert_eq!(config.browser, BrowserType::Firefox);
192 assert!(!config.headless);
193 assert_eq!(config.viewport_width, 1280);
194 }
195
196 #[test]
197 fn test_observable() {
198 let config = BrowserConfig::new().observable();
199 assert!(!config.headless);
200 assert_eq!(config.viewport_width, 1280);
201 assert_eq!(config.viewport_height, 720);
202 }
203}