Repository: servo/servo
File: components/webdriver_server/lib.rs (Rust)

Code before:
        // new Function() and then takes the resulting function and executes
        // it with a vec of arguments.
        let script = format!(
            "(function() {{ {}\n }})({})",
            func_body,
            args_string.join(", ")
        );
        debug!("{}", script);

        // Step 2. If session's current browsing context is no longer open,
        // return error with error code no such window.
        self.verify_browsing_context_is_open(self.browsing_context_id()?)?;

        // Step 3. Handle any user prompt.
        self.handle_any_user_prompts(self.webview_id()?)?;

        let (sender, receiver) = ipc::channel().unwrap();
        let cmd = WebDriverScriptCommand::ExecuteScript(script, sender);
        self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;

        let timeout_duration = self
            .session()?
            .session_timeouts()
            .script
            .map(Duration::from_millis);
        let result = wait_for_ipc_response_with_timeout(receiver, timeout_duration)?;

        self.postprocess_js_result(result)
    }

    fn handle_execute_async_script(
        &self,
        parameters: JavascriptCommandParameters,
    ) -> WebDriverResult<WebDriverResponse> {
        // Step 1. Let body and arguments be the result of trying to extract the script arguments
        // from a request with argument parameters.
        let (function_body, mut args_string) = self.extract_script_arguments(parameters)?;
        args_string.push("resolve".to_string());

        let timeout = self.session()?.session_timeouts().script;
        let timeout_script = timeout
            .map(|script_timeout| format!("setTimeout(webdriverTimeout, {script_timeout});"))
            .unwrap_or_default();

        let joined_args = args_string.join(", ");
        let script = format!(
            r#"(function() {{
              let webdriverPromise = new Promise(function(resolve, reject) {{
                  {timeout_script}
                  (async function() {{
                    {function_body}

Review comment (suggestion):
We need to map `ErrorStatus::Timeout` to `ErrorStatus::ScriptTimeout` here

Code after:

        // Step 5. Not needed because "In a session that is only a HTTP session
        // only one command can run at a time, so this will never block."

        // Step 6. Let undo actions be input cancel list in reverse order.

        let undo_actions = session
            .input_cancel_list_mut()
            .drain(..)
            .rev()
            .map(|(id, action_item)| Vec::from([(id, action_item)]))
            .collect();
        // Step 7. Dispatch undo actions with current browsing context.
        if let Err(err) = self.dispatch_actions(undo_actions, browsing_context_id) {
            return Err(WebDriverError::new(err, "Failed to dispatch undo actions"));
        }

        // Step 8. Reset the input state of session's current top-level browsing context.
        session.input_state_table_mut().clear();

        Ok(WebDriverResponse::Void)
    }

    /// <https://w3c.github.io/webdriver/#dfn-execute-script>
    fn handle_execute_script(
        &self,
        parameters: JavascriptCommandParameters,
    ) -> WebDriverResult<WebDriverResponse> {
        // Step 1. Let body and arguments be the result of trying to extract the script arguments
        // from a request with argument parameters.
        let (func_body, args_string) = self.extract_script_arguments(parameters)?;
        // This is pretty ugly; we really want something that acts like
        // new Function() and then takes the resulting function and executes
        // it with a vec of arguments.
        let script = format!(
            "(function() {{ {}\n }})({})",
            func_body,
            args_string.join(", ")
        );
        debug!("{}", script);

        // Step 2. If session's current browsing context is no longer open,
        // return error with error code no such window.
        self.verify_browsing_context_is_open(self.browsing_context_id()?)?;

        // Step 3. Handle any user prompt.
        self.handle_any_user_prompts(self.webview_id()?)?;

        let (sender, receiver) = ipc::channel().unwrap();
        let cmd = WebDriverScriptCommand::ExecuteScript(script, sender);
        self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;