Skip to content

Commit 1d9aede

Browse files
committed
Refactor capabilities to make everything clearer
1 parent 6708116 commit 1d9aede

10 files changed

Lines changed: 403 additions & 362 deletions

File tree

thirtyfour/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "thirtyfour"
3-
version = "0.32.0-rc.1"
3+
version = "0.32.0-rc.2"
44
authors = ["Steve Pryde <steve@stevepryde.com>"]
55
edition = "2021"
66
license = "MIT OR Apache-2.0"
@@ -33,6 +33,7 @@ futures = "0.3.21"
3333
http = "0.2.8"
3434
log = "0.4.17"
3535
parking_lot = "0.12.1"
36+
paste = "1.0.9"
3637
serde = { version = "1.0", features = ["derive"] }
3738
serde_json = { version = "1.0", features = ["preserve_order"] }
3839
serde_repr = "0.1.8"

thirtyfour/examples/chrome_options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ async fn main() -> color_eyre::Result<()> {
1313
color_eyre::install()?;
1414

1515
let mut caps = DesiredCapabilities::chrome();
16-
caps.add_chrome_option(
16+
caps.insert_browser_option(
1717
"prefs",
1818
serde_json::json!({
1919
"profile.default_content_settings": {

thirtyfour/src/common/capabilities/chrome.rs

Lines changed: 140 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use std::path::Path;
2+
3+
use paste::paste;
4+
use serde::Serialize;
5+
use serde_json::{json, to_value, Value};
6+
17
use crate::error::WebDriverResult;
2-
use crate::Capabilities;
38
use crate::CapabilitiesHelper;
4-
use serde::de::DeserializeOwned;
5-
use serde::Serialize;
6-
use serde_json::{from_value, json, to_value};
7-
use std::ops::{Deref, DerefMut};
8-
use std::path::Path;
9+
use crate::{BrowserCapabilitiesHelper, Capabilities};
910

1011
#[derive(Debug, Clone, Serialize)]
1112
#[serde(transparent)]
@@ -15,113 +16,161 @@ pub struct ChromeCapabilities {
1516

1617
impl Default for ChromeCapabilities {
1718
fn default() -> Self {
18-
let mut capabilities = Capabilities::new();
19-
capabilities.insert("browserName".to_string(), json!("chrome"));
20-
ChromeCapabilities {
21-
capabilities,
19+
Self::new()
20+
}
21+
}
22+
23+
macro_rules! chrome_arg_wrapper {
24+
($($fname:ident => $opt:literal),*) => {
25+
paste! {
26+
$(
27+
#[doc = concat!("Set the ", $opt, " option.")]
28+
pub fn [<set_ $fname>](&mut self) -> WebDriverResult<()> {
29+
self.add_arg($opt)
30+
}
31+
32+
#[doc = concat!("Unset the ", $opt, " option.")]
33+
pub fn [<unset_ $fname>](&mut self) -> WebDriverResult<()> {
34+
self.remove_arg($opt)
35+
}
36+
37+
#[doc = concat!("Return true if the ", $opt, " option is set.")]
38+
pub fn [<is_ $fname>](&mut self) -> bool {
39+
self.has_arg($opt)
40+
}
41+
)*
2242
}
2343
}
2444
}
2545

2646
impl ChromeCapabilities {
2747
/// Create a new ChromeCapabilities struct.
2848
pub fn new() -> Self {
29-
ChromeCapabilities::default()
30-
}
31-
32-
/// Add the specified Chrome option. This is a helper method for `add_chrome_arg()`.
33-
pub fn add_chrome_option<T>(&mut self, key: &str, value: T) -> WebDriverResult<()>
34-
where
35-
T: Serialize,
36-
{
37-
self.add_subkey("goog:chromeOptions", key, value)
38-
}
39-
40-
/// Get the specified Chrome option.
41-
pub fn get_chrome_option<T>(&self, key: &str) -> T
42-
where
43-
T: DeserializeOwned + Default,
44-
{
45-
self.capabilities
46-
.get("goog:chromeOptions")
47-
.and_then(|options| options.get(key))
48-
.and_then(|option| from_value(option.clone()).ok())
49-
.unwrap_or_default()
49+
let mut capabilities = Capabilities::new();
50+
capabilities.insert("browserName".to_string(), json!("chrome"));
51+
ChromeCapabilities {
52+
capabilities,
53+
}
5054
}
5155

5256
/// Get the current list of command-line arguments to `chromedriver` as a vec.
53-
pub fn get_args(&self) -> Vec<String> {
54-
self.get_chrome_option("args")
57+
pub fn args(&self) -> Vec<String> {
58+
self.browser_option("args").unwrap_or_default()
5559
}
5660

5761
/// Get the current list of Chrome extensions as a vec.
62+
///
5863
/// Each item is a base64-encoded string containing the .CRX extension file contents.
5964
/// Use `add_extension()` to add a new extension file.
60-
pub fn get_extensions(&self) -> Vec<String> {
61-
self.get_chrome_option("extensions")
65+
pub fn extensions(&self) -> Vec<String> {
66+
self.browser_option("extensions").unwrap_or_default()
6267
}
6368

6469
/// Get the path to the chrome binary (if one was previously set).
65-
pub fn get_binary(&self) -> String {
66-
self.get_chrome_option("binary")
70+
pub fn binary(&self) -> Option<String> {
71+
self.browser_option("binary")
6772
}
6873

6974
/// Set the path to chrome binary to use.
7075
pub fn set_binary(&mut self, path: &str) -> WebDriverResult<()> {
71-
self.add_chrome_option("binary", path)
76+
self.insert_browser_option("binary", path)
77+
}
78+
79+
/// Unset the chrome binary path.
80+
pub fn unset_binary(&mut self) {
81+
self.remove_browser_option("binary");
7282
}
7383

7484
/// Get the current debugger address (if one was previously set).
75-
pub fn get_debugger_address(&self) -> String {
76-
self.get_chrome_option("debuggerAddress")
85+
pub fn debugger_address(&self) -> Option<String> {
86+
self.browser_option("debuggerAddress")
7787
}
7888

7989
/// Set the debugger address.
8090
pub fn set_debugger_address(&mut self, address: &str) -> WebDriverResult<()> {
81-
self.add_chrome_option("debuggerAddress", address)
91+
self.insert_browser_option("debuggerAddress", address)
92+
}
93+
94+
/// Unset the debugger address.
95+
pub fn unset_debugger_address(&mut self) {
96+
self.remove_browser_option("debuggerAddress");
8297
}
8398

84-
/// Add the specified command-line argument to `chromedriver`. Eg. "--disable-local-storage"
99+
/// Add the specified command-line argument to `chromedriver`.
100+
///
101+
/// ## Example
102+
///
103+
/// ```ignore
104+
/// let mut caps = DesiredCapabilities::chrome();
105+
/// caps.add_chrome_arg("--disable-local-storage")?;
106+
/// ```
107+
///
85108
/// The full list of switches can be found here:
86109
/// [https://chromium.googlesource.com/chromium/src/+/master/chrome/common/chrome_switches.cc](https://chromium.googlesource.com/chromium/src/+/master/chrome/common/chrome_switches.cc)
87-
pub fn add_chrome_arg(&mut self, arg: &str) -> WebDriverResult<()> {
88-
let mut args = self.get_args();
110+
pub fn add_arg(&mut self, arg: &str) -> WebDriverResult<()> {
111+
let mut args = self.args();
89112
let arg_string = arg.to_string();
90113
if !args.contains(&arg_string) {
91114
args.push(arg_string);
92115
}
93-
self.add_chrome_option("args", to_value(args)?)
116+
self.insert_browser_option("args", to_value(args)?)
94117
}
95118

96119
/// Remove the specified Chrome command-line argument if it had been added previously.
97-
pub fn remove_chrome_arg(&mut self, arg: &str) -> WebDriverResult<()> {
98-
let mut args = self.get_args();
120+
pub fn remove_arg(&mut self, arg: &str) -> WebDriverResult<()> {
121+
let mut args = self.args();
99122
if args.is_empty() {
100123
Ok(())
101124
} else {
102125
args.retain(|v| v != arg);
103-
self.add_chrome_option("args", to_value(args)?)
126+
self.insert_browser_option("args", to_value(args)?)
104127
}
105128
}
106129

130+
/// Return true if the specified arg is currently set.
131+
pub fn has_arg(&self, arg: &str) -> bool {
132+
self.args().contains(&arg.to_string())
133+
}
134+
135+
/// Add the specified experimental option.
136+
///
137+
/// ## Example
138+
/// ```no_run
139+
/// use thirtyfour::DesiredCapabilities;
140+
/// let mut caps = DesiredCapabilities::chrome();
141+
/// caps.add_experimental_option("excludeSwitches", vec!["--enable-logging"]).unwrap();
142+
/// ```
143+
pub fn add_experimental_option(
144+
&mut self,
145+
name: impl Into<String>,
146+
value: impl Serialize,
147+
) -> WebDriverResult<()> {
148+
self.insert_browser_option(name, value)
149+
}
150+
151+
/// Remove the specified experimental option.
152+
pub fn remove_experimental_option(&mut self, name: &str) {
153+
self.remove_browser_option(name);
154+
}
155+
107156
/// Add a base64-encoded extension.
108157
pub fn add_encoded_extension(&mut self, extension_base64: &str) -> WebDriverResult<()> {
109-
let mut extensions = self.get_extensions();
158+
let mut extensions = self.extensions();
110159
let ext_string = extension_base64.to_string();
111160
if !extensions.contains(&ext_string) {
112161
extensions.push(ext_string);
113162
}
114-
self.add_chrome_option("extensions", to_value(extensions)?)
163+
self.insert_browser_option("extensions", to_value(extensions)?)
115164
}
116165

117166
/// Remove the specified base64-encoded extension if it had been added previously.
118167
pub fn remove_encoded_extension(&mut self, extension_base64: &str) -> WebDriverResult<()> {
119-
let mut extensions = self.get_extensions();
168+
let mut extensions = self.extensions();
120169
if extensions.is_empty() {
121170
Ok(())
122171
} else {
123172
extensions.retain(|v| v != extension_base64);
124-
self.add_chrome_option("extensions", to_value(extensions)?)
173+
self.insert_browser_option("extensions", to_value(extensions)?)
125174
}
126175
}
127176

@@ -140,77 +189,63 @@ impl ChromeCapabilities {
140189
self.remove_encoded_extension(&b64_contents)
141190
}
142191

143-
/// Set the browser to run headless.
144-
pub fn set_headless(&mut self) -> WebDriverResult<()> {
145-
self.add_chrome_arg("--headless")
146-
}
147-
148-
/// Unset the headless option.
149-
pub fn unset_headless(&mut self) -> WebDriverResult<()> {
150-
self.remove_chrome_arg("--headless")
151-
}
152-
153-
/// Set disable web security.
154-
pub fn set_disable_web_security(&mut self) -> WebDriverResult<()> {
155-
self.add_chrome_arg("--disable-web-security")
156-
}
157-
158-
/// Unset disable web security.
159-
pub fn unset_disable_web_security(&mut self) -> WebDriverResult<()> {
160-
self.remove_chrome_arg("--disable-web-security")
192+
/// Get the list of exclude switches.
193+
pub fn exclude_switches(&self) -> Vec<String> {
194+
self.browser_option("excludeSwitches").unwrap_or_default()
161195
}
162196

163-
/// Set ignore certificate errors.
164-
pub fn set_ignore_certificate_errors(&mut self) -> WebDriverResult<()> {
165-
self.add_chrome_arg("--ignore-certificate-errors")
166-
}
167-
168-
/// Unset ignore certificate errors.
169-
pub fn unset_ignore_certificate_errors(&mut self) -> WebDriverResult<()> {
170-
self.remove_chrome_arg("--ignore-certificate-errors")
197+
/// Add the specified arg to the list of exclude switches.
198+
pub fn add_exclude_switch(&mut self, arg: &str) -> WebDriverResult<()> {
199+
let mut args = self.exclude_switches();
200+
let arg_string = arg.to_string();
201+
if !args.contains(&arg_string) {
202+
args.push(arg_string);
203+
}
204+
self.add_experimental_option("excludeSwitches", to_value(args)?)
171205
}
172206

173-
pub fn set_no_sandbox(&mut self) -> WebDriverResult<()> {
174-
self.add_chrome_arg("--no-sandbox")
207+
/// Remove the specified arg from the list of exclude switches.
208+
pub fn remove_exclude_switch(&mut self, arg: &str) -> WebDriverResult<()> {
209+
let mut args = self.exclude_switches();
210+
if args.is_empty() {
211+
Ok(())
212+
} else {
213+
args.retain(|v| v != arg);
214+
self.add_experimental_option("excludeSwitches", to_value(args)?)
215+
}
175216
}
176217

177-
pub fn unset_no_sandbox(&mut self) -> WebDriverResult<()> {
178-
self.remove_chrome_arg("--no-sandbox")
218+
chrome_arg_wrapper! {
219+
headless => "--headless",
220+
disable_web_security => "--disable-web-security",
221+
ignore_certificate_errors => "--ignore-certificate-errors",
222+
no_sandbox => "--no-sandbox",
223+
disable_gpu => "--disable-gpu",
224+
disable_dev_shm_usage => "--disable-dev-shm-usage",
225+
disable_local_storage => "--disable-local-storage"
179226
}
227+
}
180228

181-
pub fn set_disable_gpu(&mut self) -> WebDriverResult<()> {
182-
self.add_chrome_arg("--disable-gpu")
229+
impl CapabilitiesHelper for ChromeCapabilities {
230+
fn _get(&self, key: &str) -> Option<&Value> {
231+
self.capabilities._get(key)
183232
}
184233

185-
pub fn unset_disable_gpu(&mut self) -> WebDriverResult<()> {
186-
self.remove_chrome_arg("--disable-gpu")
234+
fn _get_mut(&mut self, key: &str) -> Option<&mut Value> {
235+
self.capabilities._get_mut(key)
187236
}
188237

189-
pub fn set_disable_dev_shm_usage(&mut self) -> WebDriverResult<()> {
190-
self.add_chrome_arg("--disable-dev-shm-usage")
238+
fn insert_base_capability(&mut self, key: String, value: Value) {
239+
self.capabilities.insert_base_capability(key, value);
191240
}
241+
}
192242

193-
pub fn unset_disable_dev_shm_usage(&mut self) -> WebDriverResult<()> {
194-
self.remove_chrome_arg("--disable-dev-shm-usage")
195-
}
243+
impl BrowserCapabilitiesHelper for ChromeCapabilities {
244+
const KEY: &'static str = "goog:chromeOptions";
196245
}
197246

198247
impl From<ChromeCapabilities> for Capabilities {
199248
fn from(caps: ChromeCapabilities) -> Capabilities {
200249
caps.capabilities
201250
}
202251
}
203-
204-
impl Deref for ChromeCapabilities {
205-
type Target = Capabilities;
206-
207-
fn deref(&self) -> &Self::Target {
208-
&self.capabilities
209-
}
210-
}
211-
212-
impl DerefMut for ChromeCapabilities {
213-
fn deref_mut(&mut self) -> &mut Self::Target {
214-
&mut self.capabilities
215-
}
216-
}

0 commit comments

Comments
 (0)