/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use serde::de; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::Value; use crate::common::{Cookie, Timeouts, WebElement}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct NewWindow { handle: String, #[serde(rename = "type")] type_hint: String, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct WindowRect { pub x: i32, pub y: i32, pub width: i32, pub height: i32, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ElementRect { pub x: f64, pub y: f64, pub width: f64, pub height: f64, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum MarionetteResult { #[serde(deserialize_with = "from_value", serialize_with = "to_value")] Bool(bool), #[serde(deserialize_with = "from_value", serialize_with = "to_empty_value")] Null, NewWindow(NewWindow), WindowRect(WindowRect), ElementRect(ElementRect), #[serde(deserialize_with = "from_value", serialize_with = "to_value")] String(String), Strings(Vec), #[serde(deserialize_with = "from_value", serialize_with = "to_value")] WebElement(WebElement), WebElements(Vec), Cookies(Vec), Timeouts(Timeouts), } fn to_value(data: T, serializer: S) -> Result where S: Serializer, T: Serialize, { #[derive(Serialize)] struct Wrapper { value: T, } Wrapper { value: data }.serialize(serializer) } fn to_empty_value(serializer: S) -> Result where S: Serializer, { #[derive(Serialize)] struct Wrapper { value: Value, } Wrapper { value: Value::Null }.serialize(serializer) } fn from_value<'de, D, T>(deserializer: D) -> Result where D: Deserializer<'de>, T: serde::de::DeserializeOwned, T: std::fmt::Debug, { #[derive(Debug, Deserialize)] struct Wrapper { value: T, } let v = Value::deserialize(deserializer)?; if v.is_object() { let w = serde_json::from_value::>(v).map_err(de::Error::custom)?; Ok(w.value) } else { Err(de::Error::custom("Cannot be deserialized to struct")) } } #[cfg(test)] mod tests { use super::*; use crate::test::{assert_de, assert_ser_de, ELEMENT_KEY}; use serde_json::json; #[test] fn test_boolean_response() { assert_ser_de(&MarionetteResult::Bool(true), json!({"value": true})); } #[test] fn test_cookies_response() { let mut data = Vec::new(); data.push(Cookie { name: "foo".into(), value: "bar".into(), path: Some("/common".into()), domain: Some("web-platform.test".into()), secure: false, http_only: false, expiry: None, same_site: Some("Strict".into()), }); assert_ser_de( &MarionetteResult::Cookies(data), json!([{"name":"foo","value":"bar","path":"/common","domain":"web-platform.test","secure":false,"httpOnly":false,"sameSite":"Strict"}]), ); } #[test] fn test_new_window_response() { let data = NewWindow { handle: "6442450945".into(), type_hint: "tab".into(), }; let json = json!({"handle": "6442450945", "type": "tab"}); assert_ser_de(&MarionetteResult::NewWindow(data), json); } #[test] fn test_web_element_response() { let data = WebElement { element: "foo".into(), }; assert_ser_de( &MarionetteResult::WebElement(data), json!({"value": {ELEMENT_KEY: "foo"}}), ); } #[test] fn test_web_elements_response() { let data = vec![ WebElement { element: "foo".into(), }, WebElement { element: "bar".into(), }, ]; assert_ser_de( &MarionetteResult::WebElements(data), json!([{ELEMENT_KEY: "foo"}, {ELEMENT_KEY: "bar"}]), ); } #[test] fn test_timeouts_response() { let data = Timeouts { implicit: Some(1000), page_load: Some(200000), script: Some(Some(60000)), }; assert_ser_de( &MarionetteResult::Timeouts(data), json!({"implicit":1000,"pageLoad":200000,"script":60000}), ); } #[test] fn test_string_response() { assert_ser_de( &MarionetteResult::String("foo".into()), json!({"value": "foo"}), ); } #[test] fn test_strings_response() { assert_ser_de( &MarionetteResult::Strings(vec!["2147483649".to_string()]), json!(["2147483649"]), ); } #[test] fn test_null_response() { assert_ser_de(&MarionetteResult::Null, json!({ "value": null })); } #[test] fn test_window_rect_response() { let data = WindowRect { x: 100, y: 100, width: 800, height: 600, }; let json = json!({"x": 100, "y": 100, "width": 800, "height": 600}); assert_ser_de(&MarionetteResult::WindowRect(data), json); } #[test] fn test_element_rect_response() { let data = ElementRect { x: 8.0, y: 8.0, width: 148.6666717529297, height: 22.0, }; let json = json!({"x": 8, "y": 8, "width": 148.6666717529297, "height": 22}); assert_de(&MarionetteResult::ElementRect(data), json); } }