Bug 1396821 - Always use serde for serialization and deserailization. draft
authorJames Graham <james@hoppipolla.co.uk>
Thu, 21 Sep 2017 15:50:29 +0200
changeset 668501 6af7a1189067c4c5b1a879cb1176bd6be2ab4ce1
parent 668500 d7f29dde61cffee398c6fe9877dc5109a7a52d12
child 732725 1599457ba3921d2c93504de07280937c0bb7cd13
push id81069
push userbmo:hskupin@gmail.com
push dateThu, 21 Sep 2017 19:15:05 +0000
bugs1396821
milestone57.0a1
Bug 1396821 - Always use serde for serialization and deserailization. MozReview-Commit-ID: KnCml7nALDA
testing/webdriver/src/actions.rs
testing/webdriver/src/capabilities.rs
testing/webdriver/src/command.rs
testing/webdriver/src/common.rs
testing/webdriver/src/lib.rs
testing/webdriver/src/response.rs
--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,646 +1,353 @@
-use command::Parameters;
 use common::WebElement;
-use error::{WebDriverResult, WebDriverError, ErrorStatus};
+use serde::{Deserialize, Deserializer};
 use serde_json::{Value, Map};
 use std::default::Default;
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize)]
 pub struct ActionSequence {
     pub id: Option<String>,
     pub actions: ActionsType
 }
 
-impl Parameters for ActionSequence {
-    fn from_json(body: &Value) -> WebDriverResult<ActionSequence> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Actions chain was not an object");
-
-        let type_name = try_opt!(try_opt!(data.get("type"),
-                                          ErrorStatus::InvalidArgument,
-                                          "Missing type parameter").as_str(),
-                                 ErrorStatus::InvalidArgument,
-                                 "Parameter ;type' was not a string");
+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>,
+            },
+        }
 
