Skip to main content

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, Credentials};
6use serde::ser::{Serialize, Serializer};
7use serde_json::Value;
8
9#[derive(Debug, PartialEq, Serialize)]
10#[serde(untagged, remote = "Self")]
11pub enum WebDriverResponse {
12    CloseWindow(CloseWindowResponse),
13    Cookie(CookieResponse),
14    Cookies(CookiesResponse),
15    DeleteSession,
16    ElementRect(ElementRectResponse),
17    Generic(ValueResponse),
18    NewSession(NewSessionResponse),
19    NewWindow(NewWindowResponse),
20    Timeouts(TimeoutsResponse),
21    Void,
22    WebAuthnAddVirtualAuthenticator(u64),
23    WebAuthnGetCredentials(GetCredentialsResponse),
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<Credentials>);
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: Option<u64>,
107    pub implicit: Option<u64>,
108}
109
110impl TimeoutsResponse {
111    pub fn new(
112        script: Option<u64>,
113        page_load: Option<u64>,
114        implicit: Option<u64>,
115    ) -> TimeoutsResponse {
116        TimeoutsResponse {
117            script,
118            page_load,
119            implicit,
120        }
121    }
122}
123
124#[derive(Debug, PartialEq, Serialize)]
125pub struct ValueResponse(pub Value);
126
127#[derive(Debug, PartialEq, Serialize)]
128pub struct WindowRectResponse {
129    /// `WindowProxy`’s [screenX] attribute.
130    ///
131    /// [screenX]: https://drafts.csswg.org/cssom-view/#dom-window-screenx
132    pub x: i32,
133
134    /// `WindowProxy`’s [screenY] attribute.
135    ///
136    /// [screenY]: https://drafts.csswg.org/cssom-view/#dom-window-screeny
137    pub y: i32,
138
139    /// Width of the top-level browsing context’s outer dimensions, including
140    /// any browser chrome and externally drawn window decorations in CSS
141    /// reference pixels.
142    pub width: i32,
143
144    /// Height of the top-level browsing context’s outer dimensions, including
145    /// any browser chrome and externally drawn window decorations in CSS
146    /// reference pixels.
147    pub height: i32,
148}
149
150#[cfg(test)]
151mod tests {
152    use serde_json::{json, Map};
153
154    use super::*;
155    use crate::common::Date;
156    use crate::test::assert_ser;
157
158    #[test]
159    fn test_json_new_window_response() {
160        let json = json!({"value": {"handle": "42", "type": "window"}});
161        let response = WebDriverResponse::NewWindow(NewWindowResponse {
162            handle: "42".into(),
163            typ: "window".into(),
164        });
165
166        assert_ser(&response, json);
167    }
168
169    #[test]
170    fn test_json_close_window_response() {
171        assert_ser(
172            &WebDriverResponse::CloseWindow(CloseWindowResponse(vec!["1234".into()])),
173            json!({"value": ["1234"]}),
174        );
175    }
176
177    #[test]
178    fn test_json_cookie_response_with_optional() {
179        let json = json!({"value": {
180            "name": "foo",
181            "value": "bar",
182            "path": "/",
183            "domain": "foo.bar",
184            "secure": true,
185            "httpOnly": false,
186            "expiry": 123,
187            "sameSite": "Strict",
188        }});
189        let response = WebDriverResponse::Cookie(CookieResponse(Cookie {
190            name: "foo".into(),
191            value: "bar".into(),
192            path: Some("/".into()),
193            domain: Some("foo.bar".into()),
194            expiry: Some(Date(123)),
195            secure: true,
196            http_only: false,
197            same_site: Some("Strict".into()),
198        }));
199
200        assert_ser(&response, json);
201    }
202
203    #[test]
204    fn test_json_cookie_response_without_optional() {
205        let json = json!({"value": {
206            "name": "foo",
207            "value": "bar",
208            "path": "/",
209            "domain": null,
210            "secure": true,
211            "httpOnly": false,
212        }});
213        let response = WebDriverResponse::Cookie(CookieResponse(Cookie {
214            name: "foo".into(),
215            value: "bar".into(),
216            path: Some("/".into()),
217            domain: None,
218            expiry: None,
219            secure: true,
220            http_only: false,
221            same_site: None,
222        }));
223
224        assert_ser(&response, json);
225    }
226
227    #[test]
228    fn test_json_cookies_response() {
229        let json = json!({"value": [{
230            "name": "name",
231            "value": "value",
232            "path": "/",
233            "domain": null,
234            "secure": true,
235            "httpOnly": false,
236            "sameSite": "None",
237        }]});
238        let response = WebDriverResponse::Cookies(CookiesResponse(vec![Cookie {
239            name: "name".into(),
240            value: "value".into(),
241            path: Some("/".into()),
242            domain: None,
243            expiry: None,
244            secure: true,
245            http_only: false,
246            same_site: Some("None".into()),
247        }]));
248
249        assert_ser(&response, json);
250    }
251
252    #[test]
253    fn test_json_delete_session_response() {
254        assert_ser(&WebDriverResponse::DeleteSession, json!({ "value": null }));
255    }
256
257    #[test]
258    fn test_json_element_rect_response() {
259        let json = json!({"value": {
260            "x": 0.0,
261            "y": 1.0,
262            "width": 2.0,
263            "height": 3.0,
264        }});
265        let response = WebDriverResponse::ElementRect(ElementRectResponse {
266            x: 0f64,
267            y: 1f64,
268            width: 2f64,
269            height: 3f64,
270        });
271
272        assert_ser(&response, json);
273    }
274
275    #[test]
276    fn test_json_generic_value_response() {
277        let response = {
278            let mut value = Map::new();
279            value.insert(
280                "example".into(),
281                Value::Array(vec![Value::String("test".into())]),
282            );
283            WebDriverResponse::Generic(ValueResponse(Value::Object(value)))
284        };
285        assert_ser(&response, json!({"value": {"example": ["test"]}}));
286    }
287
288    #[test]
289    fn test_json_new_session_response() {
290        let response =
291            WebDriverResponse::NewSession(NewSessionResponse::new("id".into(), json!({})));
292        assert_ser(
293            &response,
294            json!({"value": {"sessionId": "id", "capabilities": {}}}),
295        );
296    }
297
298    #[test]
299    fn test_json_timeouts_response() {
300        assert_ser(
301            &WebDriverResponse::Timeouts(TimeoutsResponse::new(Some(1), Some(2), Some(3))),
302            json!({"value": {"script": 1, "pageLoad": 2, "implicit": 3}}),
303        );
304    }
305
306    #[test]
307    fn test_json_timeouts_response_with_null_timeout() {
308        assert_ser(
309            &WebDriverResponse::Timeouts(TimeoutsResponse::new(None, None, None)),
310            json!({"value": {"script": null, "pageLoad": null, "implicit": null}}),
311        );
312    }
313
314    #[test]
315    fn test_json_void_response() {
316        assert_ser(&WebDriverResponse::Void, json!({ "value": null }));
317    }
318
319    #[test]
320    fn test_json_window_rect_response() {
321        let json = json!({"value": {
322            "x": 0,
323            "y": 1,
324            "width": 2,
325            "height": 3,
326        }});
327        let response = WebDriverResponse::WindowRect(WindowRectResponse {
328            x: 0i32,
329            y: 1i32,
330            width: 2i32,
331            height: 3i32,
332        });
333
334        assert_ser(&response, json);
335    }
336}