1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 use serde::ser::{Serialize, Serializer};
6 use serde::{Deserialize, Deserializer};
7 use std::collections::HashMap;
8 use std::fmt::{self, Display, Formatter};
9
10 pub static ELEMENT_KEY: &str = "element-6066-11e4-a52e-4f735466cecf";
11 pub static FRAME_KEY: &str = "frame-075b-4da1-b6ba-e579c2d3230a";
12 pub static SHADOW_KEY: &str = "shadow-6066-11e4-a52e-4f735466cecf";
13 pub static WINDOW_KEY: &str = "window-fcc6-11e5-b4f8-330a88ab9d7f";
14
15 pub static MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
16
17 pub type Parameters = HashMap<String, String>;
18
19 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
20 pub struct Cookie {
21 pub name: String,
22 pub value: String,
23 pub path: Option<String>,
24 pub domain: Option<String>,
25 #[serde(default)]
26 pub secure: bool,
27 #[serde(rename = "httpOnly")]
28 pub http_only: bool,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub expiry: Option<Date>,
31 #[serde(skip_serializing_if = "Option::is_none", rename = "sameSite")]
32 pub same_site: Option<String>,
33 }
34
35 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
36 pub struct Date(pub u64);
37
38 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
39 #[serde(untagged)]
40 pub enum FrameId {
41 Short(u16),
42 #[serde(
43 rename = "element-6066-11e4-a52e-4f735466cecf",
44 serialize_with = "serialize_webelement_id"
45 )]
46 Element(WebElement),
47 }
48
49 // TODO(Henrik): Remove when ToMarionette trait has been fixed (Bug 1481776)
serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,50 fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
51 where
52 S: Serializer,
53 {
54 element.serialize(serializer)
55 }
56
57 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
58 pub enum LocatorStrategy {
59 #[serde(rename = "css selector")]
60 CSSSelector,
61 #[serde(rename = "link text")]
62 LinkText,
63 #[serde(rename = "partial link text")]
64 PartialLinkText,
65 #[serde(rename = "tag name")]
66 TagName,
67 #[serde(rename = "xpath")]
68 XPath,
69 }
70
71 #[derive(Clone, Debug, PartialEq)]
72 pub struct ShadowRoot(pub String);
73
74 // private
75 #[derive(Serialize, Deserialize)]
76 struct ShadowRootObject {
77 #[serde(rename = "shadow-6066-11e4-a52e-4f735466cecf")]
78 id: String,
79 }
80
81 impl Serialize for ShadowRoot {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,82 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83 where
84 S: Serializer,
85 {
86 ShadowRootObject { id: self.0.clone() }.serialize(serializer)
87 }
88 }
89
90 impl<'de> Deserialize<'de> for ShadowRoot {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,91 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92 where
93 D: Deserializer<'de>,
94 {
95 Deserialize::deserialize(deserializer).map(|ShadowRootObject { id }| ShadowRoot(id))
96 }
97 }
98
99 impl Display for ShadowRoot {
fmt(&self, f: &mut Formatter) -> fmt::Result100 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
101 write!(f, "{}", self.0)
102 }
103 }
104
105 #[derive(Clone, Debug, PartialEq)]
106 pub struct WebElement(pub String);
107
108 // private
109 #[derive(Serialize, Deserialize)]
110 struct WebElementObject {
111 #[serde(rename = "element-6066-11e4-a52e-4f735466cecf")]
112 id: String,
113 }
114
115 impl Serialize for WebElement {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,116 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117 where
118 S: Serializer,
119 {
120 WebElementObject { id: self.0.clone() }.serialize(serializer)
121 }
122 }
123
124 impl<'de> Deserialize<'de> for WebElement {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,125 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126 where
127 D: Deserializer<'de>,
128 {
129 Deserialize::deserialize(deserializer).map(|WebElementObject { id }| WebElement(id))
130 }
131 }
132
133 impl Display for WebElement {
fmt(&self, f: &mut Formatter) -> fmt::Result134 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
135 write!(f, "{}", self.0)
136 }
137 }
138
139 #[derive(Clone, Debug, PartialEq)]
140 pub struct WebFrame(pub String);
141
142 // private
143 #[derive(Serialize, Deserialize)]
144 struct WebFrameObject {
145 #[serde(rename = "frame-075b-4da1-b6ba-e579c2d3230a")]
146 id: String,
147 }
148
149 impl Serialize for WebFrame {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,150 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151 where
152 S: Serializer,
153 {
154 WebFrameObject { id: self.0.clone() }.serialize(serializer)
155 }
156 }
157
158 impl<'de> Deserialize<'de> for WebFrame {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,159 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160 where
161 D: Deserializer<'de>,
162 {
163 Deserialize::deserialize(deserializer).map(|WebFrameObject { id }| WebFrame(id))
164 }
165 }
166
167 #[derive(Clone, Debug, PartialEq)]
168 pub struct WebWindow(pub String);
169
170 // private
171 #[derive(Serialize, Deserialize)]
172 struct WebWindowObject {
173 #[serde(rename = "window-fcc6-11e5-b4f8-330a88ab9d7f")]
174 id: String,
175 }
176
177 impl Serialize for WebWindow {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,178 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179 where
180 S: Serializer,
181 {
182 WebWindowObject { id: self.0.clone() }.serialize(serializer)
183 }
184 }
185
186 impl<'de> Deserialize<'de> for WebWindow {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,187 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188 where
189 D: Deserializer<'de>,
190 {
191 Deserialize::deserialize(deserializer).map(|WebWindowObject { id }| WebWindow(id))
192 }
193 }
194
195 #[cfg(test)]
196 mod tests {
197 use super::*;
198 use crate::test::{assert_ser, assert_ser_de};
199 use serde_json::{self, json};
200
201 #[test]
test_json_date()202 fn test_json_date() {
203 assert_ser_de(&Date(1234), json!(1234));
204 }
205
206 #[test]
test_json_date_invalid()207 fn test_json_date_invalid() {
208 assert!(serde_json::from_value::<Date>(json!("2018-01-01")).is_err());
209 }
210
211 #[test]
test_json_frame_id_short()212 fn test_json_frame_id_short() {
213 assert_ser_de(&FrameId::Short(1234), json!(1234));
214 }
215
216 #[test]
test_json_frame_id_webelement()217 fn test_json_frame_id_webelement() {
218 assert_ser(
219 &FrameId::Element(WebElement("elem".into())),
220 json!({ELEMENT_KEY: "elem"}),
221 );
222 }
223
224 #[test]
test_json_frame_id_invalid()225 fn test_json_frame_id_invalid() {
226 assert!(serde_json::from_value::<FrameId>(json!(true)).is_err());
227 }
228
229 #[test]
test_json_locator_strategy_css_selector()230 fn test_json_locator_strategy_css_selector() {
231 assert_ser_de(&LocatorStrategy::CSSSelector, json!("css selector"));
232 }
233
234 #[test]
test_json_locator_strategy_link_text()235 fn test_json_locator_strategy_link_text() {
236 assert_ser_de(&LocatorStrategy::LinkText, json!("link text"));
237 }
238
239 #[test]
test_json_locator_strategy_partial_link_text()240 fn test_json_locator_strategy_partial_link_text() {
241 assert_ser_de(
242 &LocatorStrategy::PartialLinkText,
243 json!("partial link text"),
244 );
245 }
246
247 #[test]
test_json_locator_strategy_tag_name()248 fn test_json_locator_strategy_tag_name() {
249 assert_ser_de(&LocatorStrategy::TagName, json!("tag name"));
250 }
251
252 #[test]
test_json_locator_strategy_xpath()253 fn test_json_locator_strategy_xpath() {
254 assert_ser_de(&LocatorStrategy::XPath, json!("xpath"));
255 }
256
257 #[test]
test_json_locator_strategy_invalid()258 fn test_json_locator_strategy_invalid() {
259 assert!(serde_json::from_value::<LocatorStrategy>(json!("foo")).is_err());
260 }
261
262 #[test]
test_json_shadowroot()263 fn test_json_shadowroot() {
264 assert_ser_de(&ShadowRoot("shadow".into()), json!({SHADOW_KEY: "shadow"}));
265 }
266
267 #[test]
test_json_shadowroot_invalid()268 fn test_json_shadowroot_invalid() {
269 assert!(serde_json::from_value::<ShadowRoot>(json!({"invalid":"shadow"})).is_err());
270 }
271
272 #[test]
test_json_webelement()273 fn test_json_webelement() {
274 assert_ser_de(&WebElement("elem".into()), json!({ELEMENT_KEY: "elem"}));
275 }
276
277 #[test]
test_json_webelement_invalid()278 fn test_json_webelement_invalid() {
279 assert!(serde_json::from_value::<WebElement>(json!({"invalid": "elem"})).is_err());
280 }
281
282 #[test]
test_json_webframe()283 fn test_json_webframe() {
284 assert_ser_de(&WebFrame("frame".into()), json!({FRAME_KEY: "frame"}));
285 }
286
287 #[test]
test_json_webframe_invalid()288 fn test_json_webframe_invalid() {
289 assert!(serde_json::from_value::<WebFrame>(json!({"invalid": "frame"})).is_err());
290 }
291
292 #[test]
test_json_webwindow()293 fn test_json_webwindow() {
294 assert_ser_de(&WebWindow("window".into()), json!({WINDOW_KEY: "window"}));
295 }
296
297 #[test]
test_json_webwindow_invalid()298 fn test_json_webwindow_invalid() {
299 assert!(serde_json::from_value::<WebWindow>(json!({"invalid": "window"})).is_err());
300 }
301 }
302