-        let id = match data.get("id") {
-            Some(x) => Some(try_opt!(x.as_str(),
-                                     ErrorStatus::InvalidArgument,
-                                     "Parameter 'id' was not a string").to_owned()),
-            None => None
-        };
-
-
-        // Note that unlike the spec we get the pointer parameters in ActionsType::from_json
-
-        let actions = match type_name {
-            "none" | "key" | "pointer" => try!(ActionsType::from_json(&body)),
-            _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                                "Invalid action type"))
-        };
-
-        Ok(ActionSequence {
-            id: id.into(),
-            actions: actions
-        })
+        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) => {
+            ActionsType::Null {ref actions} => {
                 ("none",
                  actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
             }
-            ActionsType::Key(ref actions) => {
+            ActionsType::Key {ref actions} => {
                 ("key",
                  actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
             }
-            ActionsType::Pointer(ref parameters, ref actions) => {
+            ActionsType::Pointer {ref parameters, ref actions} => {
                 data.insert("parameters".into(), parameters.into());
                 ("pointer",
                  actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
             }
         };
         data.insert("type".into(), action_type.into());
         data.insert("actions".into(), actions.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize)]
 pub enum ActionsType {
-    Null(Vec<NullActionItem>),
-    Key(Vec<KeyActionItem>),
-    Pointer(PointerActionParameters, Vec<PointerActionItem>)
+    Null {actions: Vec<NullActionItem>},
+    Key {actions: Vec<KeyActionItem>},
+    Pointer {parameters: PointerActionParameters, actions:Vec<PointerActionItem>}
 }
 
-impl Parameters for ActionsType {
-    fn from_json(body: &Value) -> WebDriverResult<ActionsType> {
-        // These unwraps are OK as long as this is only called from ActionSequence::from_json
-        let data = body.as_object().expect("Body should be a JSON Object");
-        let actions_type = body.get("type").and_then(|x| x.as_str()).expect("Type should be a string");
-        let actions_chain = try_opt!(try_opt!(data.get("actions"),
-                                              ErrorStatus::InvalidArgument,
-                                              "Missing actions parameter").as_array(),
-                                     ErrorStatus::InvalidArgument,
-                                     "Parameter 'actions' was not an array");
-        match actions_type {
-            "none" => {
-                let mut actions = Vec::with_capacity(actions_chain.len());
-                for action_body in actions_chain.iter() {
-                    actions.push(try!(NullActionItem::from_json(action_body)));
-                };
-                Ok(ActionsType::Null(actions))
-            },
-            "key" => {
-                let mut actions = Vec::with_capacity(actions_chain.len());
-                for action_body in actions_chain.iter() {
-                    actions.push(try!(KeyActionItem::from_json(action_body)));
-                };
-                Ok(ActionsType::Key(actions))
-            },
-            "pointer" => {
-                let mut actions = Vec::with_capacity(actions_chain.len());
-                let parameters = match data.get("parameters") {
-                    Some(x) => try!(PointerActionParameters::from_json(x)),
-                    None => Default::default()
-                };
-
-                for action_body in actions_chain.iter() {
-                    actions.push(try!(PointerActionItem::from_json(action_body)));
-                }
-                Ok(ActionsType::Pointer(parameters, actions))
-            }
-            _ => panic!("Got unexpected action type after checking type")
-        }
-    }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all="lowercase")]
 pub enum PointerType {
     Mouse,
     Pen,
     Touch,
 }
 
-impl Parameters for PointerType {
-    fn from_json(body: &Value) -> WebDriverResult<PointerType> {
-        match body.as_str() {
-            Some("mouse") => Ok(PointerType::Mouse),
-            Some("pen") => Ok(PointerType::Pen),
-            Some("touch") => Ok(PointerType::Touch),
-            Some(_) => Err(WebDriverError::new(
-                ErrorStatus::InvalidArgument,
-                "Unsupported pointer type"
-            )),
-            None => Err(WebDriverError::new(
-                ErrorStatus::InvalidArgument,
-                "Pointer type was not a string"
-            ))
-        }
-    }
-}
-
 impl<'a> From<&'a PointerType> for Value {
     fn from(params: &'a PointerType) -> Value {
         match *params {
             PointerType::Mouse => "mouse".into(),
             PointerType::Pen => "pen".into(),
             PointerType::Touch => "touch".into(),
         }
     }
 }
 
 impl Default for PointerType {
     fn default() -> PointerType {
         PointerType::Mouse
     }
 }
 
-#[derive(Debug, Default, PartialEq)]
+#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
 pub struct PointerActionParameters {
+    #[serde(rename="pointerType")]
     pub pointer_type: PointerType
 }
 
-impl Parameters for PointerActionParameters {
-    fn from_json(body: &Value) -> WebDriverResult<PointerActionParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Parameter 'parameters' was not an object");
-        let pointer_type = match data.get("pointerType") {
-            Some(x) => try!(PointerType::from_json(x)),
-            None => PointerType::default()
-        };
-        Ok(PointerActionParameters {
-            pointer_type: pointer_type
-        })
-    }
-}
-
 impl<'a> From<&'a PointerActionParameters> for Value {
     fn from(params: &'a PointerActionParameters) -> Value {
         let mut data = Map::new();
         data.insert("pointerType".to_owned(),
                     (&params.pointer_type).into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
 pub enum NullActionItem {
     General(GeneralAction)
 }
 
-impl Parameters for NullActionItem {
-    fn from_json(body: &Value) -> WebDriverResult<NullActionItem> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Actions chain was not an object");
-        let type_name = try_opt!(
-            try_opt!(data.get("type"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'type' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'type' was not a string");
-        match type_name {
-            "pause" => Ok(NullActionItem::General(
-                try!(GeneralAction::from_json(body)))),
-            _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                                "Invalid type attribute"))
-        }
-    }
-}
-
 impl<'a> From<&'a NullActionItem> for Value {
     fn from(params: &'a NullActionItem) -> Value {
         match *params {
             NullActionItem::General(ref x) => x.into(),
         }
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
 pub enum KeyActionItem {
     General(GeneralAction),
     Key(KeyAction)
 }
 
-impl Parameters for KeyActionItem {
-    fn from_json(body: &Value) -> WebDriverResult<KeyActionItem> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Key action item was not an object");
-        let type_name = try_opt!(
-            try_opt!(data.get("type"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'type' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'type' was not a string");
-        match type_name {
-            "pause" => Ok(KeyActionItem::General(
-                try!(GeneralAction::from_json(body)))),
-            _ => Ok(KeyActionItem::Key(
-                try!(KeyAction::from_json(body))))
-        }
-    }
-}
-
 impl<'a> From<&'a KeyActionItem> for Value {
     fn from(params: &'a KeyActionItem) -> Value {
         match *params {
             KeyActionItem::General(ref x) => x.into(),
             KeyActionItem::Key(ref x) => x.into()
         }
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
 pub enum PointerActionItem {
     General(GeneralAction),
     Pointer(PointerAction)
 }
 
-impl Parameters for PointerActionItem {
-    fn from_json(body: &Value) -> WebDriverResult<PointerActionItem> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Pointer action item was not an object");
-        let type_name = try_opt!(
-            try_opt!(data.get("type"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'type' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'type' was not a string");
-
-        match type_name {
-            "pause" => Ok(PointerActionItem::General(try!(GeneralAction::from_json(body)))),
-            _ => Ok(PointerActionItem::Pointer(try!(PointerAction::from_json(body))))
-        }
-    }
-}
-
 impl<'a> From<&'a PointerActionItem> for Value {
     fn from(params: &'a PointerActionItem) -> Value {
         match *params {
             PointerActionItem::General(ref x) => x.into(),
             PointerActionItem::Pointer(ref x) => x.into()
         }
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
 pub enum GeneralAction {
     Pause(PauseAction)
 }
 
-impl Parameters for GeneralAction {
-    fn from_json(body: &Value) -> WebDriverResult<GeneralAction> {
-        match body.get("type").and_then(|x| x.as_str()) {
-            Some("pause") => Ok(GeneralAction::Pause(try!(PauseAction::from_json(body)))),
-            _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                         "Invalid or missing type attribute"))
-        }
-    }
-}
-
 impl<'a> From<&'a GeneralAction> for Value {
     fn from(params: &'a GeneralAction) -> Value {
         match *params {
             GeneralAction::Pause(ref x) => x.into()
         }
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct PauseAction {
     pub duration: u64
 }
 
-impl Parameters for PauseAction {
-    fn from_json(body: &Value) -> WebDriverResult<PauseAction> {
-        let default = Value::Number(0.into());
-        Ok(PauseAction {
-            duration: try_opt!(body.get("duration").unwrap_or(&default).as_u64(),
-                               ErrorStatus::InvalidArgument,
-                               "Parameter 'duration' was not a positive integer")
-        })
-    }
-}
-
 impl<'a> From<&'a PauseAction> for Value {
     fn from(params: &'a PauseAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(),
                     "pause".into());
         data.insert("duration".to_owned(),
                     params.duration.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
 pub enum KeyAction {
+    #[serde(rename="keyUp")]
     Up(KeyUpAction),
+    #[serde(rename="keyDown")]
     Down(KeyDownAction)
 }
 
-impl Parameters for KeyAction {
-    fn from_json(body: &Value) -> WebDriverResult<KeyAction> {
-        match body.get("type").and_then(|x| x.as_str()) {
-            Some("keyDown") => Ok(KeyAction::Down(try!(KeyDownAction::from_json(body)))),
-            Some("keyUp") => Ok(KeyAction::Up(try!(KeyUpAction::from_json(body)))),
-            Some(_) | None => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                                      "Invalid type attribute value for key action"))
-        }
-    }
-}
-
 impl<'a> From<&'a KeyAction> for Value {
     fn from(params: &'a KeyAction) -> Value {
         match *params {
             KeyAction::Down(ref x) => x.into(),
             KeyAction::Up(ref x) => x.into(),
         }
     }
 }
 
-fn validate_key_value(value_str: &str) -> WebDriverResult<char> {
-    let mut chars = value_str.chars();
-    let value = if let Some(c) = chars.next() {
-        c
-    } else {
-        return Err(WebDriverError::new(
-            ErrorStatus::InvalidArgument,
-            "Parameter 'value' was an empty string"))
-    };
-    if chars.next().is_some() {
-        return Err(WebDriverError::new(
-            ErrorStatus::InvalidArgument,
-            "Parameter 'value' contained multiple characters"))
-    };
-    Ok(value)
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct KeyUpAction {
     pub value: char
 }
 
-impl Parameters for KeyUpAction {
-    fn from_json(body: &Value) -> WebDriverResult<KeyUpAction> {
-        let value_str = try_opt!(
-                try_opt!(body.get("value"),
-                         ErrorStatus::InvalidArgument,
-                         "Missing value parameter").as_str(),
-                ErrorStatus::InvalidArgument,
-            "Parameter 'value' was not a string");
-
-        let value = try!(validate_key_value(value_str));
-        Ok(KeyUpAction {
-            value: value
-        })
-    }
-}
-
 impl<'a> From<&'a KeyUpAction> for Value {
     fn from(params: &'a KeyUpAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(),
                     "keyUp".into());
         data.insert("value".to_string(),
                     params.value.to_string().into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct KeyDownAction {
     pub value: char
 }
 
-impl Parameters for KeyDownAction {
-    fn from_json(body: &Value) -> WebDriverResult<KeyDownAction> {
-        let value_str = try_opt!(
-                try_opt!(body.get("value"),
-                         ErrorStatus::InvalidArgument,
-                         "Missing value parameter").as_str(),
-                ErrorStatus::InvalidArgument,
-            "Parameter 'value' was not a string");
-        let value = try!(validate_key_value(value_str));
-        Ok(KeyDownAction {
-            value: value
-        })
-    }
-}
-
 impl<'a> From<&'a KeyDownAction> for Value {
     fn from(params: &'a KeyDownAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(),
                     "keyDown".into());
         data.insert("value".to_owned(),
                     params.value.to_string().into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged, rename_all="lowercase")]
 pub enum PointerOrigin {
     Viewport,
     Pointer,
     Element(WebElement),
 }
 
-impl Parameters for PointerOrigin {
-    fn from_json(body: &Value) -> WebDriverResult<PointerOrigin> {
-        match *body {
-            Value::String(ref x) => {
-                match &**x {
-                    "viewport" => Ok(PointerOrigin::Viewport),
-                    "pointer" => Ok(PointerOrigin::Pointer),
-                    _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                                 "Unknown pointer origin"))
-                }
-            },
-            Value::Object(_) => Ok(PointerOrigin::Element(try!(WebElement::from_json(body)))),
-            _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                        "Pointer origin was not a string or an object"))
-        }
-    }
-}
-
 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(),
         }
     }
 }
 
 impl Default for PointerOrigin {
     fn default() -> PointerOrigin {
         PointerOrigin::Viewport
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
 pub enum PointerAction {
+    #[serde(rename="pointerUp")]
     Up(PointerUpAction),
+    #[serde(rename="pointerDown")]
     Down(PointerDownAction),
+    #[serde(rename="pointerMove")]
     Move(PointerMoveAction),
+    #[serde(rename="pointerCancel")]
     Cancel
 }
 
-impl Parameters for PointerAction {
-    fn from_json(body: &Value) -> WebDriverResult<PointerAction> {
-        match body.get("type").and_then(|x| x.as_str()) {
-            Some("pointerUp") => Ok(PointerAction::Up(try!(PointerUpAction::from_json(body)))),
-            Some("pointerDown") => Ok(PointerAction::Down(try!(PointerDownAction::from_json(body)))),
-            Some("pointerMove") => Ok(PointerAction::Move(try!(PointerMoveAction::from_json(body)))),
-            Some("pointerCancel") => Ok(PointerAction::Cancel),
-            Some(_) | None => Err(WebDriverError::new(
-                ErrorStatus::InvalidArgument,
-                "Missing or invalid type argument for pointer action"))
-        }
-    }
-}
-
 impl<'a> From<&'a PointerAction> for Value {
     fn from(params: &'a PointerAction) -> Value {
         match *params {
             PointerAction::Down(ref x) => x.into(),
             PointerAction::Up(ref x) => x.into(),
             PointerAction::Move(ref x) => x.into(),
             PointerAction::Cancel => {
                 let mut data = Map::new();
                 data.insert("type".to_owned(),
                             "pointerCancel".into());
                 Value::Object(data)
             }
         }
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct PointerUpAction {
     pub button: u64,
 }
 
-impl Parameters for PointerUpAction {
-    fn from_json(body: &Value) -> WebDriverResult<PointerUpAction> {
-        let button = try_opt!(
-            try_opt!(body.get("button"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing button parameter").as_u64(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'button' was not a positive integer");
-
-        Ok(PointerUpAction {
-            button: button
-        })
-    }
-}
-
 impl<'a> From<&'a PointerUpAction> for Value {
     fn from(params: &'a PointerUpAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(),
                     "pointerUp".into());
         data.insert("button".to_owned(), params.button.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct PointerDownAction {
     pub button: u64,
 }
 
-impl Parameters for PointerDownAction {
-    fn from_json(body: &Value) -> WebDriverResult<PointerDownAction> {
-        let button = try_opt!(
-            try_opt!(body.get("button"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing button parameter").as_u64(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'button' was not a positive integer");
-
-        Ok(PointerDownAction {
-            button: button
-        })
-    }
-}
-
 impl<'a> From<&'a PointerDownAction> for Value {
     fn from(params: &'a PointerDownAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(),
                     "pointerDown".into());
         data.insert("button".to_owned(), params.button.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct PointerMoveAction {
     pub duration: Option<u64>,
     pub origin: PointerOrigin,
     pub x: Option<i64>,
     pub y: Option<i64>
 }
 
-impl Parameters for PointerMoveAction {
-    fn from_json(body: &Value) -> WebDriverResult<PointerMoveAction> {
-        let duration = match body.get("duration") {
-            Some(duration) => Some(try_opt!(duration.as_u64(),
-                                            ErrorStatus::InvalidArgument,
-                                            "Parameter 'duration' was not a positive integer")),
-            None => None
-
-        };
-
-        let origin = match body.get("origin") {
-            Some(o) => try!(PointerOrigin::from_json(o)),
-            None => PointerOrigin::default()
-        };
-
-        let x = match body.get("x") {
-            Some(x) => {
-                Some(try_opt!(x.as_i64(),
-                              ErrorStatus::InvalidArgument,
-                              "Parameter 'x' was not an integer"))
-            },
-            None => None
-        };
-
-        let y = match body.get("y") {
-            Some(y) => {
-                Some(try_opt!(y.as_i64(),
-                              ErrorStatus::InvalidArgument,
-                              "Parameter 'y' was not an integer"))
-            },
-            None => None
-        };
-
-        Ok(PointerMoveAction {
-            duration: duration.into(),
-            origin: origin.into(),
-            x: x.into(),
-            y: y.into(),
-        })
-    }
-}
-
 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());
         if let Some(duration) = params.duration {
             data.insert("duration".to_owned(),
                         duration.into());
         }
@@ -651,8 +358,86 @@ impl<'a> From<&'a PointerMoveAction> for
             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
+                            ),
+                        }
+                    }
+                }
+            ]
+        };
+        let actual: ActionsParameters = serde_json::from_str(
+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"}
+  ]
+}]}"#).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
--- a/testing/webdriver/src/capabilities.rs
+++ b/testing/webdriver/src/capabilities.rs
@@ -1,9 +1,8 @@
-use command::Parameters;
 use error::{WebDriverResult, WebDriverError, ErrorStatus};
 use std::convert::From;
 use serde_json::{Value, Map};
 use url::Url;
 
 pub type Capabilities = Map<String, Value>;
 
 /// Trait for objects that can be used to inspect browser capabilities
@@ -58,22 +57,34 @@ 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)]
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
+pub struct SpecNewSessionParametersWrapper {
+    capabilities: SpecNewSessionParameters
+}
+
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
 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)
@@ -284,56 +295,16 @@ impl SpecNewSessionParameters {
             "dismiss" |
             "accept" => {},
             x => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                 format!("{} was not a valid unhandledPromptBehavior value", x)))        }
         Ok(())
     }
 }
 
-impl Parameters for SpecNewSessionParameters {
-    fn from_json(body: &Value) -> WebDriverResult<SpecNewSessionParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::UnknownError,
-                            "Message body was not an object");
-
-        let capabilities = try_opt!(
-            try_opt!(data.get("capabilities"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'capabilities' parameter").as_object(),
-            ErrorStatus::InvalidArgument,
-                     "'capabilities' parameter is not an object");
-
-        let default_always_match = Value::Object(Capabilities::new());
-        let always_match = try_opt!(capabilities.get("alwaysMatch")
-                                   .unwrap_or(&default_always_match)
-                                   .as_object(),
-                                   ErrorStatus::InvalidArgument,
-                                   "'alwaysMatch' parameter is not an object");
-        let default_first_matches = Value::Array(vec![]);
-        let first_matches = try!(
-            try_opt!(capabilities.get("firstMatch")
-                     .unwrap_or(&default_first_matches)
-                     .as_array(),
-                     ErrorStatus::InvalidArgument,
-                     "'firstMatch' parameter is not an array")
-                .iter()
-                .map(|x| x.as_object()
-                     .map(|x| x.clone())
-                     .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                                "'firstMatch' entry is not an object")))
-                .collect::<WebDriverResult<Vec<Capabilities>>>());
-
-        return Ok(SpecNewSessionParameters {
-            alwaysMatch: always_match.clone(),
-            firstMatch: first_matches
-        });
-    }
-}
-
 impl<'a> From<&'a SpecNewSessionParameters> for Value {
     fn from(params: &'a SpecNewSessionParameters) -> Value {
         let mut body = Map::new();
         let mut capabilities = Map::new();
         capabilities.insert("alwaysMatch".into(), Value::Object(params.alwaysMatch.clone()));
         capabilities.insert("firstMatch".into(), Value::Array(params.firstMatch.clone()
                                                               .into_iter()
                                                               .map(|x| Value::Object(x))
@@ -449,17 +420,17 @@ impl CapabilitiesMatching for SpecNewSes
                 return Some(merged)
             })
             .next()
             .map(|x| x.clone());
             Ok(selected)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
 pub struct LegacyNewSessionParameters {
     pub desired: Capabilities,
     pub required: Capabilities,
 }
 
 impl CapabilitiesMatching for LegacyNewSessionParameters {
     fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
                                              -> WebDriverResult<Option<Capabilities>> {
@@ -475,64 +446,32 @@ impl CapabilitiesMatching for LegacyNewS
                           caps.insert(key.clone(), value.clone());
                       }
                       caps});
         browser_capabilities.init(&capabilities);
         Ok(Some(capabilities))
     }
 }
 
-impl Parameters for LegacyNewSessionParameters {
-    fn from_json(body: &Value) -> WebDriverResult<LegacyNewSessionParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::UnknownError,
-                            "Message body was not an object");
-
-        let desired_capabilities =
-            if let Some(capabilities) = data.get("desiredCapabilities") {
-                try_opt!(capabilities.as_object(),
-                         ErrorStatus::InvalidArgument,
-                         "'desiredCapabilities' parameter is not an object").clone()
-            } else {
-                Map::new()
-            };
-
-        let required_capabilities =
-            if let Some(capabilities) = data.get("requiredCapabilities") {
-                try_opt!(capabilities.as_object(),
-                         ErrorStatus::InvalidArgument,
-                         "'requiredCapabilities' parameter is not an object").clone()
-            } else {
-                Map::new()
-            };
-
-        Ok(LegacyNewSessionParameters {
-            desired: desired_capabilities,
-            required: required_capabilities
-        })
-    }
-}
-
 impl<'a> From<&'a LegacyNewSessionParameters> for Value {
     fn from(params: &'a LegacyNewSessionParameters) -> Value {
         let mut data = Map::new();
         data.insert("desiredCapabilities".to_owned(), Value::Object(params.desired.clone()));
         data.insert("requiredCapabilities".to_owned(), Value::Object(params.required.clone()));
         Value::Object(data)
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use serde_json::{self, Value};
-    use std::collections::Map;
+    use serde_json::{self, Value, Map};
     use super::{WebDriverResult, SpecNewSessionParameters};
 
     fn validate_proxy(value: &str) -> WebDriverResult<()> {
-        let data = serde_json::from_str(value).unwrap();
+        let data = serde_json::from_str::<Value>(value).unwrap();
         SpecNewSessionParameters::validate_proxy(&data)
     }
 
     #[test]
     fn test_validate_proxy() {
         // proxy hosts
         validate_proxy("{\"httpProxy\": \"127.0.0.1\"}").unwrap();
         validate_proxy("{\"httpProxy\": \"127.0.0.1:\"}").unwrap();
--- a/testing/webdriver/src/command.rs
+++ b/testing/webdriver/src/command.rs
@@ -1,10 +1,10 @@
 use actions::ActionSequence;
-use capabilities::{SpecNewSessionParameters, LegacyNewSessionParameters,
+use capabilities::{SpecNewSessionParametersWrapper, 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;
 
@@ -59,17 +59,17 @@ pub enum WebDriverCommand<T: WebDriverEx
     ElementSendKeys(WebElement, SendKeysParameters),
     PerformActions(ActionsParameters),
     ReleaseActions,
     DismissAlert,
     AcceptAlert,
     GetAlertText,
     SendAlertText(SendKeysParameters),
     TakeScreenshot,
-    TakeElementScreenshot(WebElement),
+    TakeElementScreenshot(TakeScreenshotParameters),
     Status,
     Extension(T)
 }
 
 pub trait WebDriverExtensionCommand : Clone + Send + PartialEq {
     fn parameters_json(&self) -> Option<Value>;
 }
 
@@ -102,77 +102,77 @@ 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: NewSessionParameters = try!(Parameters::from_json(&body_data));
-                WebDriverCommand::NewSession(parameters)
+                let parameters: NewSessionParametersWrapper = serde_json::from_str(raw_body)?;
+                WebDriverCommand::NewSession(parameters.into())
             },
             Route::DeleteSession => WebDriverCommand::DeleteSession,
             Route::Get => {
-                let parameters: GetParameters = try!(Parameters::from_json(&body_data));
+                let parameters: GetParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::Get(parameters)
             },
             Route::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
             Route::GoBack => WebDriverCommand::GoBack,
             Route::GoForward => WebDriverCommand::GoForward,
             Route::Refresh => WebDriverCommand::Refresh,
             Route::GetTitle => WebDriverCommand::GetTitle,
             Route::GetPageSource => WebDriverCommand::GetPageSource,
             Route::GetWindowHandle => WebDriverCommand::GetWindowHandle,
             Route::GetWindowHandles => WebDriverCommand::GetWindowHandles,
             Route::CloseWindow => WebDriverCommand::CloseWindow,
             Route::GetTimeouts => WebDriverCommand::GetTimeouts,
             Route::SetTimeouts => {
-                let parameters: TimeoutsParameters = try!(Parameters::from_json(&body_data));
+                let parameters: TimeoutsParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::SetTimeouts(parameters)
             },
             Route::GetWindowRect | Route::GetWindowPosition | Route::GetWindowSize => WebDriverCommand::GetWindowRect,
             Route::SetWindowRect | Route::SetWindowPosition | Route::SetWindowSize => {
-                let parameters: WindowRectParameters = Parameters::from_json(&body_data)?;
+                let parameters: WindowRectParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::SetWindowRect(parameters)
             },
             Route::MinimizeWindow => WebDriverCommand::MinimizeWindow,
             Route::MaximizeWindow => WebDriverCommand::MaximizeWindow,
             Route::FullscreenWindow => WebDriverCommand::FullscreenWindow,
             Route::SwitchToWindow => {
-                let parameters: SwitchToWindowParameters = try!(Parameters::from_json(&body_data));
+                let parameters: SwitchToWindowParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::SwitchToWindow(parameters)
             }
             Route::SwitchToFrame => {
-                let parameters: SwitchToFrameParameters = try!(Parameters::from_json(&body_data));
+                let parameters: SwitchToFrameParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::SwitchToFrame(parameters)
             },
             Route::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
             Route::FindElement => {
-                let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+                let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::FindElement(parameters)
             },
             Route::FindElements => {
-                let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+                let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::FindElements(parameters)
             },
             Route::FindElementElement => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.as_str().into());
-                let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+                let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::FindElementElement(element, parameters)
             },
             Route::FindElementElements => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.as_str().into());
-                let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+                let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::FindElementElements(element, parameters)
             },
             Route::GetActiveElement => WebDriverCommand::GetActiveElement,
             Route::IsDisplayed => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.as_str().into());
