Skip to main content

webdriver_server/
timeout.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 https://mozilla.org/MPL/2.0/. */
4
5use std::time::Duration;
6
7use serde_json::{Value, json};
8use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
9
10/// Initial script timeout from
11/// <https://w3c.github.io/webdriver/#dfn-timeouts-configuration>.
12pub(crate) const DEFAULT_SCRIPT_TIMEOUT: u64 = 30_000;
13
14/// Initial page load timeout from
15/// <https://w3c.github.io/webdriver/#dfn-timeouts-configuration>.
16pub(crate) const DEFAULT_PAGE_LOAD_TIMEOUT: u64 = 300_000;
17
18/// Initial initial wait timeout from
19/// <https://w3c.github.io/webdriver/#dfn-timeouts-configuration>.
20pub(crate) const DEFAULT_IMPLICIT_WAIT: u64 = 0;
21
22/// An amount of time to wait before considering that a screenshot has timed out.
23/// If after 10 seconds the screenshot cannot be taken, assume that the test has
24/// timed out.
25pub(crate) const SCREENSHOT_TIMEOUT: Duration = Duration::from_secs(10);
26
27/// <https://w3c.github.io/webdriver/#dfn-timeouts-configuration>
28/// A `None` timeout means waiting indefinitely.
29pub(crate) struct TimeoutsConfiguration {
30    pub(crate) script: Option<u64>,
31    pub(crate) page_load: Option<u64>,
32    pub(crate) implicit_wait: Option<u64>,
33    pub(crate) sleep_interval: u64,
34}
35
36impl Default for TimeoutsConfiguration {
37    fn default() -> Self {
38        TimeoutsConfiguration {
39            script: Some(DEFAULT_SCRIPT_TIMEOUT),
40            page_load: Some(DEFAULT_PAGE_LOAD_TIMEOUT),
41            implicit_wait: Some(DEFAULT_IMPLICIT_WAIT),
42            sleep_interval: 10,
43        }
44    }
45}
46
47/// <https://w3c.github.io/webdriver/#dfn-deserialize-as-timeouts-configuration>
48pub(crate) fn deserialize_as_timeouts_configuration(
49    timeouts: &Value,
50) -> WebDriverResult<TimeoutsConfiguration> {
51    if let Value::Object(map) = timeouts {
52        let mut config = TimeoutsConfiguration::default();
53
54        // Step 3: For each key → value in timeouts:
55        for (key, value) in map {
56            // Step 3.1: If «"script", "pageLoad", "implicit"» does not contain key, then continue.
57            let target = match key.as_str() {
58                "implicit" => &mut config.implicit_wait,
59                "pageLoad" => &mut config.page_load,
60                "script" => &mut config.script,
61                _ => continue,
62            };
63
64            // Step 3.2: If value is neither null nor a number greater than or equal to 0
65            // and less than or equal to the maximum safe integer return error with error
66            // code invalid argument.
67            // Step 3.3: Run the substeps matching key:
68            //  - "script": Set configuration's script timeout to value.
69            //  - "pageLoad": Set configuration's page load timeout to value.
70            //  - "implicit": Set configuration's implicit wait timeout to value.
71            *target = match value {
72                Value::Null => None,
73                Value::Number(num) => Some(
74                    num.as_f64()
75                        .expect("Number already validated when parsing requests")
76                        as u64,
77                ),
78                _ => unreachable!("This has been validated when parsing requests"),
79            };
80        }
81
82        Ok(config)
83    } else {
84        Err(WebDriverError::new(
85            ErrorStatus::InvalidArgument,
86            "Expected an object for timeouts",
87        ))
88    }
89}
90
91/// <https://w3c.github.io/webdriver/#dfn-serialize-the-timeouts-configuration>
92pub(crate) fn serialize_timeouts_configuration(timeouts: &TimeoutsConfiguration) -> Value {
93    json!({
94        "script": timeouts.script,
95        "pageLoad": timeouts.page_load,
96        "implicit": timeouts.implicit_wait,
97    })
98}