webdriver/
response.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 crate::common::{Cookie, CredentialParameters};
6use serde::ser::{Serialize, Serializer};
7use serde_json::Value;
8
9#[derive(Debug, PartialEq, Serialize)]
10#[serde(untagged, remote = "Self")]
11pub enum WebDriverResponse {
12    NewWindow(NewWindowResponse),
13    CloseWindow(CloseWindowResponse),
14    Cookie(CookieResponse),
15    Cookies(CookiesResponse),
16    DeleteSession,
17    ElementRect(ElementRectResponse),
18    Generic(ValueResponse),
19    WebAuthnAddVirtualAuthenticator(u64),
20    WebAuthnGetCredentials(GetCredentialsResponse),
21    NewSession(NewSessionResponse),
22    Timeouts(TimeoutsResponse),
23    Void,
24    WindowRect(WindowRectResponse),
25}
26
27impl Serialize for WebDriverResponse {
28    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
29    where
30        S: Serializer,
31    {
32        #[derive(Serialize)]
33        struct Wrapper<'a> {
34            #[serde(with = "WebDriverResponse")]
35            value: &'a WebDriverResponse,
36        }
37
38        Wrapper { value: self }.serialize(serializer)
39    }
40}
41
42#[derive(Debug, PartialEq, Serialize)]
43pub struct NewWindowResponse {
44    pub handle: String,
45    #[serde(rename = "type")]
46    pub typ: String,
47}
48
49#[derive(Debug, PartialEq, Serialize)]
50pub struct CloseWindowResponse(pub Vec<String>);
51
52#[derive(Clone, Debug, PartialEq, Serialize)]
53pub struct CookieResponse(pub Cookie);
54
55#[derive(Debug, PartialEq, Serialize)]
56pub struct CookiesResponse(pub Vec<Cookie>);
57
58#[derive(Debug, PartialEq, Serialize)]
59pub struct ElementRectResponse {
60    /// X axis position of the top-left corner of the element relative
61    /// to the current browsing context’s document element in CSS reference
62    /// pixels.
63    pub x: f64,
64
65    /// Y axis position of the top-left corner of the element relative
66    /// to the current browsing context’s document element in CSS reference
67    /// pixels.
68    pub y: f64,
69
70    /// Height of the element’s [bounding rectangle] in CSS reference
71    /// pixels.
72    ///
73    /// [bounding rectangle]: https://drafts.fxtf.org/geometry/#rectangle
74    pub width: f64,
75
76    /// Width of the element’s [bounding rectangle] in CSS reference
77    /// pixels.
78    ///
79    /// [bounding rectangle]: https://drafts.fxtf.org/geometry/#rectangle
80    pub height: f64,
81}
82
83#[derive(Debug, PartialEq, Serialize)]
84pub struct GetCredentialsResponse(pub Vec<CredentialParameters>);
85
86#[derive(Debug, PartialEq, Serialize)]
87pub struct NewSessionResponse {
88    #[serde(rename = "sessionId")]
89    pub session_id: String,
90    pub capabilities: Value,
91}
92
93impl NewSessionResponse {
94    pub fn new(session_id: String, capabilities: Value) -> NewSessionResponse {
95        NewSessionResponse {
96            session_id,
97            capabilities,
98        }
99    }
100}
101
102#[derive(Debug, PartialEq, Serialize)]
103pub struct TimeoutsResponse {
104    pub script: Option<u64>,
105    #[serde(rename = "pageLoad")]
106    pub page_load: u64,
107    pub implicit: u64,
108}
109
110impl TimeoutsResponse {
111    pub fn new(script: Option<u64>, page_load: u64, implicit: u64) -> TimeoutsResponse {
112        TimeoutsResponse {
113            script,
114            page_load,
115            implicit,
116        }
117    }
118}
119
120#[derive(Debug, PartialEq, Serialize)]
121pub struct ValueResponse(pub Value);
122
123#[derive(Debug, PartialEq, Serialize)]
124pub struct WindowRectResponse {
125    /// `WindowProxy`’s [screenX] attribute.
126    ///
127    /// [screenX]: https://drafts.csswg.org/cssom-view/#dom-window-screenx
128    pub x: i32,
129
130    /// `WindowProxy`’s [screenY] attribute.
131    ///
132    /// [screenY]: https://drafts.csswg.org/cssom-view/#dom-window-screeny
133    pub y: i32,
134
135    /// Width of the top-level browsing context’s outer dimensions, including
136    /// any browser chrome and externally drawn window decorations in CSS
137    /// reference pixels.
138    pub width: i32,
139
140    /// Height of the top-level browsing context’s outer dimensions, including
141    /// any browser chrome and externally drawn window decorations in CSS
142    /// reference pixels.
143    pub height: i32,
144}
145
146#[cfg(test)]
147mod tests {
148    use serde_json::{json, Map};
149
150    use super::*;
151    use crate::common::Date;
152    use crate::test::assert_ser;
153
154    #[test]
155    fn test_json_new_window_response() {
156        let json = json!({"value": {"handle": "42", "type": "window"}});
157        let response = WebDriverResponse::NewWindow(NewWindowResponse {
158            handle: "42".into(),
159            typ: "window".into(),
160        });
161
162        assert_ser(&response, json);
163    }
164
165    #[test]
166    fn test_json_close_window_response() {
167        assert_ser(
168            &WebDriverResponse::CloseWindow(CloseWindowResponse(vec!["1234".into()])),
169            json!({"value": ["1234"]}),
170        );
171    }
172
173    #[test]
174    fn test_json_cookie_response_with_optional() {
175        let json = json!({"value": {
176            "name": "foo",
177            "value": "bar",
178            "path": "/",
179            "domain": "foo.bar",
180            "secure": true,
181            "httpOnly": false,
182            "expiry": 123,
183            "sameSite": "Strict",
184        }});
185        let response = WebDriverResponse::Cookie(CookieResponse(Cookie {
186            name: "foo".into(),
187            value: "bar".into(),
188            path: Some("/".into()),
189            domain: Some("foo.bar".into()),
190            expiry: Some(Date(123)),
191            secure: true,
192            http_only: false,
193            same_site: Some("Strict".into()),
194        }));
195
196        assert_ser(&response, json);
197    }
198
199    #[test]
200    fn test_json_cookie_response_without_optional() {
201        let json = json!({"value": {
202            "name": "foo",
203            "value": "bar",
204            "path": "/",
205            "domain": null,
206            "secure": true,
207            "httpOnly": false,
208        }});
209        let response = WebDriverResponse::Cookie(CookieResponse(Cookie {
210            name: "foo".into(),
211            value: "bar".into(),
212            path: Some("/".into()),
213            domain: None,
214            expiry: None,
215            secure: true,
216            http_only: false,
217            same_site: None,
218        }));
219
220        assert_ser(&response, json);
221    }
222
223    #[test]
224    fn test_json_cookies_response() {
225        let json = json!({"value": [{
226            "name": "name",
227            "value": "value",
228            "path": "/",
229            "domain": null,
230            "secure": true,
231            "httpOnly": false,
232            "sameSite": "None",
233        }]});
234        let response = WebDriverResponse::Cookies(CookiesResponse(vec![Cookie {
235            name: "name".into(),
236            value: "value".into(),
237            path: Some("/".into()),
238            domain: None,
239            expiry: None,
240            secure: true,
241            http_only: false,
242            same_site: Some("None".into()),
243        }]));
244
245        assert_ser(&response, json);
246    }
247
248    #[test]
249    fn test_json_delete_session_response() {
250        assert_ser(&WebDriverResponse::DeleteSession, json!({ "value": null }));
251    }
252
253    #[test]
254    fn test_json_element_rect_response() {
255        let json = json!({"value": {
256            "x": 0.0,
257            "y": 1.0,
258            "width": 2.0,
259            "height": 3.0,
260        }});
261        let response = WebDriverResponse::ElementRect(ElementRectResponse {
262            x: 0f64,
263            y: 1f64,
264            width: 2f64,
265            height: 3f64,
266        });
267
268        assert_ser(&response, json);
269    }
270
271    #[test]
272    fn test_json_generic_value_response() {
273        let response = {
274            let mut value = Map::new();
275            value.insert(
276                "example".into(),
277                Value::Array(vec![Value::String("test".into())]),
278            );
279            WebDriverResponse::Generic(ValueResponse(Value::Object(value)))
280        };
281        assert_ser(&response, json!({"value": {"example": ["test"]}}));
282    }
283
284    #[test]
285    fn test_json_new_session_response() {
286        let response =
287            WebDriverResponse::NewSession(NewSessionResponse::new("id".into(), json!({})));
288        assert_ser(
289            &response,
290            json!({"value": {"sessionId": "id", "capabilities": {}}}),
291        );
292    }
293
294    #[test]
295    fn test_json_timeouts_response() {
296        assert_ser(
297            &WebDriverResponse::Timeouts(TimeoutsResponse::new(Some(1), 2, 3)),
298            json!({"value": {"script": 1, "pageLoad": 2, "implicit": 3}}),
299        );
300    }
301
302    #[test]
303    fn test_json_timeouts_response_with_null_script_timeout() {
304        assert_ser(
305            &WebDriverResponse::Timeouts(TimeoutsResponse::new(None, 2, 3)),
306            json!({"value": {"script": null, "pageLoad": 2, "implicit": 3}}),
307        );
308    }
309
310    #[test]
311    fn test_json_void_response() {
312        assert_ser(&WebDriverResponse::Void, json!({ "value": null }));
313    }
314
315    #[test]
316    fn test_json_window_rect_response() {
317        let json = json!({"value": {
318            "x": 0,
319            "y": 1,
320            "width": 2,
321            "height": 3,
322        }});
323        let response = WebDriverResponse::WindowRect(WindowRectResponse {
324            x: 0i32,
325            y: 1i32,
326            width: 2i32,
327            height: 3i32,
328        });
329
330        assert_ser(&response, json);
331    }
332}