@@ -264,76 +264,73 @@ impl<U: WebDriverExtensionRoute> WebDriv
                 let element = WebElement::new(element_id.as_str().into());
                 WebDriverCommand::ElementClear(element)
             },
             Route::ElementSendKeys => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.as_str().into());
-                let parameters: SendKeysParameters = try!(Parameters::from_json(&body_data));
+                let parameters: SendKeysParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::ElementSendKeys(element, parameters)
             },
             Route::ExecuteScript => {
-                let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
+                let parameters: JavascriptCommandParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::ExecuteScript(parameters)
             },
             Route::ExecuteAsyncScript => {
-                let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
+                let parameters: JavascriptCommandParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::ExecuteAsyncScript(parameters)
             },
             Route::GetCookies => {
                 WebDriverCommand::GetCookies
             },
             Route::GetNamedCookie => {
                 let name = try_opt!(params.name("name"),
                                     ErrorStatus::InvalidArgument,
                                     "Missing 'name' parameter").as_str().into();
                 WebDriverCommand::GetNamedCookie(name)
             },
             Route::AddCookie => {
-                let parameters: AddCookieParameters = try!(Parameters::from_json(&body_data));
-                WebDriverCommand::AddCookie(parameters)
+                let parameters: AddCookieParametersWrapper = serde_json::from_str(raw_body)?;
+                WebDriverCommand::AddCookie(parameters.cookie)
             },
             Route::DeleteCookies => {
                 WebDriverCommand::DeleteCookies
             },
             Route::DeleteCookie => {
                 let name = try_opt!(params.name("name"),
                                     ErrorStatus::InvalidArgument,
                                     "Missing name parameter").as_str().into();
                 WebDriverCommand::DeleteCookie(name)
             },
             Route::PerformActions => {
-                let parameters: ActionsParameters = try!(Parameters::from_json(&body_data));
+                let parameters: ActionsParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::PerformActions(parameters)
             },
             Route::ReleaseActions => {
                 WebDriverCommand::ReleaseActions
             },
             Route::DismissAlert => {
                 WebDriverCommand::DismissAlert
             },
             Route::AcceptAlert => {
                 WebDriverCommand::AcceptAlert
             },
             Route::GetAlertText => {
                 WebDriverCommand::GetAlertText
             },
             Route::SendAlertText => {
-                let parameters: SendKeysParameters = try!(Parameters::from_json(&body_data));
+                let parameters: SendKeysParameters = serde_json::from_str(raw_body)?;
                 WebDriverCommand::SendAlertText(parameters)
             },
             Route::TakeScreenshot => WebDriverCommand::TakeScreenshot,
             Route::TakeElementScreenshot =>  {
-                let element_id = try_opt!(params.name("elementId"),
-                                          ErrorStatus::InvalidArgument,
-                                          "Missing elementId parameter");
-                let element = WebElement::new(element_id.as_str().into());
-                WebDriverCommand::TakeElementScreenshot(element)
+                let parameters: TakeScreenshotParameters = serde_json::from_str(raw_body)?;
+                WebDriverCommand::TakeElementScreenshot(parameters)
             },
             Route::Status => WebDriverCommand::Status,
             Route::Extension(ref extension) => {
                 try!(extension.command(params, &body_data))
             }
         };
         Ok(WebDriverMessage::new(session_id, command))
     }
