--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,20 +1,19 @@
use common::WebElement;
-use serde::{Deserialize, Deserializer};
-use serde::ser::{Serialize, Serializer};
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{self, Value, Map};
use std::default::Default;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ActionsParameters {
pub actions: Vec<ActionSequence>
}
-// TODO remove
+// TODO remove once command.rs is fixed
impl<'a> From<&'a ActionsParameters> for Value {
fn from(params: &'a ActionsParameters) -> Value {
let mut data = Map::new();
// TODO: Remove workaround
let json = serde_json::to_string(¶ms).unwrap();
data.insert("actions".to_owned(), serde_json::from_str(&json).unwrap());
Value::Object(data)
}
@@ -167,17 +166,17 @@ pub struct PointerMoveAction {
}
#[cfg(test)]
mod test {
use serde_json;
use super::*;
#[test]
- fn test_action_parameters() {
+ fn test_deserialize_action_parameters() {
let expected = ActionsParameters {
actions: vec!{
ActionSequence {
id: Some("none".into()),
actions: ActionsType::Null {
actions: vec!{
NullActionItem::General (
GeneralAction::Pause ( PauseAction { duration: 1 } )
@@ -195,17 +194,17 @@ mod test {
}]
}"#;
let actual: ActionsParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_action_sequence_null() {
+ fn test_deserialize_action_sequence_null() {
let expected = ActionSequence {
id: Some("none".into()),
actions: ActionsType::Null {
actions: vec!{
NullActionItem::General (
GeneralAction::Pause ( PauseAction { duration: 1 } )
)
}
@@ -217,17 +216,17 @@ mod test {
"actions": {"actions": [{"type": "pause", "duration": 1}]}
}"#;
let actual: ActionSequence = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_action_sequence_key() {
+ fn test_deserialize_action_sequence_key() {
let expected = ActionSequence {
id: Some("some_key".into()),
actions: ActionsType::Key {
actions: vec!{
KeyActionItem::Key (
KeyAction::Down ( KeyDownAction { value: String::from("f") } )
)
}
@@ -239,17 +238,17 @@ mod test {
"actions": {"actions": [{"type": "keyDown", "value": "f"}]}
}"#;
let actual: ActionSequence = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_action_sequence_pointer() {
+ fn test_deserialize_action_sequence_pointer() {
let expected = ActionSequence {
id: Some("some_pointer".into()),
actions: ActionsType::Pointer {
parameters: PointerActionParameters {
pointer_type: PointerType::Mouse
},
actions: vec!{
PointerActionItem::Pointer (
@@ -283,47 +282,47 @@ mod test {
]
}
}"#;
let actual: ActionSequence = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_actions_type_null() {
+ fn test_deserialize_actions_type_null() {
let expected = ActionsType::Null {
actions: vec!{
NullActionItem::General (
GeneralAction::Pause ( PauseAction { duration: 1 } )
)
}
};
let data = r#"{"actions": [{"type": "pause", "duration":1}]}"#;
let actual: ActionsType = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_actions_type_key() {
+ fn test_deserialize_actions_type_key() {
let expected = ActionsType::Key {
actions: vec!{
KeyActionItem::Key (
KeyAction::Down ( KeyDownAction { value: String::from("f") } )
)
}
};
let data = r#"{"actions": [{"type": "keyDown", "value": "f"}]}"#;
let actual: ActionsType = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_actions_type_pointer() {
+ fn test_deserialize_actions_type_pointer() {
let expected = ActionsType::Pointer {
parameters: PointerActionParameters {
pointer_type: PointerType::Mouse
},
actions: vec!{
PointerActionItem::Pointer (
PointerAction::Down ( PointerDownAction { button: 1 } )
)
@@ -335,312 +334,310 @@ mod test {
"actions": [
{"type": "pointerDown", "button": 1}
]}"#;
let actual: ActionsType = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_null_action_item_general() {
+ fn test_deserialize_null_action_item_general() {
let expected = NullActionItem::General ( GeneralAction::Pause (
PauseAction { duration: 1 }
));
let data = r#"{"type": "pause", "duration": 1}"#;
let actual: NullActionItem = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_null_action_item_invalid_type() {
+ fn test_deserialize_null_action_item_invalid_type() {
let data = r#"{"type": "invalid"}"#;
assert!(serde_json::from_str::<NullActionItem>(&data).is_err());
}
#[test]
- fn test_key_action_item_general() {
+ fn test_deserialize_key_action_item_general() {
let expected = KeyActionItem::General ( GeneralAction::Pause (
PauseAction { duration: 1 }
));
let data = r#"{"type": "pause", "duration": 1}"#;
let actual: KeyActionItem = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_action_item_key() {
+ fn test_deserialize_key_action_item_key() {
let expected = KeyActionItem::Key ( KeyAction::Down (
KeyDownAction { value: String::from("f") }
));
let data = r#"{"type": "keyDown", "value": "f"}"#;
let actual: KeyActionItem = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_action_item_invalid_type() {
+ fn test_deserialize_key_action_item_invalid_type() {
let data = r#"{"type": "invalid"}"#;
assert!(serde_json::from_str::<KeyActionItem>(&data).is_err());
}
#[test]
- fn test_key_action_down() {
+ fn test_deserialize_key_action_down() {
let expected = KeyAction::Down ( KeyDownAction { value: String::from("f") } );
let data = r#"{"type": "keyDown", "value": "f"}"#;
let actual: KeyAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_action_up() {
+ fn test_deserialize_key_action_up() {
let expected = KeyAction::Up ( KeyUpAction { value: String::from("f") } );
let data = r#"{"type": "keyUp", "value": "f"}"#;
let actual: KeyAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_action_invalid_type() {
+ fn test_deserialize_key_action_invalid_type() {
let data = r#"{"type": "invalid", "value": "f"}"#;
assert!(serde_json::from_str::<KeyAction>(&data).is_err());
}
#[test]
- fn test_key_action_missing_type() {
+ fn test_deserialize_key_action_missing_type() {
let data = r#"{"value": "f"}"#;
assert!(serde_json::from_str::<KeyAction>(&data).is_err());
}
#[test]
- fn test_key_down_action() {
+ fn test_deserialize_key_down_action() {
let expected = KeyDownAction { value: String::from("f") };
let data = r#"{"type": "keyDown", "value": "f"}"#;
let actual: KeyDownAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_down_action_missing_value() {
+ fn test_deserialize_key_down_action_missing_value() {
let data = r#"{"type": "keyDown"}"#;
assert!(serde_json::from_str::<KeyDownAction>(&data).is_err());
}
#[test]
- fn test_key_up_action() {
+ fn test_deserialize_key_up_action() {
let expected = KeyUpAction { value: String::from("f") };
let data = r#"{"type": "keyUp", "value": "f"}"#;
let actual: KeyUpAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_key_up_action_missing_value() {
+ fn test_deserialize_key_up_action_missing_value() {
let data = r#"{"type": "keyDown"}"#;
assert!(serde_json::from_str::<KeyUpAction>(&data).is_err());
}
#[test]
- fn test_pointer_action_item_general() {
+ fn test_deserialize_pointer_action_item_general() {
let expected = PointerActionItem::General ( GeneralAction::Pause (
PauseAction { duration: 1 }
));
let data = r#"{"type": "pause", "duration": 1}"#;
let actual: PointerActionItem = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_item_pointer() {
+ fn test_deserialize_pointer_action_item_pointer() {
let expected = PointerActionItem::Pointer ( PointerAction::Cancel );
let data = r#"{"type": "pointerCancel"}"#;
let actual: PointerActionItem = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_item_invalid_type() {
+ fn test_deserialize_pointer_action_item_invalid_type() {
let data = r#"{"type": "pointerInvalid"}"#;
assert!(serde_json::from_str::<PointerActionItem>(&data).is_err());
}
#[test]
- fn test_pointer_action_parameters() {
+ fn test_deserialize_pointer_action_parameters() {
let expected = PointerActionParameters { pointer_type: PointerType::Mouse};
let data = r#"{"pointerType": "mouse"}"#;
let actual: PointerActionParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_general_action_pause() {
+ fn test_deserialize_general_action_pause() {
let expected = GeneralAction::Pause ( PauseAction { duration: 1 } );
let data = r#"{"type": "pause", "duration": 1}"#;
let actual: GeneralAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pause_action() {
+ fn test_deserialize_pause_action() {
let expected = PauseAction { duration: 1 };
let data = r#"{"duration": 1}"#;
let actual: PauseAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pause_action_missing_duration() {
+ fn test_deserialize_pause_action_missing_duration() {
let data = r#"{}"#;
assert!(serde_json::from_str::<PauseAction>(&data).is_err());
}
#[test]
- fn test_pointer_action_cancel() {
+ fn test_deserialize_pointer_action_cancel() {
let expected = PointerAction::Cancel;
let data = r#"{"type": "pointerCancel"}"#;
let actual: PointerAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_down() {
+ fn test_deserialize_pointer_action_down() {
let expected = PointerAction::Down ( PointerDownAction { button: 1} );
let data = r#"{"type": "pointerDown", "button": 1}"#;
let actual: PointerAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_up() {
+ fn test_deserialize_pointer_action_up() {
let expected = PointerAction::Up ( PointerUpAction { button: 1} );
let data = r#"{"type": "pointerUp", "button": 1}"#;
let actual: PointerAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_move() {
+ fn test_deserialize_pointer_action_move() {
let expected = PointerAction::Move ( PointerMoveAction {
duration: None,
origin: PointerOrigin::Pointer,
x: None,
y: None,
});
let data = r#"{"type": "pointerMove", "origin": "pointer"}"#;
let actual: PointerAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_action_invaid_type() {
+ fn test_deserialize_pointer_action_invaid_type() {
let data = r#"{"type": "pointerInvald"}"#;
assert!(serde_json::from_str::<PointerAction>(&data).is_err());
}
#[test]
- fn test_pointer_action_missing_type() {
+ fn test_deserialize_pointer_action_missing_type() {
let data = r#"{"button": 1}"#;
assert!(serde_json::from_str::<PointerAction>(&data).is_err());
}
#[test]
- fn test_pointer_down_action() {
+ fn test_deserialize_pointer_down_action() {
let expected = PointerDownAction { button: 1 };
let data = r#"{"button": 1}"#;
let actual: PointerDownAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_down_action_invalid_field() {
+ fn test_deserialize_pointer_down_action_invalid_field() {
let data = r#"{"duration": 100}"#;
assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
}
#[test]
- fn test_pointer_down_action_missing_button_field() {
+ fn test_deserialize_pointer_down_action_missing_button_field() {
let data = r#"{}"#;
assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
}
#[test]
- fn test_pointer_up_action() {
+ fn test_deserialize_pointer_up_action() {
let expected = PointerUpAction { button: 1 };
let data = r#"{"button": 1}"#;
let actual: PointerUpAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_up_action_invalid_field() {
+ fn test_deserialize_pointer_up_action_invalid_field() {
let data = r#"{"duration": 100}"#;
assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
}
#[test]
- fn test_pointer_up_action_missing_button_field() {
+ fn test_deserialize_pointer_up_action_missing_button_field() {
let data = r#"{}"#;
assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
}
#[test]
- fn test_pointer_move_action() {
+ fn test_deserialize_pointer_move_action() {
let expected = PointerMoveAction {
duration: Some(100),
origin: PointerOrigin::Pointer,
x: Some(5),
y: Some(10),
};
let data = r#"{"duration": 100, "origin": "pointer", "x": 5, "y": 10}"#;
let actual: PointerMoveAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_move_action_missing_origin_field() {
+ fn test_deserialize_pointer_move_action_missing_origin_field() {
let data = r#"{"duration": 100, "x": 5, "y": 10}"#;
assert!(serde_json::from_str::<PointerMoveAction>(&data).is_err());
}
#[test]
- fn test_pointer_move_action_missing_optional_fields() {
+ fn test_deserialize_pointer_move_action_missing_optional_fields() {
let expected = PointerMoveAction {
duration: None,
origin: PointerOrigin::Pointer,
x: None,
y: None,
};
let data = r#"{"origin": "pointer"}"#;
let actual: PointerMoveAction = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_origin() {
- // TODO: Fix with maybe custom serialize / deserialze method
- // similar like https://github.com/serde-rs/serde/issues/751#issuecomment-277580700
+ fn test_deserialize_pointer_origin() {
let data = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
let expected = PointerOrigin::Element(WebElement { id: "elem".into() });
assert_eq!(expected, actual);
let data = r#""pointer""#;
let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
let expected = PointerOrigin::Pointer;
@@ -648,23 +645,23 @@ mod test {
let data = r#""viewport""#;
let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
let expected = PointerOrigin::Viewport;
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_origin_invalid_type() {
+ fn test_deserialize_pointer_origin_invalid_type() {
let data = r#""invalid""#;
assert!(serde_json::from_str::<PointerOrigin>(&data).is_err());
}
#[test]
- fn test_pointer_type() {
+ fn test_deserialize_pointer_type() {
let data = r#""mouse""#;
let actual: PointerType = serde_json::from_str(&data).unwrap();
let expected = PointerType::Mouse;
assert_eq!(expected, actual);
let data = r#""pen""#;
let actual: PointerType = serde_json::from_str(&data).unwrap();
let expected = PointerType::Pen;
@@ -672,13 +669,13 @@ mod test {
let data = r#""touch""#;
let actual: PointerType = serde_json::from_str(&data).unwrap();
let expected = PointerType::Touch;
assert_eq!(expected, actual);
}
#[test]
- fn test_pointer_type_invalid_type() {
+ fn test_deserialize_pointer_type_invalid_type() {
let data = r#""invalid""#;
assert!(serde_json::from_str::<PointerType>(&data).is_err());
}
}
--- a/testing/webdriver/src/capabilities.rs
+++ b/testing/webdriver/src/capabilities.rs
@@ -57,34 +57,33 @@ pub trait CapabilitiesMatching {
///
/// Takes a BrowserCapabilites object and returns a set of capabilites that
/// are valid for that browser, if any, or None if there are no matching
/// capabilities.
fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
-> WebDriverResult<Option<Capabilities>>;
}
-#[derive(Debug, PartialEq, Serialize, Deserialize)]
-pub struct SpecNewSessionParametersWrapper {
- capabilities: SpecNewSessionParameters
-}
+// #[derive(Debug, PartialEq, Serialize, Deserialize)]
+// pub struct SpecNewSessionParametersWrapper {
+// capabilities: SpecNewSessionParameters
+// }
+
+// impl From<SpecNewSessionParametersWrapper> for SpecNewSessionParameters {
+// fn from(wrapper: SpecNewSessionParametersWrapper) -> SpecNewSessionParameters {
+// wrapper.capabilities
+// }
+// }
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct SpecNewSessionParameters {
pub alwaysMatch: Capabilities,
pub firstMatch: Vec<Capabilities>,
}
-impl From<SpecNewSessionParametersWrapper> for SpecNewSessionParameters {
- fn from(wrapper: SpecNewSessionParametersWrapper) -> SpecNewSessionParameters {
- wrapper.capabilities
- }
-}
-
-
impl SpecNewSessionParameters {
fn validate<T: BrowserCapabilities>(&self,
mut capabilities: Capabilities,
browser_capabilities: &T) -> WebDriverResult<Capabilities> {
// Filter out entries with the value `null`
let null_entries = capabilities
.iter()
.filter(|&(_, ref value)| **value == Value::Null)
@@ -492,24 +491,50 @@ impl<'a> From<&'a LegacyNewSessionParame
data.insert("requiredCapabilities".to_owned(), Value::Object(params.required.clone()));
Value::Object(data)
}
}
#[cfg(test)]
mod tests {
use serde_json::{self, Value};
- use super::{SpecNewSessionParameters, WebDriverResult};
+ use super::*;
fn validate_proxy(value: &str) -> WebDriverResult<()> {
let data = serde_json::from_str::<Value>(value).unwrap();
SpecNewSessionParameters::validate_proxy(&data)
}
#[test]
+ fn test_deserialize_spec_new_session_parameters_always() {
+ let data = r#"{"alwaysMatch":{"foo": "bar"}"#;
+ let actual: SpecNewSessionParameters = serde_json::from_str(&data).unwrap();
+ let mut expected = SpecNewSessionParameters {
+ alwaysMatch: Capabilities::new(),
+ firstMatch: vec!{ Capabilities::new() }
+ };
+ expected.alwaysMatch.insert("foo".into(), "bar".into());
+ assert_eq!(actual, expected);
+ }
+
+ #[test]
+ fn test_deserialize_spec_new_session_parameters_first() {
+ let data = r#"{"firstMatch":[{"foo": "bar"}]}"#;
+ let actual: SpecNewSessionParameters = serde_json::from_str(&data).unwrap();
+ let mut expected = SpecNewSessionParameters {
+ alwaysMatch: Capabilities::new(),
+ firstMatch: vec!{ Capabilities::new() }
+ };
+ println!("{:?}", actual);
+ assert!(false);
+ //expected.firstMatch.push({"foo".into(): Value::String("bar")});
+ //assert_eq!(actual, expected);
+ }
+
+ #[test]
fn test_validate_proxy() {
// proxy hosts
validate_proxy("{\"httpProxy\": \"127.0.0.1\"}").unwrap();
validate_proxy("{\"httpProxy\": \"127.0.0.1:\"}").unwrap();
validate_proxy("{\"httpProxy\": \"127.0.0.1:3128\"}").unwrap();
validate_proxy("{\"httpProxy\": \"localhost\"}").unwrap();
validate_proxy("{\"httpProxy\": \"localhost:3128\"}").unwrap();
validate_proxy("{\"httpProxy\": \"[2001:db8::1]\"}").unwrap();
--- a/testing/webdriver/src/command.rs
+++ b/testing/webdriver/src/command.rs
@@ -1,10 +1,10 @@
use actions::ActionsParameters;
-use capabilities::{SpecNewSessionParametersWrapper, SpecNewSessionParameters, LegacyNewSessionParameters,
+use capabilities::{SpecNewSessionParameters, LegacyNewSessionParameters,
CapabilitiesMatching, BrowserCapabilities, Capabilities};
use common::{Date, WebElement, FrameId, LocatorStrategy};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{Route, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use regex::Captures;
use serde_json::{self, Value, Map};
use std::convert::From;
@@ -102,17 +102,17 @@ impl<U: WebDriverExtensionRoute> WebDriv
params: &Captures,
raw_body: &str,
requires_body: bool)
-> WebDriverResult<WebDriverMessage<U>> {
let session_id = WebDriverMessage::<U>::get_session_id(params);
let body_data = try!(WebDriverMessage::<U>::decode_body(raw_body, requires_body));
let command = match match_type {
Route::NewSession => {
- let parameters: NewSessionParametersWrapper = serde_json::from_str(raw_body)?;
+ let parameters: NewSessionParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::NewSession(parameters.into())
},
Route::DeleteSession => WebDriverCommand::DeleteSession,
Route::Get => {
let parameters: GetParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::Get(parameters)
},
Route::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
@@ -440,47 +440,40 @@ impl <U:WebDriverExtensionRoute> From<We
/// Wrapper around the two supported variants of new session paramters
///
/// The Spec variant is used for storing spec-compliant parameters whereas
/// the legacy variant is used to store desiredCapabilities/requiredCapabilities
/// parameters, and is intended to minimise breakage as we transition users to
/// the spec design.
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(untagged)]
-pub enum NewSessionParametersWrapper {
- Spec(SpecNewSessionParametersWrapper),
- Legacy(LegacyNewSessionParameters),
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum NewSessionParameters {
Spec(SpecNewSessionParameters),
+ #[serde(rename = "capabilities")]
Legacy(LegacyNewSessionParameters),
}
-impl From<NewSessionParametersWrapper> for NewSessionParameters {
- fn from(wrapper: NewSessionParametersWrapper) -> NewSessionParameters {
- match wrapper {
- NewSessionParametersWrapper::Spec(x) => NewSessionParameters::Spec(x.into()),
- NewSessionParametersWrapper::Legacy(x) => NewSessionParameters::Legacy(x)
- }
- }
-}
+// impl From<NewSessionParametersWrapper> for NewSessionParameters {
+// fn from(wrapper: NewSessionParametersWrapper) -> NewSessionParameters {
+// match wrapper {
+// NewSessionParametersWrapper::Spec(x) => NewSessionParameters::Spec(x.into()),
+// NewSessionParametersWrapper::Legacy(x) => NewSessionParameters::Legacy(x)
+// }
+// }
+// }
-
-impl <'a> From<&'a NewSessionParameters> for Value {
- fn from(params: &'a NewSessionParameters) -> Value {
- match *params {
- NewSessionParameters::Spec(ref x) => x.into(),
- NewSessionParameters::Legacy(ref x) => x.into()
- }
- }
-}
+// impl <'a> From<&'a NewSessionParameters> for Value {
+// fn from(params: &'a NewSessionParameters) -> Value {
+// match *params {
+// NewSessionParameters::Spec(ref x) => x.into(),
+// NewSessionParameters::Legacy(ref x) => x.into()
+// }
+// }
+// }
impl CapabilitiesMatching for NewSessionParameters {
fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
-> WebDriverResult<Option<Capabilities>> {
match self {
&NewSessionParameters::Spec(ref x) => x.match_browser(browser_capabilities),
&NewSessionParameters::Legacy(ref x) => x.match_browser(browser_capabilities)
}
@@ -666,75 +659,81 @@ pub struct TakeScreenshotParameters {
}
#[cfg(test)]
mod tests {
use serde_json;
use super::*;
#[test]
- fn test_take_screenshot_no_element() {
+ fn test_deserialize_take_screenshot_no_element() {
+ let data = r#"{"element": null}"#;
+
let expected = TakeScreenshotParameters { element: None };
- let data = r#"{"element": null}"#;
let actual: TakeScreenshotParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_take_screenshot_with_element() {
+ fn test_deserialize_take_screenshot_with_element() {
+ let data = r#"{"element": {"element-6066-11e4-a52e-4f735466cecf":"elem"}}"#;
+
let expected = TakeScreenshotParameters {
element: Some(WebElement { id: "elem".into() }),
};
- let data = r#"{"element": {"element-6066-11e4-a52e-4f735466cecf":"elem"}}"#;
let actual: TakeScreenshotParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_window_rect() {
+ fn test_deserialize_window_rect_with_values() {
+ let data = r#"{"x": 0, "y": 1, "width": 2, "height": 3}"#;
+
let expected = WindowRectParameters {
x: Some(0i32),
y: Some(1i32),
width: Some(2i32),
height: Some(3i32),
};
- let data = r#"{"x": 0, "y": 1, "width": 2, "height": 3}"#;
let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_window_rect_nullable() {
+ fn test_deserialize_window_rect_without_values() {
+ let data = r#"{"x": null, "y": null, "width": null, "height": null}"#;
+
let expected = WindowRectParameters {
- x: Some(0i32),
+ x: None,
y: None,
- width: Some(2i32),
+ width: None,
height: None,
};
- let data = r#"{"x": 0, "y": null, "width": 2, "height": null}"#;
let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_window_rect_missing_fields() {
+ fn test_deserialize_window_rect_missing_fields() {
+ let data = r#"{}"#;
+
let expected = WindowRectParameters {
- x: Some(0i32),
+ x: None,
y: None,
- width: Some(2i32),
+ width: None,
height: None,
};
- let data = r#"{"x": 0, "width": 2}"#;
let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
assert_eq!(expected, actual);
}
#[test]
- fn test_window_rect_floats() {
+ fn test_deserialize_window_rect_floats() {
let data = r#"{"x": 1.1, "y": 2.2, "width": 3.3, "height": 4.4}"#;
+
assert!(serde_json::from_str::<WindowRectParameters>(&data).is_err());
}
}
--- a/testing/webdriver/src/common.rs
+++ b/testing/webdriver/src/common.rs
@@ -1,83 +1,43 @@
-use serde_json::{Value, Map};
+use serde_json::Value;
use std::convert::From;
+// TODO: Add custom errors to serde
use error::{WebDriverResult, WebDriverError, ErrorStatus};
pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";
pub static FRAME_KEY: &'static str = "frame-075b-4da1-b6ba-e579c2d3230a";
pub static WINDOW_KEY: &'static str = "window-fcc6-11e5-b4f8-330a88ab9d7f";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Date(pub u64);
impl Date {
pub fn new(timestamp: u64) -> Date {
Date(timestamp)
}
}
+// TODO: to be removed once command.rs is fixed
impl From<Date> for Value {
fn from(date: Date) -> Value {
let Date(x) = date;
x.into()
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct WebElement {
- #[serde(rename="element-6066-11e4-a52e-4f735466cecf")]
- pub id: String
-}
-
-impl WebElement {
- pub fn new(id: String) -> WebElement {
- WebElement {
- id: id
- }
- }
-
- pub fn from_json(data: &Value) -> WebDriverResult<WebElement> {
- let object = try_opt!(data.as_object(),
- ErrorStatus::InvalidArgument,
- "Could not convert webelement to object");
- let id_value = try_opt!(object.get(ELEMENT_KEY),
- ErrorStatus::InvalidArgument,
- "Could not find webelement key");
-
- let id = try_opt!(id_value.as_str(),
- ErrorStatus::InvalidArgument,
- "Could not convert web element to string").to_string();
-
- Ok(WebElement::new(id))
- }
-}
-
-impl <'a> From<&'a WebElement> for Value {
- fn from(elem: &'a WebElement) -> Value {
- let mut data = Map::new();
- data.insert(ELEMENT_KEY.to_string(), elem.id.clone().into());
- Value::Object(data)
- }
-}
-
-impl <T> From<T> for WebElement
- where T: Into<String> {
- fn from(data: T) -> WebElement {
- WebElement::new(data.into())
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
pub enum FrameId {
Short(u16),
Element(WebElement)
}
+// TODO: to be removed once command.rs is fixed
impl From<FrameId> for Value {
fn from(frame_id: FrameId) -> Value {
match frame_id {
FrameId::Short(x) => {
Value::Number(x.into())
},
FrameId::Element(ref x) => {
Value::String(x.id.clone())
@@ -95,35 +55,235 @@ pub enum LocatorStrategy {
#[serde(rename = "partial link text")]
PartialLinkText,
#[serde(rename = "tag name")]
TagName,
#[serde(rename = "xpath")]
XPath,
}
-impl LocatorStrategy {
- pub fn from_json(body: &Value) -> WebDriverResult<LocatorStrategy> {
- match try_opt!(body.as_str(),
- ErrorStatus::InvalidArgument,
- "Expected locator strategy as string") {
- "css selector" => Ok(LocatorStrategy::CSSSelector),
- "link text" => Ok(LocatorStrategy::LinkText),
- "partial link text" => Ok(LocatorStrategy::PartialLinkText),
- "tag name" => Ok(LocatorStrategy::TagName),
- "xpath" => Ok(LocatorStrategy::XPath),
- x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- format!("Unknown locator strategy {}", x)))
- }
- }
-}
+// impl LocatorStrategy {
+// pub fn from_json(body: &Value) -> WebDriverResult<LocatorStrategy> {
+// match try_opt!(body.as_str(),
+// ErrorStatus::InvalidArgument,
+// "Expected locator strategy as string") {
+// "css selector" => Ok(LocatorStrategy::CSSSelector),
+// "link text" => Ok(LocatorStrategy::LinkText),
+// "partial link text" => Ok(LocatorStrategy::PartialLinkText),
+// "tag name" => Ok(LocatorStrategy::TagName),
+// "xpath" => Ok(LocatorStrategy::XPath),
+// x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
+// format!("Unknown locator strategy {}", x)))
+// }
+// }
+// }
impl From<LocatorStrategy> for Value {
fn from(strategy: LocatorStrategy) -> Value {
match strategy {
LocatorStrategy::CSSSelector => "css selector",
LocatorStrategy::LinkText => "link text",
LocatorStrategy::PartialLinkText => "partial link text",
LocatorStrategy::TagName => "tag name",
LocatorStrategy::XPath => "xpath"
}.into()
}
}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct WebElement {
+ #[serde(rename="element-6066-11e4-a52e-4f735466cecf")]
+ pub id: String
+}
+
+impl WebElement {
+ pub fn new(id: String) -> WebElement {
+ WebElement {
+ id: id
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use serde_json;
+ use super::*;
+
+ #[test]
+ fn test_deserialize_date() {
+ let data = r#"1234"#;
+
+ let date = Date(1234);
+ let actual: Date = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, date);
+ }
+
+ #[test]
+ fn test_deserialize_date_invalid() {
+ let data = r#""2018-01-01""#;
+ // TODO: User correct error type
+ assert!(serde_json::from_str::<Date>(&data).is_err());
+ }
+
+ #[test]
+ fn test_serialize_date() {
+ let expected = r#"1234"#;
+
+ let date = Date(1234);
+ assert_eq!(serde_json::to_string(&date).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_deserialize_frame_id_short() {
+ let data = r#"1234"#;
+
+ let frame_id = FrameId::Short ( 1234 );
+ let actual: FrameId = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, frame_id);
+ }
+
+ #[test]
+ fn test_deserialize_frame_id_webelement() {
+ let data = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+
+ let frame_id = FrameId::Element ( WebElement::new("elem".into()) );
+ let actual: FrameId = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, frame_id);
+ }
+
+ #[test]
+ fn test_deserialize_frame_id_invalid() {
+ let data = r#"true"#;
+ // TODO: User correct error type
+ assert!(serde_json::from_str::<FrameId>(&data).is_err());
+ }
+
+ #[test]
+ fn test_serialize_frame_id_short() {
+ let expected = r#"1234"#;
+
+ let frame_id = FrameId::Short ( 1234 );
+ assert_eq!(serde_json::to_string(&frame_id).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_frame_id_webelement() {
+ let expected = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+
+ let frame_id = FrameId::Element ( WebElement::new("elem".into()) );
+ assert_eq!(serde_json::to_string(&frame_id).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_css_selector() {
+ let data = r#""css selector""#;
+
+ let strategy = LocatorStrategy::CSSSelector;
+ let actual: LocatorStrategy = serde_json::from_str(&data).unwrap();
+
+ assert_eq!(actual, strategy);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_link_text() {
+ let data = r#""link text""#;
+
+ let strategy = LocatorStrategy::LinkText;
+ let actual: LocatorStrategy = serde_json::from_str(&data).unwrap();
+
+ assert_eq!(actual, strategy);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_partial_link_text() {
+ let data = r#""partial link text""#;
+
+ let strategy = LocatorStrategy::PartialLinkText;
+ let actual: LocatorStrategy = serde_json::from_str(&data).unwrap();
+
+ assert_eq!(actual, strategy);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_tag_name() {
+ let data = r#""tag name""#;
+
+ let strategy = LocatorStrategy::TagName;
+ let actual: LocatorStrategy = serde_json::from_str(&data).unwrap();
+
+ assert_eq!(actual, strategy);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_xpath() {
+ let data = r#""xpath""#;
+
+ let strategy = LocatorStrategy::XPath;
+ let actual: LocatorStrategy = serde_json::from_str(&data).unwrap();
+
+ assert_eq!(actual, strategy);
+ }
+
+ #[test]
+ fn test_deserialize_locator_strategy_invalid() {
+ let data = r#""foo""#;
+ assert!(serde_json::from_str::<LocatorStrategy>(&data).is_err());
+ }
+
+ #[test]
+ fn test_serialize_locator_strategy_css_selector() {
+ let expected = r#""css selector""#;
+ let strategy = LocatorStrategy::CSSSelector;
+ assert_eq!(serde_json::to_string(&strategy).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_locator_strategy_link_text() {
+ let expected = r#""link text""#;
+ let strategy = LocatorStrategy::LinkText;
+ assert_eq!(serde_json::to_string(&strategy).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_locator_strategy_partial_link_text() {
+ let expected = r#""partial link text""#;
+ let strategy = LocatorStrategy::PartialLinkText;
+ assert_eq!(serde_json::to_string(&strategy).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_locator_strategy_tag_name() {
+ let expected = r#""tag name""#;
+ let strategy = LocatorStrategy::TagName;
+ assert_eq!(serde_json::to_string(&strategy).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_locator_strategy_xpath() {
+ let expected = r#""xpath""#;
+ let strategy = LocatorStrategy::XPath;
+ assert_eq!(serde_json::to_string(&strategy).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_deserialize_webelement() {
+ let data = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+
+ let elem = WebElement::new("elem".into());
+ let actual: WebElement = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, elem);
+ }
+
+ #[test]
+ fn test_deserialize_webelement_invalid() {
+ let data = r#"{"elem-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+ // TODO: User correct error type
+ assert!(serde_json::from_str::<WebElement>(&data).is_err());
+ }
+
+ #[test]
+ fn test_serialize_webelement() {
+ let expected = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+
+ let elem = WebElement::new("elem".into());
+ assert_eq!(serde_json::to_string(&elem).unwrap(), expected);
+ }
+}
--- a/testing/webdriver/src/error.rs
+++ b/testing/webdriver/src/error.rs
@@ -1,18 +1,19 @@
use hyper::status::StatusCode;
use base64::DecodeError;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use serde_json::{Value, Error as SerdeError};
use std::borrow::Cow;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io;
-use serde_json::{self, Value, Error as SerdeError, Map};
-#[derive(Debug, PartialEq, Serialize)]
+#[derive(Debug, PartialEq)]
pub enum ErrorStatus {
/// The [`ElementClick`] command could not be completed because the
/// [element] receiving the events is obscuring the element that was
/// requested clicked.
///
/// [`ElementClick`]:
/// ../command/enum.WebDriverCommand.html#variant.ElementClick
/// [element]: ../common/struct.WebElement.html
@@ -134,16 +135,66 @@ pub enum ErrorStatus {
UnknownPath,
/// Indicates that a [command] that should have executed properly is not
/// currently supported.
UnsupportedOperation,
}
+impl<'de> Deserialize<'de> for ErrorStatus {
+ fn deserialize<D>(deserializer: D) -> Result<ErrorStatus, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ use self::ErrorStatus::*;
+
+ let error_status = match Deserialize::deserialize(deserializer)? {
+ "element click intercepted" => ElementClickIntercepted,
+ "element not interactable" | "element not visible" => ElementNotInteractable,
+ "element not selectable" => ElementNotSelectable,
+ "insecure certificate" => InsecureCertificate,
+ "invalid argument" => InvalidArgument,
+ "invalid cookie domain" => InvalidCookieDomain,
+ "invalid coordinates" | "invalid element coordinates" => InvalidCoordinates,
+ "invalid element state" => InvalidElementState,
+ "invalid selector" => InvalidSelector,
+ "invalid session id" => InvalidSessionId,
+ "javascript error" => JavascriptError,
+ "move target out of bounds" => MoveTargetOutOfBounds,
+ "no such alert" => NoSuchAlert,
+ "no such element" => NoSuchElement,
+ "no such frame" => NoSuchFrame,
+ "no such window" => NoSuchWindow,
+ "script timeout" => ScriptTimeout,
+ "session not created" => SessionNotCreated,
+ "stale element reference" => StaleElementReference,
+ "timeout" => Timeout,
+ "unable to capture screen" => UnableToCaptureScreen,
+ "unable to set cookie" => UnableToSetCookie,
+ "unexpected alert open" => UnexpectedAlertOpen,
+ "unknown command" => UnknownCommand,
+ "unknown error" => UnknownError,
+ "unsupported operation" => UnsupportedOperation,
+ _ => UnknownError,
+ };
+
+ Ok(error_status)
+ }
+}
+
+impl Serialize for ErrorStatus {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.error_code().serialize(serializer)
+ }
+}
+
impl ErrorStatus {
/// Returns the string serialisation of the error type.
pub fn error_code(&self) -> &'static str {
use self::ErrorStatus::*;
match *self {
ElementClickIntercepted => "element click intercepted",
ElementNotInteractable => "element not interactable",
ElementNotSelectable => "element not selectable",
@@ -209,109 +260,91 @@ impl ErrorStatus {
UnknownError => InternalServerError,
UnknownMethod => MethodNotAllowed,
UnknownPath => NotFound,
UnsupportedOperation => InternalServerError,
}
}
}
-/// Deserialises error type from string.
-impl From<String> for ErrorStatus {
- fn from(s: String) -> ErrorStatus {
- use self::ErrorStatus::*;
- match &*s {
- "element click intercepted" => ElementClickIntercepted,
- "element not interactable" | "element not visible" => ElementNotInteractable,
- "element not selectable" => ElementNotSelectable,
- "insecure certificate" => InsecureCertificate,
- "invalid argument" => InvalidArgument,
- "invalid cookie domain" => InvalidCookieDomain,
- "invalid coordinates" | "invalid element coordinates" => InvalidCoordinates,
- "invalid element state" => InvalidElementState,
- "invalid selector" => InvalidSelector,
- "invalid session id" => InvalidSessionId,
- "javascript error" => JavascriptError,
- "move target out of bounds" => MoveTargetOutOfBounds,
- "no such alert" => NoSuchAlert,
- "no such element" => NoSuchElement,
- "no such frame" => NoSuchFrame,
- "no such window" => NoSuchWindow,
- "script timeout" => ScriptTimeout,
- "session not created" => SessionNotCreated,
- "stale element reference" => StaleElementReference,
- "timeout" => Timeout,
- "unable to capture screen" => UnableToCaptureScreen,
- "unable to set cookie" => UnableToSetCookie,
- "unexpected alert open" => UnexpectedAlertOpen,
- "unknown command" => UnknownCommand,
- "unknown error" => UnknownError,
- "unsupported operation" => UnsupportedOperation,
- _ => UnknownError,
- }
- }
-}
-
pub type WebDriverResult<T> = Result<T, WebDriverError>;
-#[derive(Debug, Serialize)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(remote = "Self")]
pub struct WebDriverError {
pub error: ErrorStatus,
pub message: Cow<'static, str>,
pub stack: Cow<'static, str>,
+ pub data: Option<Value>,
+ #[serde(skip)]
pub delete_session: bool,
}
+impl Serialize for WebDriverError {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ #[derive(Serialize)]
+ struct Wrapper<'a> {
+ #[serde(with = "WebDriverError")]
+ value: &'a WebDriverError,
+ }
+
+ Wrapper { value: self }.serialize(serializer)
+ }
+}
+
+impl<'de> Deserialize<'de> for WebDriverError {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ #[derive(Deserialize)]
+ struct Wrapper {
+ #[serde(with = "WebDriverError")]
+ value: WebDriverError,
+ }
+
+ Wrapper::deserialize(deserializer).map(|wrapper| wrapper.value)
+ }
+}
+
impl WebDriverError {
pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
where S: Into<Cow<'static, str>>
{
WebDriverError {
error: error,
message: message.into(),
stack: "".into(),
+ data: None,
delete_session: false,
}
}
pub fn new_with_stack<S>(error: ErrorStatus, message: S, stack: S) -> WebDriverError
where S: Into<Cow<'static, str>>
{
WebDriverError {
error: error,
message: message.into(),
stack: stack.into(),
+ data: None,
delete_session: false,
}
}
pub fn error_code(&self) -> &'static str {
self.error.error_code()
}
pub fn http_status(&self) -> StatusCode {
self.error.http_status()
}
-
- pub fn to_json_string(&self) -> String {
- serde_json::to_string(&Value::from(self)).unwrap()
- }
-}
-
-impl <'a> From<&'a WebDriverError> for Value {
- fn from(err: &'a WebDriverError) -> Value {
- let mut data = Map::new();
- data.insert("error".into(), err.error_code().into());
- data.insert("message".into(), err.message.clone().into());
- data.insert("stacktrace".into(),
- format!("{:?}", err.stack).into());
- let mut wrapper = Map::new();
- wrapper.insert("value".into(), Value::Object(data));
- Value::Object(wrapper)
- }
}
impl Error for WebDriverError {
fn description(&self) -> &str {
self.error_code()
}
fn cause(&self) -> Option<&Error> {
@@ -343,8 +376,108 @@ impl From<DecodeError> for WebDriverErro
}
}
impl From<Box<Error>> for WebDriverError {
fn from(err: Box<Error>) -> WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
}
}
+
+#[cfg(test)]
+mod tests {
+ use serde_json;
+ use super::*;
+
+ #[test]
+ fn test_deserialize_webdriver_error_with_optional() {
+ let data = r#"{"value":{"error":"unknown error","message":"foo bar","stack":"foo\nbar","data":"foobar"}}"#;
+
+ let error = WebDriverError {
+ error: ErrorStatus::UnknownError,
+ message: "foo bar".into(),
+ stack: "foo\nbar".into(),
+ data: Some("foobar".into()),
+ delete_session: false,
+ };
+
+ let actual: WebDriverError = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, error);
+ }
+
+ #[test]
+ fn test_deserialize_webdriver_error_without_optional() {
+ let data = r#"{"value":{"error":"unknown error","message":"foo bar","stack":"foo\nbar","data":null}}"#;
+
+ let error = WebDriverError {
+ error: ErrorStatus::UnknownError,
+ message: "foo bar".into(),
+ stack: "foo\nbar".into(),
+ data: None,
+ delete_session: false,
+ };
+
+
+ let actual: WebDriverError = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, error);
+ }
+
+ #[test]
+ fn test_deserialize_webdriver_error_invalid() {
+ let data = r#"{"error":"unknown","message":"foo bar","stack":"foo\nbar","data":null}"#;
+ assert!(serde_json::from_str::<WebDriverError>(&data).is_err());
+ }
+
+ #[test]
+ fn test_serialize_webdriver_error_with_optional() {
+ let expected = r#"{"value":{"error":"unknown error","message":"foo bar","stack":"foo\nbar","data":"foobar"}}"#;
+
+ let error = WebDriverError {
+ error: ErrorStatus::UnknownError,
+ message: "foo bar".into(),
+ stack: "foo\nbar".into(),
+ data: Some("foobar".into()),
+ delete_session: true,
+ };
+
+ assert_eq!(serde_json::to_string(&error).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_webdriver_error_without_optional() {
+ let expected = r#"{"value":{"error":"unknown error","message":"foo bar","stack":"foo\nbar","data":null}}"#;
+
+ let error = WebDriverError {
+ error: ErrorStatus::UnknownError,
+ message: "foo bar".into(),
+ stack: "foo\nbar".into(),
+ data: None,
+ delete_session: false,
+ };
+
+ assert_eq!(serde_json::to_string(&error).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_deserialize_error_status_specific() {
+ let error = ErrorStatus::InvalidSessionId;
+
+ let data = format!(r#""{}""#, error.error_code());
+ let actual: ErrorStatus = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, ErrorStatus::InvalidSessionId);
+ }
+
+ #[test]
+ fn test_deserialize_error_status_unknown() {
+ let data = r#""foo bar""#;
+ let actual: ErrorStatus = serde_json::from_str(&data).unwrap();
+ assert_eq!(actual, ErrorStatus::UnknownError);
+ }
+
+ #[test]
+ fn test_serialize_error_status() {
+ let error = ErrorStatus::UnknownError;
+ let expected = format!(r#""{}""#, error.error_code());
+
+
+ assert_eq!(serde_json::to_string(&error).unwrap(), expected);
+ }
+}
\ No newline at end of file
--- a/testing/webdriver/src/response.rs
+++ b/testing/webdriver/src/response.rs
@@ -1,10 +1,10 @@
use common::Date;
-use serde::ser::{Serialize, Serializer};
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
#[derive(Debug, Serialize)]
#[serde(untagged, remote = "Self")]
pub enum WebDriverResponse {
CloseWindow(CloseWindowResponse),
Cookie(CookieResponse),
Cookies(CookiesResponse),
@@ -27,21 +27,45 @@ impl Serialize for WebDriverResponse {
#[serde(with = "WebDriverResponse")]
value: &'a WebDriverResponse,
}
Wrapper { value: self }.serialize(serializer)
}
}
-#[derive(Debug, Serialize)]
+impl<'de> Deserialize<'de> for WebDriverResponse {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ #[derive(Deserialize)]
+ struct Wrapper {
+ #[serde(with = "WebDriverResponse")]
+ value: WebDriverResponse,
+ }
+
+ Wrapper::deserialize(deserializer).map(|wrapper| wrapper.value)
+ }
+}
+
+#[derive(Debug)]
pub struct CloseWindowResponse {
pub window_handles: Vec<String>,
}
+impl Serialize for CloseWindowResponse {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.window_handles.serialize(serializer)
+ }
+}
+
impl CloseWindowResponse {
pub fn new(handles: Vec<String>) -> CloseWindowResponse {
CloseWindowResponse { window_handles: handles }
}
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct CookieResponse {
@@ -64,19 +88,28 @@ impl CookieResponse {
domain: domain,
expiry: expiry,
secure: secure,
httpOnly: http_only
}
}
}
-#[derive(Debug, Serialize)]
+#[derive(Debug)]
pub struct CookiesResponse {
- pub value: Vec<CookieResponse>,
+ pub cookies: Vec<CookieResponse>,
+}
+
+impl Serialize for CookiesResponse {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.cookies.serialize(serializer)
+ }
}
#[derive(Debug, Serialize)]
pub struct ElementRectResponse {
/// X axis position of the top-left corner of the element relative
// to the current browsing context’s document element in CSS reference
// pixels.
pub x: f64,
@@ -137,21 +170,30 @@ impl TimeoutsResponse {
TimeoutsResponse {
script: script,
pageLoad: page_load,
implicit: implicit,
}
}
}
-#[derive(Debug, Serialize)]
+#[derive(Debug)]
pub struct ValueResponse {
pub value: Value
}
+impl Serialize for ValueResponse {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.value.serialize(serializer)
+ }
+}
+
impl ValueResponse {
pub fn new(value: Value) -> ValueResponse {
ValueResponse {
value: value
}
}
}
@@ -178,100 +220,120 @@ pub struct WindowRectResponse {
pub height: i32,
}
#[cfg(test)]
mod tests {
use serde_json;
use super::*;
- //#[test]
+ #[test]
fn test_serialize_close_window_response() {
let expected = r#"{"value":["1234"]}"#;
let response = WebDriverResponse::CloseWindow(
CloseWindowResponse::new(vec!["1234".into()]));
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
#[test]
- fn test_serialize_cookie_response() {
+ fn test_serialize_cookie_response_with_optional() {
+ let expected = r#"{"value":{"name":"foo","value":"bar","path":"/","domain":"foo.bar","expiry":123,"secure":true,"httpOnly":false}}"#;
+
+ let response = WebDriverResponse::Cookie(CookieResponse {
+ name: "foo".into(),
+ value: "bar".into(),
+ path: Some("/".into()),
+ domain: Some("foo.bar".into()),
+ expiry: Some(Date::new(123)),
+ secure: true,
+ httpOnly: false,
+ });
+ assert_eq!(serde_json::to_string(&response).unwrap(), expected);
+ }
+
+ #[test]
+ fn test_serialize_cookie_response_without_optional() {
let expected = r#"{"value":{"name":"foo","value":"bar","path":"/","domain":null,"expiry":null,"secure":true,"httpOnly":false}}"#;
let response = WebDriverResponse::Cookie(CookieResponse {
name: "foo".into(),
value: "bar".into(),
path: Some("/".into()),
domain: None,
expiry: None,
secure: true,
httpOnly: false,
});
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
- //#[test]
+ #[test]
fn test_serialize_cookies_response() {
let expected = r#"{"value":[{"name":"name","value":"value","path":"/","domain":null,"expiry":null,"secure":true,"httpOnly":false}]}"#;
let response = WebDriverResponse::Cookies(CookiesResponse {
- value: vec![
+ cookies: vec![
CookieResponse {
name: "name".into(),
value: "value".into(),
path: Some("/".into()),
domain: None,
expiry: None,
secure: true,
httpOnly: false,
}
]});
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
#[test]
fn test_serialize_delete_session_response() {
- // TODO
+ let expected = r#"{"value":null}"#;
+
+ let response = WebDriverResponse::DeleteSession;
+ assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
#[test]
fn test_serialize_element_rect_response() {
let expected = r#"{"value":{"x":0.0,"y":1.0,"width":2.0,"height":3.0}}"#;
let response = WebDriverResponse::ElementRect(
ElementRectResponse {
x: 0f64,
y: 1f64,
width: 2f64,
height: 3f64,
});
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
- //#[test]
- fn test_serialize_generic_response() {
+ #[test]
+ fn test_serialize_generic_value_response() {
let expected = r#"{"value":{"example":["test"]}}"#;
let mut value = serde_json::Map::new();
value.insert("example".into(), Value::Array(
vec![Value::String("test".into())]));
let response = WebDriverResponse::Generic(
ValueResponse::new(Value::Object(value)));
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
#[test]
fn test_serialize_new_session_response() {
let expected = r#"{"value":{"sessionId":"id","capabilities":{}}}"#;
- let response = WebDriverResponse::NewSession(NewSessionResponse::new(
- "id".into(),
- Value::Object(serde_json::Map::new())
+ let response = WebDriverResponse::NewSession(
+ NewSessionResponse::new(
+ "id".into(),
+ Value::Object(serde_json::Map::new())
));
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
#[test]
fn test_serialize_timeouts_response() {
let expected = r#"{"value":{"script":1,"pageLoad":2,"implicit":3}}"#;
@@ -297,22 +359,9 @@ mod tests {
x: 0i32,
y: 1i32,
width: 2i32,
height: 3i32,
});
assert_eq!(serde_json::to_string(&response).unwrap(), expected);
}
-
- #[test]
- fn test_serialize_value_response() {
- let expected = r#"{"value":{"example":["test"]}}"#;
-
- let mut value = serde_json::Map::new();
- value.insert("example".into(), Value::Array(
- vec![Value::String("test".into())]));
-
- let response = ValueResponse::new(Value::Object(value));
-
- assert_eq!(expected, serde_json::to_string(&response).unwrap());
- }
}