Bug 1489141 - [webdriver] Ignore any unknown variant of enum PointerOrigin. r=ato a=test-only
authorHenrik Skupin <mail@hskupin.info>
Fri, 07 Sep 2018 11:27:04 +0200
changeset 492449 39b50c15dc4d47d64f2e3bd0ca96f3801228e6cf
parent 492448 263df0c4e8e4da73e23e9fc7bec8b06a16de15be
child 492450 76ea80f9f4414e4619581bcd611010e8af3adc65
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato, test-only
bugs1489141
milestone63.0
Bug 1489141 - [webdriver] Ignore any unknown variant of enum PointerOrigin. r=ato a=test-only To keep backward compatibility, the legacy "ELEMENT" key for an instance of PointerOrigin has to be supported, but ignored. This workaround can be removed once legacy support gets dropped from geckodriver.
testing/webdriver/src/actions.rs
--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,11 +1,12 @@
-use common::WebElement;
+use common::{WebElement, ELEMENT_KEY};
 use serde::de::{self, Deserialize, Deserializer};
 use serde::ser::{Serialize, Serializer};
+use serde_json::Value;
 use std::default::Default;
 use unicode_segmentation::UnicodeSegmentation;
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct ActionSequence {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub id: Option<String>,
     #[serde(flatten)]
@@ -159,50 +160,67 @@ pub struct PointerMoveAction {
     pub y: Option<i64>,
 }
 
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct PointerUpAction {
     pub button: u64,
 }
 
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
 pub enum PointerOrigin {
     #[serde(
-        rename = "element-6066-11e4-a52e-4f735466cecf",
-        serialize_with = "serialize_webelement_id",
-        deserialize_with = "deserialize_webelement_id"
+        rename = "element-6066-11e4-a52e-4f735466cecf", serialize_with = "serialize_webelement_id"
     )]
     Element(WebElement),
     #[serde(rename = "pointer")]
     Pointer,
     #[serde(rename = "viewport")]
     Viewport,
 }
 
 impl Default for PointerOrigin {
     fn default() -> PointerOrigin {
         PointerOrigin::Viewport
     }
 }
 
+// TODO: The custom deserializer can be removed once the support of the legacy
+// ELEMENT key has been removed from Selenium bindings
+// See: https://github.com/SeleniumHQ/selenium/issues/6393
+impl<'de> Deserialize<'de> for PointerOrigin {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let value = Value::deserialize(deserializer)?;
+        if let Some(web_element) = value.get(ELEMENT_KEY) {
+            String::deserialize(web_element)
+                .map(|id| PointerOrigin::Element(WebElement { id }))
+                .map_err(de::Error::custom)
+        } else if value == "pointer" {
+            Ok(PointerOrigin::Pointer)
+        } else if value == "viewport" {
+            Ok(PointerOrigin::Viewport)
+        } else {
+            Err(de::Error::custom(format!(
+                "unknown value `{}`, expected `pointer`, `viewport`, or `element-6066-11e4-a52e-4f735466cecf`",
+                value.to_string()
+            )))
+        }
+    }
+}
+
 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 })
-}
-
 fn deserialize_to_option_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
 where
     D: Deserializer<'de>,
 {
     Option::deserialize(deserializer)?
         .ok_or_else(|| de::Error::custom("invalid type: null, expected i64"))
 }
 
@@ -874,16 +892,74 @@ mod test {
             x: Some(5),
             y: Some(10),
         });
 
         check_deserialize(&json, &data);
     }
 
     #[test]
+    fn test_json_pointer_action_move_with_origin_webelement() {
+        let json = r#"{
+            "type":"pointerMove",
+            "duration":100,
+            "origin":{
+                "element-6066-11e4-a52e-4f735466cecf":"elem"
+            },
+            "x":5,
+            "y":10
+        }"#;
+        let data = PointerAction::Move(PointerMoveAction {
+            duration: Some(100),
+            origin: PointerOrigin::Element(WebElement { id: "elem".into() }),
+            x: Some(5),
+            y: Some(10),
+        });
+
+        check_serialize_deserialize(&json, &data);
+    }
+
+    #[test]
+    fn test_json_pointer_action_move_with_origin_webelement_and_legacy_element() {
+        let json = r#"{
+            "type":"pointerMove",
+            "duration":100,
+            "origin":{
+                "ELEMENT":"elem",
+                "element-6066-11e4-a52e-4f735466cecf":"elem"
+            },
+            "x":5,
+            "y":10
+        }"#;
+        let data = PointerAction::Move(PointerMoveAction {
+            duration: Some(100),
+            origin: PointerOrigin::Element(WebElement { id: "elem".into() }),
+            x: Some(5),
+            y: Some(10),
+        });
+
+        check_deserialize(&json, &data);
+    }
+
+    #[test]
+    fn test_json_pointer_action_move_with_origin_only_legacy_element() {
+        let json = r#"{
+            "type":"pointerMove",
+            "duration":100,
+            "origin":{
+                "ELEMENT":"elem"
+            },
+            "x":5,
+            "y":10
+        }"#;
+
+        assert!(serde_json::from_str::<PointerOrigin>(&json).is_err());
+    }
+
+    #[test]
     fn test_json_pointer_action_move_with_x_missing() {
         let json = r#"{
             "type":"pointerMove",
             "duration":100,
             "origin":"viewport",
             "y":10
         }"#;
         let data = PointerAction::Move(PointerMoveAction {