@@ -435,45 +432,46 @@ impl <U:WebDriverExtensionRoute> From<We
         let mut data = Map::new();
         if let Some(parameters) = parameters {
             data.insert("parameters".to_string(), parameters);
         }
         Value::Object(data)
     }
 }
 
-pub trait Parameters: Sized {
-    fn from_json(body: &Value) -> WebDriverResult<Self>;
-}
-
 /// 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(Serialize, Deserialize, Debug)]
+#[serde(untagged)]
+pub enum NewSessionParametersWrapper {
+    Spec(SpecNewSessionParametersWrapper),
+    Legacy(LegacyNewSessionParameters),
+}
+
 #[derive(Debug, PartialEq)]
 pub enum NewSessionParameters {
     Spec(SpecNewSessionParameters),
     Legacy(LegacyNewSessionParameters),
 }
 
-impl Parameters for NewSessionParameters {
-    fn from_json(body: &Value) -> WebDriverResult<NewSessionParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::UnknownError,
-                            "Message body was not an object");
-        if data.get("capabilities").is_some() {
-            Ok(NewSessionParameters::Spec(try!(SpecNewSessionParameters::from_json(body))))
-        } else {
-            Ok(NewSessionParameters::Legacy(try!(LegacyNewSessionParameters::from_json(body))))
+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()
         }
     }
 }
