use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, json, to_value, Value};
use crate::common::capabilities::chrome::ChromeCapabilities;
use crate::common::capabilities::edge::EdgeCapabilities;
use crate::common::capabilities::firefox::FirefoxCapabilities;
use crate::common::capabilities::ie::InternetExplorerCapabilities;
use crate::common::capabilities::opera::OperaCapabilities;
use crate::common::capabilities::safari::SafariCapabilities;
use crate::error::WebDriverResult;
use crate::ChromiumCapabilities;
pub type Capabilities = serde_json::Map<String, Value>;
const W3C_CAPABILITY_NAMES: &[&str] = &[
"acceptInsecureCerts",
"browserName",
"browserVersion",
"platformName",
"pageLoadStrategy",
"proxy",
"setWindowRect",
"timeouts",
"unhandledPromptBehavior",
"strictFileInteractability",
];
const OSS_W3C_CONVERSION: &[(&str, &str)] = &[
("acceptSslCerts", "acceptInsecureCerts"),
("version", "browserVersion"),
("platform", "platformName"),
];
pub fn make_w3c_caps(caps: &serde_json::Value) -> serde_json::Value {
let mut always_match = serde_json::json!({});
if let Some(caps_map) = caps.as_object() {
for (k, v) in caps_map.iter() {
if !v.is_null() {
for (k_from, k_to) in OSS_W3C_CONVERSION {
if k_from == k {
always_match[k_to] = v.clone();
}
}
}
if W3C_CAPABILITY_NAMES.contains(&k.as_str()) || k.contains(':') {
always_match[k] = v.clone();
}
}
}
json!({
"firstMatch": [{}], "alwaysMatch": always_match
})
}
#[derive(Debug)]
pub struct DesiredCapabilities;
impl DesiredCapabilities {
pub fn chrome() -> ChromeCapabilities {
ChromeCapabilities::new()
}
pub fn chromium() -> ChromiumCapabilities {
ChromiumCapabilities::new()
}
pub fn edge() -> EdgeCapabilities {
EdgeCapabilities::new()
}
pub fn firefox() -> FirefoxCapabilities {
FirefoxCapabilities::new()
}
pub fn internet_explorer() -> InternetExplorerCapabilities {
InternetExplorerCapabilities::new()
}
pub fn opera() -> OperaCapabilities {
OperaCapabilities::new()
}
pub fn safari() -> SafariCapabilities {
SafariCapabilities::new()
}
}
pub trait CapabilitiesHelper {
fn _get(&self, key: &str) -> Option<&Value>;
fn _get_mut(&mut self, key: &str) -> Option<&mut Value>;
fn insert_base_capability(&mut self, key: String, value: Value);
fn set_base_capability<T>(&mut self, key: &str, value: T) -> WebDriverResult<()>
where
T: Serialize,
{
self.insert_base_capability(key.to_string(), to_value(value)?);
Ok(())
}
fn set_version(&mut self, version: &str) -> WebDriverResult<()> {
self.set_base_capability("version", version)
}
fn set_platform(&mut self, platform: &str) -> WebDriverResult<()> {
self.set_base_capability("platform", platform)
}
fn set_javascript_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("javascriptEnabled", enabled)
}
fn set_database_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("databaseEnabled", enabled)
}
fn set_location_context_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("locationContextEnabled", enabled)
}
fn set_application_cache_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("applicationCacheEnabled", enabled)
}
fn set_browser_connection_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("browserConnectionEnabled", enabled)
}
fn set_web_storage_enabled(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("webStorageEnabled", enabled)
}
#[deprecated(since = "0.32.0-rc.5", note = "please use `accept_insecure_certs` instead")]
fn accept_ssl_certs(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("acceptSslCerts", enabled)
}
fn accept_insecure_certs(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("acceptInsecureCerts", enabled)
}
fn set_rotatable(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("rotatable", enabled)
}
fn set_native_events(&mut self, enabled: bool) -> WebDriverResult<()> {
self.set_base_capability("nativeEvents", enabled)
}
fn set_proxy(&mut self, proxy: Proxy) -> WebDriverResult<()> {
self.set_base_capability("proxy", proxy)
}
fn set_unexpected_alert_behaviour(&mut self, behaviour: AlertBehaviour) -> WebDriverResult<()> {
self.set_base_capability("unexpectedAlertBehaviour", behaviour)
}
fn set_element_scroll_behaviour(&mut self, behaviour: ScrollBehaviour) -> WebDriverResult<()> {
self.set_base_capability("elementScrollBehavior", behaviour)
}
fn handles_alerts(&self) -> Option<bool> {
self._get("handlesAlerts").and_then(|x| x.as_bool())
}
fn css_selectors_enabled(&self) -> Option<bool> {
self._get("cssSelectorsEnabled").and_then(|x| x.as_bool())
}
fn page_load_strategy(&self) -> WebDriverResult<PageLoadStrategy> {
let strategy = self._get("pageLoadStrategy").map(|x| from_value(x.clone())).transpose()?;
Ok(strategy.unwrap_or_default())
}
fn set_page_load_strategy(&mut self, strategy: PageLoadStrategy) -> WebDriverResult<()> {
self.set_base_capability("pageLoadStrategy", strategy)
}
}
pub trait BrowserCapabilitiesHelper: CapabilitiesHelper {
const KEY: &'static str;
fn insert_browser_option(
&mut self,
key: impl Into<String>,
value: impl Serialize,
) -> WebDriverResult<()> {
match self._get_mut(Self::KEY) {
Some(Value::Object(v)) => {
v.insert(key.into(), to_value(value)?);
}
_ => self.insert_base_capability(Self::KEY.to_string(), json!({ key: value })),
}
Ok(())
}
fn remove_browser_option(&mut self, key: &str) {
if let Some(Value::Object(v)) = &mut self._get_mut(Self::KEY) {
v.remove(key);
}
}
fn browser_option<T>(&self, key: &str) -> Option<T>
where
T: DeserializeOwned,
{
self._get(Self::KEY)
.and_then(|options| options.get(key))
.and_then(|option| from_value(option.clone()).ok())
}
}
impl CapabilitiesHelper for Capabilities {
fn _get(&self, key: &str) -> Option<&Value> {
self.get(key)
}
fn _get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.get_mut(key)
}
fn insert_base_capability(&mut self, key: String, value: Value) {
self.insert(key, value);
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "proxyType", rename_all = "lowercase")]
pub enum Proxy {
Direct,
#[serde(rename_all = "camelCase")]
Manual {
#[serde(skip_serializing_if = "Option::is_none")]
ftp_proxy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
http_proxy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
ssl_proxy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
socks_proxy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
socks_version: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
socks_username: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
socks_password: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
no_proxy: Option<String>,
},
#[serde(rename = "pac")]
AutoConfig {
#[serde(rename = "proxyAutoconfigUrl")]
url: String,
},
AutoDetect,
System,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum AlertBehaviour {
Accept,
Dismiss,
Ignore,
}
#[derive(Debug, Clone, Serialize)]
#[repr(u8)]
pub enum ScrollBehaviour {
Top = 0,
Bottom = 1,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PageLoadStrategy {
#[default]
Normal,
Eager,
None,
}