--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,65 +1,20 @@
use common::WebElement;
use serde::{Deserialize, Deserializer};
+use serde::ser::{Serialize, Serializer};
use serde_json::{Value, Map};
use std::default::Default;
-#[derive(Debug, PartialEq, Serialize)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ActionSequence {
pub id: Option<String>,
pub actions: ActionsType
}
-impl<'de> Deserialize<'de> for ActionSequence {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where D: Deserializer<'de>
- {
- #[derive(Deserialize)]
- #[serde(tag = "type", rename_all = "lowercase")]
- enum Helper {
- Null {
- id: Option<String>,
- actions: Vec<NullActionItem>,
- },
- Key {
- id: Option<String>,
- actions: Vec<KeyActionItem>,
- },
- Pointer {
- id: Option<String>,
- #[serde(default)]
- parameters: PointerActionParameters,
- actions: Vec<PointerActionItem>,
- },
- }
-
- match Helper::deserialize(deserializer)? {
- Helper::Null { id, actions } => {
- Ok(ActionSequence {
- id: id,
- actions: ActionsType::Null{actions},
- })
- }
- Helper::Key { id, actions } => {
- Ok(ActionSequence {
- id: id,
- actions: ActionsType::Key{actions},
- })
- }
- Helper::Pointer { id, parameters, actions } => {
- Ok(ActionSequence {
- id: id,
- actions: ActionsType::Pointer{parameters, actions},
- })
- }
- }
- }
-}
-
impl<'a> From<&'a ActionSequence> for Value {
fn from(params: &'a ActionSequence) -> Value {
let mut data: Map<String, Value> = Map::new();
data.insert("id".into(), params.id.clone().map(|x| x.into()).unwrap_or(Value::Null));
let (action_type, actions) = match params.actions {
ActionsType::Null {ref actions} => {
("none",
actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
@@ -75,17 +30,18 @@ impl<'a> From<&'a ActionSequence> for Va
}
};
data.insert("type".into(), action_type.into());
data.insert("actions".into(), actions.into());
Value::Object(data)
}
}
-#[derive(Debug, PartialEq, Serialize)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged, rename_all = "lowercase")]
pub enum ActionsType {
Null {actions: Vec<NullActionItem>},
Key {actions: Vec<KeyActionItem>},
Pointer {parameters: PointerActionParameters, actions:Vec<PointerActionItem>}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all="lowercase")]
@@ -168,17 +124,17 @@ impl<'a> From<&'a PointerActionItem> for
match *params {
PointerActionItem::General(ref x) => x.into(),
PointerActionItem::Pointer(ref x) => x.into()
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
-#[serde(tag = "type")]
+#[serde(tag = "type", rename_all="lowercase")]
pub enum GeneralAction {
Pause(PauseAction)
}
impl<'a> From<&'a GeneralAction> for Value {
fn from(params: &'a GeneralAction) -> Value {
match *params {
GeneralAction::Pause(ref x) => x.into()
@@ -248,23 +204,40 @@ impl<'a> From<&'a KeyDownAction> for Val
"keyDown".into());
data.insert("value".to_owned(),
params.value.to_string().into());
Value::Object(data)
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
-#[serde(untagged, rename_all="lowercase")]
pub enum PointerOrigin {
+ #[serde(rename = "viewport")]
Viewport,
+ #[serde(rename = "pointer")]
Pointer,
+ #[serde(
+ rename = "element-6066-11e4-a52e-4f735466cecf",
+ serialize_with = "serialize_webelement_id",
+ deserialize_with = "deserialize_webelement_id")]
Element(WebElement),
}
+fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
+ where S: Serializer
+{
+ element.id.serialize(serializer)
+}
+
+fn deserialize_webelement_id<'de, D>(deserializer: D) -> Result<WebElement, D::Error>
+ where D: Deserializer<'de>
+{
+ String::deserialize(deserializer).map(|id| WebElement { id })
+}
+
impl<'a> From<&'a PointerOrigin> for Value {
fn from(params: &'a PointerOrigin) -> Value {
match *params {
PointerOrigin::Viewport => "viewport".into(),
PointerOrigin::Pointer => "pointer".into(),
PointerOrigin::Element(ref x) => x.into(),
}
}
@@ -342,104 +315,512 @@ pub struct PointerMoveAction {
pub x: Option<i64>,
pub y: Option<i64>
}
impl<'a> From<&'a PointerMoveAction> for Value {
fn from(params: &'a PointerMoveAction) -> Value {
let mut data = Map::new();
data.insert("type".to_owned(), "pointerMove".into());
+ data.insert("origin".to_owned(), (¶ms.origin).into());
+
if let Some(duration) = params.duration {
data.insert("duration".to_owned(),
duration.into());
}
-
- data.insert("origin".to_owned(), (¶ms.origin).into());
-
if let Some(x) = params.x {
data.insert("x".to_owned(), x.into());
}
if let Some(y) = params.y {
data.insert("y".to_owned(), y.into());
}
Value::Object(data)
}
}
#[cfg(test)]
mod test {
use serde_json;
- use command::ActionsParameters;
- use common::WebElement;
use super::*;
#[test]
- fn test_pointer_no_parameters() {
- let expected = ActionsParameters {
- actions: vec![
- ActionSequence {
- id: None,
- actions: ActionsType::Pointer {
- parameters: PointerActionParameters {
- pointer_type: PointerType::Mouse
- },
- actions: vec!{
- PointerActionItem::Pointer (
- PointerAction::Down (
- PointerDownAction {
- button: 0
- }
- )
- ),
- PointerActionItem::Pointer(
- PointerAction::Move (
- PointerMoveAction {
- duration: Some(100),
- x: Some(5),
- y: Some(10),
- origin: PointerOrigin::Pointer
- }
- )
- ),
- PointerActionItem::Pointer(
- PointerAction::Move (
- PointerMoveAction {
- duration: Some(200),
- x: Some(10),
- y: Some(20),
- origin: PointerOrigin::Element(
- WebElement {
- id: "elem".into()
- }
- )
- }
- )
- ),
- PointerActionItem::Pointer(
- PointerAction::Up (
- PointerUpAction {
- button: 0
- }
- )
- ),
- PointerActionItem::Pointer(
- PointerAction::Cancel
- ),
- }
- }
+ fn test_action_sequence_null() {
+ let expected = ActionSequence {
+ id: Some("none".into()),
+ actions: ActionsType::Null {
+ actions: vec!{
+ NullActionItem::General (
+ GeneralAction::Pause ( PauseAction { duration: 1 } )
+ )
+ }
+ }
+ };
+
+ let data = r#"{
+ "id": "none",
+ "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() {
+ let expected = ActionSequence {
+ id: Some("some_key".into()),
+ actions: ActionsType::Key {
+ actions: vec!{
+ KeyActionItem::Key (
+ KeyAction::Down ( KeyDownAction { value: String::from("f") } )
+ )
}
- ]
+ }
+ };
+
+ let data = r#"{
+ "id": "some_key",
+ "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() {
+ let expected = ActionSequence {
+ id: Some("some_pointer".into()),
+ actions: ActionsType::Pointer {
+ parameters: PointerActionParameters {
+ pointer_type: PointerType::Mouse
+ },
+ actions: vec!{
+ PointerActionItem::Pointer (
+ PointerAction::Down ( PointerDownAction { button: 0 } )
+ ),
+ PointerActionItem::Pointer (
+ PointerAction::Move ( PointerMoveAction {
+ origin: PointerOrigin::Pointer,
+ duration: None,
+ x: Some(10),
+ y: Some(20),
+ })
+ ),
+ PointerActionItem::Pointer (
+ PointerAction::Up ( PointerUpAction { button: 0 } )
+ ),
+ }
+ }
+ };
+
+ let data = r#"{
+ "id": "some_pointer",
+ "actions": {
+ "parameters": {
+ "pointerType": "mouse"
+ },
+ "actions": [
+ {"type": "pointerDown", "button": 0},
+ {"type": "pointerMove", "origin":"pointer", "x": 10, "y": 20},
+ {"type": "pointerUp", "button": 0}
+ ]
+ }
+ }"#;
+ let actual: ActionSequence = serde_json::from_str(&data).unwrap();
+ assert_eq!(expected, actual);
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ let expected = ActionsType::Pointer {
+ parameters: PointerActionParameters {
+ pointer_type: PointerType::Mouse
+ },
+ actions: vec!{
+ PointerActionItem::Pointer (
+ PointerAction::Down ( PointerDownAction { button: 1 } )
+ )
+ }
};
let data = r#"{
-"actions": [
- {"type": "pointer", "actions": [
- {"type": "pointerDown", "button": 0},
- {"type": "pointerMove", "x": 5, "y": 10, "origin": "relative"},
- {"type": "pointerMove", "x": 5, "y": 10, "origin": {"element-6066-11e4-a52e-4f735466cecf": "elem"}},
- {"type": "pointerUp", "button": 0},
- {"type": "pointerCancel"}
- ]
-}]}"#;
- let actual: ActionsParameters = serde_json::from_str(&data).unwrap();
+ "parameters": {"pointerType": "mouse"},
+ "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() {
+ 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() {
+ let data = r#"{"type": "invalid"}"#;
+ assert!(serde_json::from_str::<NullActionItem>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ let data = r#"{"type": "invalid"}"#;
+ assert!(serde_json::from_str::<KeyActionItem>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ let data = r#"{"type": "invalid", "value": "f"}"#;
+ assert!(serde_json::from_str::<KeyAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_key_action_missing_type() {
+ let data = r#"{"value": "f"}"#;
+ assert!(serde_json::from_str::<KeyAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ let data = r#"{"type": "keyDown"}"#;
+ assert!(serde_json::from_str::<KeyDownAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ let data = r#"{"type": "keyDown"}"#;
+ assert!(serde_json::from_str::<KeyUpAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ let data = r#"{"type": "pointerInvalid"}"#;
+ assert!(serde_json::from_str::<PointerActionItem>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ 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() {
+ let data = r#"{}"#;
+ assert!(serde_json::from_str::<PauseAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ 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() {
+ 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() {
+ let data = r#"{"type": "pointerInvald"}"#;
+ assert!(serde_json::from_str::<PointerAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_pointer_action_missing_type() {
+ let data = r#"{"button": 1}"#;
+ assert!(serde_json::from_str::<PointerAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ let data = r#"{"duration": 100}"#;
+ assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_pointer_down_action_missing_button_field() {
+ let data = r#"{}"#;
+ assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ let data = r#"{"duration": 100}"#;
+ assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_pointer_up_action_missing_button_field() {
+ let data = r#"{}"#;
+ assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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() {
+ 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() {
+ 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
+ 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;
+ assert_eq!(expected, actual);
+
+ 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() {
+ let data = r#""invalid""#;
+ assert!(serde_json::from_str::<PointerOrigin>(&data).is_err());
+ }
+
+ #[test]
+ fn test_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;
+ assert_eq!(expected, actual);
+
+ 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() {
+ let data = r#""invalid""#;
+ assert!(serde_json::from_str::<PointerType>(&data).is_err());
+ }
}