@@ -483,94 +481,37 @@ impl CapabilitiesMatching for NewSession
                                              -> WebDriverResult<Option<Capabilities>> {
         match self {
             &NewSessionParameters::Spec(ref x) => x.match_browser(browser_capabilities),
             &NewSessionParameters::Legacy(ref x) => x.match_browser(browser_capabilities)
         }
     }
 }
 
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct GetParameters {
     pub url: String
 }
 
-impl Parameters for GetParameters {
-    fn from_json(body: &Value) -> WebDriverResult<GetParameters> {
-        let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
-                            "Message body was not an object");
-        let url = try_opt!(
-            try_opt!(data.get("url"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'url' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "'url' not a string");
-        Ok(GetParameters {
-            url: url.to_string()
-        })
-    }
-}
-
 impl<'a> From<&'a GetParameters> for Value {
     fn from(params: &'a GetParameters) -> Value {
         let mut data = Map::new();
         data.insert("url".to_string(), Value::String(params.url.clone()));
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct TimeoutsParameters {
     pub script: Option<u64>,
+    #[serde(rename="pageLoad")]
     pub page_load: Option<u64>,
     pub implicit: Option<u64>,
 }
 
-impl Parameters for TimeoutsParameters {
-    fn from_json(body: &Value) -> WebDriverResult<TimeoutsParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::UnknownError,
-                            "Message body was not an object");
-
-        let script = match data.get("script") {
-            Some(json) => {
-                Some(try_opt!(json.as_u64(),
-                              ErrorStatus::InvalidArgument,
-                              "Script timeout duration was not a signed integer"))
-            }
-            None => None,
-        };
-
-        let page_load = match data.get("pageLoad") {
-            Some(json) => {
-                Some(try_opt!(json.as_u64(),
-                              ErrorStatus::InvalidArgument,
-                              "Page load timeout duration was not a signed integer"))
-            }
-            None => None,
-        };
-
-        let implicit = match data.get("implicit") {
-            Some(json) => {
-                Some(try_opt!(json.as_u64(),
-                              ErrorStatus::InvalidArgument,
-                              "Implicit timeout duration was not a signed integer"))
-            }
-            None => None,
-        };
-
-        Ok(TimeoutsParameters {
-            script: script,
-            page_load: page_load,
-            implicit: implicit,
-        })
-    }
-}
-
 impl<'a> From<&'a TimeoutsParameters> for Value {
     fn from(params: &'a TimeoutsParameters) -> Value {
         let mut data = Map::new();
         if let Some(ms) = params.script {
             data.insert("script".into(), Value::Number(ms.into()));
         }
         if let Some(ms) = params.page_load {
             data.insert("pageLoad".into(), Value::Number(ms.into()));
@@ -587,476 +528,155 @@ impl<'a> From<&'a TimeoutsParameters> fo
 /// `WindowProxy`.
 ///
 /// In some user agents the operating system’s window dimensions, including
 /// decorations, are provided by the proprietary `window.outerWidth` and
 /// `window.outerHeight` DOM properties.
 ///
 /// [`screenX`]: https://w3c.github.io/webdriver/webdriver-spec.html#dfn-screenx
 /// [`screenY`]: https://w3c.github.io/webdriver/webdriver-spec.html#dfn-screeny
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct WindowRectParameters {
     pub x: Option<i32>,
     pub y: Option<i32>,
     pub width: Option<i32>,
     pub height: Option<i32>,
 }
 
-impl Parameters for WindowRectParameters {
-    fn from_json(body: &Value) -> WebDriverResult<WindowRectParameters> {
-        let data = try_opt!(body.as_object(),
-            ErrorStatus::InvalidArgument, "Message body was not an object");
-
-        let x = match data.get("x") {
-            Some(json) => {
-                let x = try_opt!(json.as_f64(),
-                    ErrorStatus::InvalidArgument,
-                    "'x' is not a number"
-                ) as i64;
-
-                if x < i32::min_value() as i64 || x > i32::max_value() as i64 {
-                    return Err(WebDriverError::new(
-                        ErrorStatus::InvalidArgument,
-                        "'x' is larger than i32",
-                    ));
-                }
-                Some(x as i32)
-            },
-            None => None,
-        };
-
-        let y = match data.get("y") {
-            Some(json) => {
-                let y = try_opt!(json.as_f64(),
-                    ErrorStatus::InvalidArgument,
-                    "'y' is not a number"
-                ) as i64;
-
-                if y < i32::min_value() as i64 || y > i32::max_value() as i64 {
-                    return Err(WebDriverError::new(
-                        ErrorStatus::InvalidArgument,
-                        "'y' is larger than i32",
-                    ));
-                }
-                Some(y as i32)
-            },
-            None => None,
-        };
-
-        let width = match data.get("width") {
-            Some(json) => {
-                let width = try_opt!(json.as_f64(),
-                    ErrorStatus::InvalidArgument,
-                    "'width' is not a positive integer"
-                ) as i64;
-
-                if width < 0 || width > i32::max_value() as i64 {
-                    return Err(WebDriverError::new(
-                        ErrorStatus::InvalidArgument,
-                        "'width' is larger than i32",
-                    ));
-                }
-                Some(width as i32)
-            },
-            None => None,
-        };
-
-        let height = match data.get("height") {
-            Some(json) => {
-                let height = try_opt!(json.as_f64(),
-                    ErrorStatus::InvalidArgument,
-                    "'height' is not a positive integer"
-                ) as i64;
-
-                if height < 0 || height > i32::max_value() as i64 {
-                    return Err(WebDriverError::new(
-                        ErrorStatus::InvalidArgument,
-                        "'height' is larger than i32",
-                    ));
-                }
-                Some(height as i32)
-            },
-            None => None,
-        };
-
-        Ok(WindowRectParameters { x, y, width, height })
-    }
-}
-
 impl<'a> From<&'a WindowRectParameters> for Value {
     fn from(params: &'a WindowRectParameters) -> Value {
         let mut data = Map::new();
         data.insert("x".to_string(), params.x.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
         data.insert("y".to_string(), params.y.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
         data.insert("width".to_string(), params.width.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
         data.insert("height".to_string(), params.height.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct SwitchToWindowParameters {
     pub handle: String
 }
 
-impl Parameters for SwitchToWindowParameters {
-    fn from_json(body: &Value) -> WebDriverResult<SwitchToWindowParameters> {
-        let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
-                            "Message body was not an object");
-        let handle = try_opt!(
-            try_opt!(data.get("handle"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'handle' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "'handle' not a string");
-        return Ok(SwitchToWindowParameters {
-            handle: handle.to_string()
-        })
-    }
-}
-
 impl<'a> From<&'a SwitchToWindowParameters> for Value {
     fn from(params: &'a SwitchToWindowParameters) -> Value {
         let mut data = Map::new();
         data.insert("handle".to_string(), params.handle.clone().into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct LocatorParameters {
     pub using: LocatorStrategy,
     pub value: String
 }
 
-impl Parameters for LocatorParameters {
-    fn from_json(body: &Value) -> WebDriverResult<LocatorParameters> {
-        let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
-                            "Message body was not an object");
-
-        let using = try!(LocatorStrategy::from_json(
-            try_opt!(data.get("using"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'using' parameter")));
-
-        let value = try_opt!(
-            try_opt!(data.get("value"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'value' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "Could not convert using to string").to_string();
-
-        return Ok(LocatorParameters {
-            using: using,
-            value: value
-        })
-    }
-}
-
 impl<'a> From<&'a LocatorParameters> for Value {
     fn from(params: &'a LocatorParameters) -> Value {
         let mut data = Map::new();
         data.insert("using".to_string(), params.using.into());
         data.insert("value".to_string(), params.value.clone().into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct SwitchToFrameParameters {
-    pub id: FrameId
-}
-
-impl Parameters for SwitchToFrameParameters {
-    fn from_json(body: &Value) -> WebDriverResult<SwitchToFrameParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::UnknownError,
-                            "Message body was not an object");
-        let id = try!(FrameId::from_json(try_opt!(data.get("id"),
-                                                  ErrorStatus::UnknownError,
-                                                  "Missing 'id' parameter")));
-
-        Ok(SwitchToFrameParameters {
-            id: id
-        })
-    }
+    pub id: Option<FrameId>
 }
 
 impl<'a> From<&'a SwitchToFrameParameters> for Value {
     fn from(params: &'a SwitchToFrameParameters) -> Value {
         let mut data = Map::new();
-        data.insert("id".to_string(), params.id.clone().into());
+        data.insert("id".to_string(), params.id.clone().map(|x| x.into()).unwrap_or(Value::Null));
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct SendKeysParameters {
     pub text: String
 }
 
-impl Parameters for SendKeysParameters {
-    fn from_json(body: &Value) -> WebDriverResult<SendKeysParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Message body was not an object");
-        let text = try_opt!(try_opt!(data.get("text"),
-                                     ErrorStatus::InvalidArgument,
-                                     "Missing 'text' parameter").as_str(),
-                            ErrorStatus::InvalidArgument,
-                            "Could not convert 'text' to string");
-
-        Ok(SendKeysParameters {
-            text: text.into()
-        })
-    }
-}
-
 impl<'a> From<&'a SendKeysParameters> for Value {
     fn from(params: &'a SendKeysParameters) -> Value {
         let mut data = Map::new();
         data.insert("value".to_string(), params.text.clone().into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct JavascriptCommandParameters {
     pub script: String,
     pub args: Option<Vec<Value>>
 }
 
-impl Parameters for JavascriptCommandParameters {
-    fn from_json(body: &Value) -> WebDriverResult<JavascriptCommandParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Message body was not an object");
-
-        let args_json = try_opt!(data.get("args"),
-                                 ErrorStatus::InvalidArgument,
-                                 "Missing args parameter");
-
-        let args = Some(try_opt!(args_json.as_array(),
-                                 ErrorStatus::InvalidArgument,
-                                 "Failed to convert args to Array").clone());
-
-         //TODO: Look for WebElements in args?
-        let script = try_opt!(
-            try_opt!(data.get("script"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing script parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "Failed to convert script to String");
-        Ok(JavascriptCommandParameters {
-            script: script.to_string(),
-            args: args.clone()
-        })
-    }
-}
-
 impl<'a> From<&'a JavascriptCommandParameters> for Value {
     fn from(params: &'a JavascriptCommandParameters) -> Value {
         let mut data = Map::new();
         //TODO: Wrap script so that it becomes marionette-compatible
         data.insert("script".to_string(), params.script.clone().into());
         data.insert("args".to_string(), params.args.clone()
                     .map(|x| Value::Array(x))
                     .unwrap_or(Value::Null));
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
-pub struct GetNamedCookieParameters {
-    pub name: Option<String>,
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct AddCookieParametersWrapper {
+    cookie: AddCookieParameters
 }
 
-impl Parameters for GetNamedCookieParameters {
-    fn from_json(body: &Value) -> WebDriverResult<GetNamedCookieParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Message body was not an object");
-        let name_json = try_opt!(data.get("name"),
-                                 ErrorStatus::InvalidArgument,
-                                 "Missing 'name' parameter");
-        let name = Some(try_opt!(name_json.as_str(),
-                                 ErrorStatus::InvalidArgument,
-                                 "Failed to convert name to string")
-                        .into());
-        return Ok(GetNamedCookieParameters { name: name });
-    }
-}
-
-impl<'a> From<&'a GetNamedCookieParameters> for Value {
-    fn from(params: &'a GetNamedCookieParameters) -> Value {
-        let mut data = Map::new();
-        data.insert("name".to_string(), params.name.clone().map(|x| x.into()).unwrap_or(Value::Null));
-        Value::Object(data)
-    }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize, Debug)]
 pub struct AddCookieParameters {
     pub name: String,
     pub value: String,
     pub path: Option<String>,
     pub domain: Option<String>,
     pub expiry: Option<Date>,
     pub secure: bool,
     pub httpOnly: bool
 }
 
-impl Parameters for AddCookieParameters {
-    fn from_json(body: &Value) -> WebDriverResult<AddCookieParameters> {
-        if !body.is_object() {
-            return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
-                                           "Message body was not an object"));
-        }
-
-        let data = try_opt!(body.get("cookie").and_then(|x| x.as_object()),
-                            ErrorStatus::UnableToSetCookie,
-                            "Cookie parameter not found or not an object");
-
-        let name = try_opt!(
-            try_opt!(data.get("name"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'name' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "'name' is not a string").to_string();
-
-        let value = try_opt!(
-            try_opt!(data.get("value"),
-                     ErrorStatus::InvalidArgument,
-                     "Missing 'value' parameter").as_str(),
-            ErrorStatus::InvalidArgument,
-            "'value' is not a string").to_string();
-
-        let path = match data.get("path") {
-            Some(path_json) => {
-                Some(try_opt!(path_json.as_str(),
-                              ErrorStatus::InvalidArgument,
-                              "Failed to convert path to String").to_string())
-            },
-            None => None
-        };
-
-        let domain = match data.get("domain") {
-            Some(domain_json) => {
-                Some(try_opt!(domain_json.as_str(),
-                              ErrorStatus::InvalidArgument,
-                              "Failed to convert domain to String").to_string())
-            },
-            None => None
-        };
-
-        let expiry = match data.get("expiry") {
-            Some(expiry_json) => {
-                Some(Date::new(try_opt!(expiry_json.as_u64(),
-                                        ErrorStatus::InvalidArgument,
-                                        "Failed to convert expiry to Date")))
-            },
-            None => None
-        };
-
-        let secure = match data.get("secure") {
-            Some(x) => try_opt!(x.as_bool(),
-                                ErrorStatus::InvalidArgument,
-                                "Failed to convert secure to boolean"),
-            None => false
-        };
-
-        let http_only = match data.get("httpOnly") {
-            Some(x) => try_opt!(x.as_bool(),
-                                ErrorStatus::InvalidArgument,
-                                "Failed to convert httpOnly to boolean"),
-            None => false
-        };
-
-        return Ok(AddCookieParameters {
-            name: name,
-            value: value,
-            path: path,
-            domain: domain,
-            expiry: expiry,
-            secure: secure,
-            httpOnly: http_only
-        })
-    }
-}
-
 impl<'a> From<&'a AddCookieParameters> for Value {
     fn from(params: &'a AddCookieParameters) -> Value {
         let mut data = Map::new();
         data.insert("name".to_string(), params.name.clone().into());
         data.insert("value".to_string(), params.value.clone().into());
         data.insert("path".to_string(), params.path.clone().map(|x| x.into()).unwrap_or(Value::Null));
         data.insert("domain".to_string(), params.domain.clone().map(|x| x.into()).unwrap_or(Value::Null));
         data.insert("expiry".to_string(), params.expiry.clone().map(|x| x.into()).unwrap_or(Value::Null));
         data.insert("secure".to_string(), params.secure.into());
         data.insert("httpOnly".to_string(), params.httpOnly.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct TakeScreenshotParameters {
     pub element: Option<WebElement>
 }
 
-impl Parameters for TakeScreenshotParameters {
-    fn from_json(body: &Value) -> WebDriverResult<TakeScreenshotParameters> {
-        let data = try_opt!(body.as_object(),
-                            ErrorStatus::InvalidArgument,
-                            "Message body was not an object");
-        let element = match data.get("element") {
-            Some(element_json) => Some(try!(WebElement::from_json(element_json))),
-            None => None
-        };
-
-        return Ok(TakeScreenshotParameters {
-            element: element
-        })
-    }
-}
-
 impl<'a> From<&'a TakeScreenshotParameters> for Value {
     fn from(params: &'a TakeScreenshotParameters) -> Value {
         let mut data = Map::new();
         data.insert("element".to_string(), params.element.clone().map(|x| (&x).into()).unwrap_or(Value::Null));
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct ActionsParameters {
     pub actions: Vec<ActionSequence>
 }
 
-impl Parameters for ActionsParameters {
-    fn from_json(body: &Value) -> WebDriverResult<ActionsParameters> {
-        try_opt!(body.as_object(),
-                 ErrorStatus::InvalidArgument,
-                 "Message body was not an object");
-        let actions = try_opt!(
-            try_opt!(body.get("actions"),
-                     ErrorStatus::InvalidArgument,
-                     "No actions parameter found").as_array(),
-            ErrorStatus::InvalidArgument,
-            "Parameter 'actions' was not an array");
-
-        let mut result = Vec::with_capacity(actions.len());
-        for chain in actions.iter() {
-            result.push(try!(ActionSequence::from_json(chain)));
-        }
-        Ok(ActionsParameters {
-            actions: result
-        })
-    }
-}
-
 impl<'a> From<&'a ActionsParameters> for Value {
     fn from(params: &'a ActionsParameters) -> Value {
         let mut data = Map::new();
         data.insert("actions".to_owned(),
                     params.actions.iter().map(|x| x.into()).collect::<Vec<Value>>().into());
         Value::Object(data)
     }
 }
--- a/testing/webdriver/src/common.rs
+++ b/testing/webdriver/src/common.rs
@@ -1,33 +1,34 @@
 use serde_json::{Value, Map};
 use std::convert::From;
 
 use error::{WebDriverResult, WebDriverError, ErrorStatus};
 
 pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";
 
-#[derive(Clone, Debug, PartialEq, Serialize)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct Date(pub u64);
 
 impl Date {
     pub fn new(timestamp: u64) -> Date {
         Date(timestamp)
     }
 }
 
 impl From<Date> for Value {
     fn from(date: Date) -> Value {
         let Date(x) = date;
         x.into()
     }
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[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
         }
@@ -59,68 +60,46 @@ impl <'a> From<&'a WebElement> for Value
 
 impl <T> From<T> for WebElement
     where T: Into<String> {
     fn from(data: T) -> WebElement {
         WebElement::new(data.into())
     }
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub enum FrameId {
     Short(u16),
-    Element(WebElement),
-    Null
-}
-
-impl FrameId {
-    pub fn from_json(data: &Value) -> WebDriverResult<FrameId> {
-        match data {
-            &Value::Number(ref x) => {
-                let x = try_opt!(x.as_u64(),
-                                 ErrorStatus::NoSuchFrame,
-                                 "frame id out of range");
-                if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
-                    return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
-                                                   "frame id out of range"))
-                };
-                Ok(FrameId::Short(x as u16))
-            },
-
-            &Value::Null => Ok(FrameId::Null),
-            &Value::Object(_) => Ok(FrameId::Element(
-                try!(WebElement::from_json(data)))),
-            _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
-                                         "frame id has unexpected type"))
-        }
-    }
+    Element(WebElement)
 }
 
 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())
-            },
-            FrameId::Null => {
-                Value::Null
             }
         }
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub enum LocatorStrategy {
+    #[serde(rename = "css selector")]
     CSSSelector,
+    #[serde(rename = "link text")]
     LinkText,
+    #[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") {
--- a/testing/webdriver/src/lib.rs
+++ b/testing/webdriver/src/lib.rs
@@ -2,46 +2,25 @@
 
 extern crate backtrace;
 extern crate base64;
 #[macro_use]
 extern crate log;
 extern crate hyper;
 extern crate regex;
 extern crate cookie;
+extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 extern crate serde_json;
 extern crate time;
 extern crate url;
 
 #[macro_use] pub mod macros;
 pub mod actions;
 pub mod httpapi;
 pub mod capabilities;
 pub mod command;
 pub mod common;
 pub mod error;
 pub mod server;
 pub mod response;
 
-#[cfg(test)]
-mod nullable_tests {
-    use super::common::Nullable;
-
-    #[test]
-    fn test_nullable_map() {
-        let mut test = Nullable::Value(21);
-
-        assert_eq!(test.map(|x| x << 1), Nullable::Value(42));
-
-        test = Nullable::Null;
-
-        assert_eq!(test.map(|x| x << 1), Nullable::Null);
-    }
-
-    #[test]
-    fn test_nullable_into() {
-        let test: Option<i32> = Nullable::Value(42).into();
-
-        assert_eq!(test, Some(42));
-    }
-}
--- a/testing/webdriver/src/response.rs
+++ b/testing/webdriver/src/response.rs
@@ -220,61 +220,60 @@ pub struct CookiesResponse {
     pub value: Vec<Cookie>,
 }
 
 #[cfg(test)]
 mod tests {
     use super::{CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, ElementRectResponse,
                 NewSessionResponse, Nullable, TimeoutsResponse, ValueResponse, WebDriverResponse,
                 WindowRectResponse};
-    use serde_json::Value;
-    use std::collections::BTreeMap;
+    use serde_json::{self, Map, Value};
 
     fn test(resp: WebDriverResponse, expected_str: &str) {
         let data = resp.to_json_string();
-        let actual = Value::from_str(&*data).unwrap();
-        let expected = Value::from_str(expected_str).unwrap();
+        let actual: Value = serde_json::from_str(&*data).unwrap();
+        let expected: Value = serde_json::from_str(expected_str).unwrap();
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn test_close_window() {
         let resp = WebDriverResponse::CloseWindow(
             CloseWindowResponse::new(vec!["test".into()]));
         let expected = r#"{"value": ["test"]}"#;
         test(resp, expected);
     }
 
     #[test]
     fn test_cookie() {
         let cookie = Cookie {
             name: "name".into(),
             value: "value".into(),
-            path: Nullable::Value("/".into()),
-            domain: Nullable::Null,
-            expiry: Nullable::Null,
+            path: Some("/".into()),
+            domain: None,
+            expiry: None,
             secure: true,
             httpOnly: false,
         };
         let resp = WebDriverResponse::Cookie(CookieResponse { value: cookie });
         let expected = r#"{"value": {"name": "name", "expiry": null, "value": "value",
 "path": "/", "domain": null, "secure": true, "httpOnly": false}}"#;
         test(resp, expected);
     }
 
     #[test]
     fn test_cookies() {
         let resp = WebDriverResponse::Cookies(CookiesResponse {
             value: vec![
                 Cookie {
                     name: "name".into(),
                     value: "value".into(),
-                    path: Nullable::Value("/".into()),
-                    domain: Nullable::Null,
-                    expiry: Nullable::Null,
+                    path: Some("/".into()),
+                    domain: None,
+                    expiry: None,
                     secure: true,
                     httpOnly: false,
                 }
             ]});
         let expected = r#"{"value": [{"name": "name", "value": "value", "path": "/",
 "domain": null, "expiry": null, "secure": true, "httpOnly": false}]}"#;
         test(resp, expected);
     }
@@ -304,31 +303,31 @@ mod tests {
         let expected = r#"{"value": {"x": 0, "y": 1, "width": 2, "height": 3}}"#;
         test(resp, expected);
     }
 
     #[test]
     fn test_new_session() {
         let resp = WebDriverResponse::NewSession(
             NewSessionResponse::new("test".into(),
-                                    Value::Object(BTreeMap::new())));
+                                    Value::Object(Map::new())));
         let expected = r#"{"value": {"sessionId": "test", "capabilities": {}}}"#;
         test(resp, expected);
     }
 
     #[test]
     fn test_timeouts() {
          let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new(
             1, 2, 3));
         let expected = r#"{"value": {"script": 1, "pageLoad": 2, "implicit": 3}}"#;
         test(resp, expected);
     }
 
     #[test]
     fn test_value() {
-        let mut value = BTreeMap::new();
+        let mut value = Map::new();
         value.insert("example".into(), Value::Array(vec![Value::String("test".into())]));
         let resp = WebDriverResponse::Generic(ValueResponse::new(
             Value::Object(value)));
         let expected = r#"{"value": {"example": ["test"]}}"#;
         test(resp, expected);
     }
 }