/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate ::common::{from_cookie, from_name, to_cookie, to_name, Cookie, Frame, Timeouts
, Window};
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Url {
pub url: String,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Locator {
#[ serde(skip_serializing_if = "Option::is_none" )]
pub element: Option<String>,
pub using: Selector,
pub value: String,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Selector {
#[ serde(rename = "css selector" )]
Css,
#[ serde(rename = "link text" )]
LinkText,
#[ serde(rename = "partial link text" )]
PartialLinkText,
#[ serde(rename = "tag name" )]
TagName,
#[ serde(rename = "xpath" )]
XPath,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct NewWindow {
#[ serde(rename = "type" , skip_serializing_if = "Option::is_none" )]
pub type_hint: Option<String>,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct WindowRect {
#[ serde(default, skip_serializing_if = "Option::is_none" )]
pub x: Option<i32>,
#[ serde(default, skip_serializing_if = "Option::is_none" )]
pub y: Option<i32>,
#[ serde(default, skip_serializing_if = "Option::is_none" )]
pub width: Option<i32>,
#[ serde(default, skip_serializing_if = "Option::is_none" )]
pub height: Option<i32>,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Keys {
pub text: String,
pub value: Vec<String>,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[ serde(untagged)]
pub enum PrintPageRange {
Integer(u64),
Range(String),
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[ serde(default, rename_all = "camelCase" )]
pub struct PrintParameters {
pub orientation: PrintOrientation,
pub scale: f64,
pub background: bool,
pub page: PrintPage,
pub margin: PrintMargins,
pub page_ranges: Vec<PrintPageRange>,
pub shrink_to_fit: bool,
}
impl Default for PrintParameters {
fn default() -> Self {
PrintParameters {
orientation: PrintOrientation::default(),
scale: 1 .0 ,
background: false ,
page: PrintPage::default(),
margin: PrintMargins::default(),
page_ranges: Vec::new(),
shrink_to_fit: true ,
}
}
}
#[ derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[ serde(rename_all = "lowercase" )]
pub enum PrintOrientation {
Landscape,
#[ default]
Portrait,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PrintPage {
pub width: f64,
pub height: f64,
}
impl Default for PrintPage {
fn default() -> Self {
PrintPage {
width: 21 .59 ,
height: 27 .94 ,
}
}
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PrintMargins {
pub top: f64,
pub bottom: f64,
pub left: f64,
pub right: f64,
}
impl Default for PrintMargins {
fn default() -> Self {
PrintMargins {
top: 1 .0 ,
bottom: 1 .0 ,
left: 1 .0 ,
right: 1 .0 ,
}
}
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SetPermissionParameters {
pub descriptor: SetPermissionDescriptor,
pub state: SetPermissionState,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SetPermissionDescriptor {
pub name: String,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[ serde(rename_all = "lowercase" )]
pub enum SetPermissionState {
Denied,
Granted,
Prompt,
}
#[ derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum WebAuthnProtocol {
#[ serde(rename = "ctap1/u2f" )]
Ctap1U2f,
#[ serde(rename = "ctap2" )]
Ctap2,
#[ serde(rename = "ctap2_1" )]
Ctap2_1,
}
#[ derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[ serde(rename_all = "kebab-case" )]
pub enum AuthenticatorTransport {
Usb,
Nfc,
Ble,
SmartCard,
Hybrid,
Internal,
}
#[ derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AuthenticatorParameters {
pub protocol: WebAuthnProtocol,
pub transport: AuthenticatorTransport,
pub has_resident_key: bool,
pub has_user_verification: bool,
pub is_user_consenting: bool,
pub is_user_verified: bool,
}
#[ derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct CredentialParameters {
pub credential_id: String,
pub is_resident_credential: bool,
pub rp_id: String,
pub private_key: String,
pub user_handle: String,
pub sign_count: u64,
}
#[ derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct UserVerificationParameters {
pub is_user_verified: bool,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ScreenshotOptions {
pub id: Option<String>,
pub highlights: Vec<Option<String>>,
pub full: bool,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Script {
pub script: String,
pub args: Option<Vec<Value>>,
}
#[ derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Command {
#[ serde(rename = "WebDriver:AcceptAlert" )]
AcceptAlert,
#[ serde(
rename = "WebDriver:AddCookie" ,
serialize_with = "to_cookie" ,
deserialize_with = "from_cookie"
)]
AddCookie(Cookie),
#[ serde(rename = "WebDriver:CloseWindow" )]
CloseWindow,
#[ serde(
rename = "WebDriver:DeleteCookie" ,
serialize_with = "to_name" ,
deserialize_with = "from_name"
)]
DeleteCookie(String),
#[ serde(rename = "WebDriver:DeleteAllCookies" )]
DeleteCookies,
#[ serde(rename = "WebDriver:DeleteSession" )]
DeleteSession,
#[ serde(rename = "WebDriver:DismissAlert" )]
DismissAlert,
#[ serde(rename = "WebDriver:ElementClear" )]
ElementClear { id: String },
#[ serde(rename = "WebDriver:ElementClick" )]
ElementClick { id: String },
#[ serde(rename = "WebDriver:ElementSendKeys" )]
ElementSendKeys {
id: String,
text: String,
value: Vec<String>,
},
#[ serde(rename = "WebDriver:ExecuteAsyncScript" )]
ExecuteAsyncScript(Script),
#[ serde(rename = "WebDriver:ExecuteScript" )]
ExecuteScript(Script),
#[ serde(rename = "WebDriver:FindElement" )]
FindElement(Locator),
#[ serde(rename = "WebDriver:FindElements" )]
FindElements(Locator),
#[ serde(rename = "WebDriver:FindElementFromShadowRoot" )]
FindShadowRootElement {
#[ serde(rename = "shadowRoot" )]
shadow_root: String,
using: Selector,
value: String,
},
#[ serde(rename = "WebDriver:FindElementsFromShadowRoot" )]
FindShadowRootElements {
#[ serde(rename = "shadowRoot" )]
shadow_root: String,
using: Selector,
value: String,
},
#[ serde(rename = "WebDriver:FullscreenWindow" )]
FullscreenWindow,
#[ serde(rename = "WebDriver:Navigate" )]
Get(Url),
#[ serde(rename = "WebDriver:GetActiveElement" )]
GetActiveElement,
#[ serde(rename = "WebDriver:GetAlertText" )]
GetAlertText,
#[ serde(rename = "WebDriver:GetComputedLabel" )]
GetComputedLabel { id: String },
#[ serde(rename = "WebDriver:GetComputedRole" )]
GetComputedRole { id: String },
#[ serde(rename = "WebDriver:GetCookies" )]
GetCookies,
#[ serde(rename = "WebDriver:GetElementCSSValue" )]
GetCSSValue {
id: String,
#[ serde(rename = "propertyName" )]
property: String,
},
#[ serde(rename = "WebDriver:GetCurrentURL" )]
GetCurrentUrl,
#[ serde(rename = "WebDriver:GetElementAttribute" )]
GetElementAttribute { id: String, name: String },
#[ serde(rename = "WebDriver:GetElementProperty" )]
GetElementProperty { id: String, name: String },
#[ serde(rename = "WebDriver:GetElementRect" )]
GetElementRect { id: String },
#[ serde(rename = "WebDriver:GetElementTagName" )]
GetElementTagName { id: String },
#[ serde(rename = "WebDriver:GetElementText" )]
GetElementText { id: String },
#[ serde(rename = "WebDriver:GetPageSource" )]
GetPageSource,
#[ serde(rename = "WebDriver:GetShadowRoot" )]
GetShadowRoot { id: String },
#[ serde(rename = "WebDriver:GetTimeouts" )]
GetTimeouts,
#[ serde(rename = "WebDriver:GetTitle" )]
GetTitle,
#[ serde(rename = "WebDriver:GetWindowHandle" )]
GetWindowHandle,
#[ serde(rename = "WebDriver:GetWindowHandles" )]
GetWindowHandles,
#[ serde(rename = "WebDriver:GetWindowRect" )]
GetWindowRect,
#[ serde(rename = "WebDriver:Back" )]
GoBack,
#[ serde(rename = "WebDriver:Forward" )]
GoForward,
#[ serde(rename = "WebDriver:IsElementDisplayed" )]
IsDisplayed { id: String },
#[ serde(rename = "WebDriver:IsElementEnabled" )]
IsEnabled { id: String },
#[ serde(rename = "WebDriver:IsElementSelected" )]
IsSelected { id: String },
#[ serde(rename = "WebDriver:MaximizeWindow" )]
MaximizeWindow,
#[ serde(rename = "WebDriver:MinimizeWindow" )]
MinimizeWindow,
#[ serde(rename = "WebDriver:NewWindow" )]
NewWindow(NewWindow),
#[ serde(rename = "WebDriver:Print" )]
Print(PrintParameters),
#[ serde(rename = "WebDriver:Refresh" )]
Refresh,
#[ serde(rename = "WebDriver:ReleaseActions" )]
ReleaseActions,
#[ serde(rename = "WebDriver:SendAlertText" )]
SendAlertText(Keys),
#[ serde(rename = "WebDriver:SetPermission" )]
SetPermission(SetPermissionParameters),
#[ serde(rename = "WebDriver:SetTimeouts" )]
SetTimeouts(Timeouts),
#[ serde(rename = "WebDriver:SetWindowRect" )]
SetWindowRect(WindowRect),
#[ serde(rename = "WebDriver:SwitchToFrame" )]
SwitchToFrame(Frame),
#[ serde(rename = "WebDriver:SwitchToParentFrame" )]
SwitchToParentFrame,
#[ serde(rename = "WebDriver:SwitchToWindow" )]
SwitchToWindow(Window),
#[ serde(rename = "WebDriver:TakeScreenshot" )]
TakeScreenshot(ScreenshotOptions),
#[ serde(rename = "WebAuthn:AddVirtualAuthenticator" )]
WebAuthnAddVirtualAuthenticator(AuthenticatorParameters),
#[ serde(rename = "WebAuthn:RemoveVirtualAuthenticator" )]
WebAuthnRemoveVirtualAuthenticator,
#[ serde(rename = "WebAuthn:AddCredential" )]
WebAuthnAddCredential(CredentialParameters),
#[ serde(rename = "WebAuthn:GetCredentials" )]
WebAuthnGetCredentials,
#[ serde(rename = "WebAuthn:RemoveCredential" )]
WebAuthnRemoveCredential,
#[ serde(rename = "WebAuthn:RemoveAllCredentials" )]
WebAuthnRemoveAllCredentials,
#[ serde(rename = "WebAuthn:SetUserVerified" )]
WebAuthnSetUserVerified(UserVerificationParameters),
}
#[ cfg(test)]
mod tests {
use super ::*;
use crate ::common::Date;
use crate ::test::{assert_ser, assert_ser_de};
use serde_json::json;
#[ test]
fn test_json_screenshot() {
let data = ScreenshotOptions {
id: None,
highlights: vec![],
full: false ,
};
let json = json!({"full" :false ,"highlights" :[],"id" :null});
assert_ser_de(&data, json);
}
#[ test]
fn test_json_selector_css() {
assert_ser_de(&Selector::Css, json!("css selector" ));
}
#[ test]
fn test_json_selector_link_text() {
assert_ser_de(&Selector::LinkText, json!("link text" ));
}
#[ test]
fn test_json_selector_partial_link_text() {
assert_ser_de(&Selector::PartialLinkText, json!("partial link text" ));
}
#[ test]
fn test_json_selector_tag_name() {
assert_ser_de(&Selector::TagName, json!("tag name" ));
}
#[ test]
fn test_json_selector_xpath() {
assert_ser_de(&Selector::XPath, json!("xpath" ));
}
#[ test]
fn test_json_selector_invalid() {
assert!(serde_json::from_value::<Selector>(json!("foo" )).is_err());
}
#[ test]
fn test_json_locator() {
let json = json!({
"using" : "partial link text" ,
"value" : "link text" ,
});
let data = Locator {
element: None,
using: Selector::PartialLinkText,
value: "link text" .into(),
};
assert_ser_de(&data, json);
}
#[ test]
fn test_json_keys() {
let data = Keys {
text: "Foo" .into(),
value: vec!["F" .into(), "o" .into(), "o" .into()],
};
let json = json!({"text" : "Foo" , "value" : ["F" , "o" , "o" ]});
assert_ser_de(&data, json);
}
#[ test]
fn test_json_new_window() {
let data = NewWindow {
type_hint: Some("foo" .into()),
};
assert_ser_de(&data, json!({ "type" : "foo" }));
}
#[ test]
fn test_json_window_rect() {
let data = WindowRect {
x: Some(123 ),
y: None,
width: None,
height: None,
};
assert_ser_de(&data, json!({"x" : 123 }));
}
#[ test]
fn test_command_with_params() {
let locator = Locator {
element: None,
using: Selector::Css,
value: "value" .into(),
};
let json = json!({"WebDriver:FindElement" : {"using" : "css selector" , "value" : "value" }});
assert_ser_de(&Command::FindElement(locator), json);
}
#[ test]
fn test_command_with_wrapper_params() {
let cookie = Cookie {
name: "hello" .into(),
value: "world" .into(),
path: None,
domain: None,
secure: false ,
http_only: false ,
expiry: Some(Date(1564488092 )),
same_site: None,
};
let json = json!({"WebDriver:AddCookie" : {"cookie" : {"name" : "hello" , "value" : "world" , "secure" : false , "httpOnly" : false , "expiry" : 1564488092 }}});
assert_ser_de(&Command::AddCookie(cookie), json);
}
#[ test]
fn test_empty_commands() {
assert_ser_de(&Command::GetTimeouts, json!("WebDriver:GetTimeouts" ));
}
#[ test]
fn test_json_command_invalid() {
assert!(serde_json::from_value::<Command>(json!("foo" )).is_err());
}
#[ test]
fn test_json_delete_cookie_command() {
let json = json!({"WebDriver:DeleteCookie" : {"name" : "foo" }});
assert_ser_de(&Command::DeleteCookie("foo" .into()), json);
}
#[ test]
fn test_json_new_window_command() {
let data = NewWindow {
type_hint: Some("foo" .into()),
};
let json = json!({"WebDriver:NewWindow" : {"type" : "foo" }});
assert_ser_de(&Command::NewWindow(data), json);
}
#[ test]
fn test_json_new_window_command_with_none_value() {
let data = NewWindow { type_hint: None };
let json = json!({"WebDriver:NewWindow" : {}});
assert_ser_de(&Command::NewWindow(data), json);
}
#[ test]
fn test_json_command_as_struct() {
assert_ser(
&Command::FindElement(Locator {
element: Some("foo" .into()),
using: Selector::XPath,
value: "bar" .into(),
}),
json!({"WebDriver:FindElement" : {"element" : "foo" , "using" : "xpath" , "value" : "bar" }}),
);
}
#[ test]
fn test_json_get_computed_label_command() {
assert_ser_de(
&Command::GetComputedLabel { id: "foo" .into() },
json!({"WebDriver:GetComputedLabel" : {"id" : "foo" }}),
);
}
#[ test]
fn test_json_get_computed_role_command() {
assert_ser_de(
&Command::GetComputedRole { id: "foo" .into() },
json!({"WebDriver:GetComputedRole" : {"id" : "foo" }}),
);
}
#[ test]
fn test_json_get_css_value() {
assert_ser_de(
&Command::GetCSSValue {
id: "foo" .into(),
property: "bar" .into(),
},
json!({"WebDriver:GetElementCSSValue" : {"id" : "foo" , "propertyName" : "bar" }}),
);
}
#[ test]
fn test_json_find_shadow_root_element() {
assert_ser_de(
&Command::FindShadowRootElement {
shadow_root: "foo" .into(),
using: Selector::Css,
value: "bar" .into(),
},
json!({"WebDriver:FindElementFromShadowRoot" : {"shadowRoot" : "foo" , "using" : "css selector" , "value" : "bar" }}),
);
}
#[ test]
fn test_json_find_shadow_root_elements() {
assert_ser_de(
&Command::FindShadowRootElements {
shadow_root: "foo" .into(),
using: Selector::Css,
value: "bar" .into(),
},
json!({"WebDriver:FindElementsFromShadowRoot" : {"shadowRoot" : "foo" , "using" : "css selector" , "value" : "bar" }}),
);
}
}
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-19)
¤
*© Formatika GbR, Deutschland