webdriver/
common.rs

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