webdriver: Add handle any user prompts step for all commands (#38035)

- Add `handler any user prompt` step for all commands.
- Enable webdriver tests which were blocked by `handle any user prompt`
step.

---------

Signed-off-by: batu_hoang <hoang.binh.trong@huawei.com>
This commit is contained in:
batu_hoang 2025-07-17 17:47:47 +08:00 committed by GitHub
parent 18d1a62add
commit 345733a5c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 859 additions and 472 deletions

View file

@ -66,6 +66,9 @@ use webdriver::response::{
use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler};
use crate::actions::{ActionItem, InputSourceState, PointerInputState};
use crate::user_prompt::{
UserPromptHandler, default_unhandled_prompt_behavior, deserialize_unhandled_prompt_behaviour,
};
#[derive(Default)]
pub struct WebDriverMessageIdGenerator {
@ -186,7 +189,7 @@ pub struct WebDriverSession {
strict_file_interactability: bool,
unhandled_prompt_behavior: String,
user_prompt_handler: UserPromptHandler,
/// <https://w3c.github.io/webdriver/#dfn-input-state-map>
input_state_table: RefCell<HashMap<String, InputSourceState>>,
@ -214,7 +217,7 @@ impl WebDriverSession {
page_loading_strategy: "normal".to_string(),
strict_file_interactability: false,
unhandled_prompt_behavior: "dismiss and notify".to_string(),
user_prompt_handler: UserPromptHandler::new(),
input_state_table: RefCell::new(HashMap::new()),
input_cancel_list: RefCell::new(Vec::new()),
@ -653,13 +656,14 @@ impl Handler {
match processed.get("unhandledPromptBehavior") {
Some(unhandled_prompt_behavior) => {
session.unhandled_prompt_behavior =
unhandled_prompt_behavior.to_string()
session.user_prompt_handler = deserialize_unhandled_prompt_behaviour(
unhandled_prompt_behavior.clone(),
)?;
},
None => {
processed.insert(
"unhandledPromptBehavior".to_string(),
json!(session.unhandled_prompt_behavior),
json!(default_unhandled_prompt_behavior()),
);
},
}
@ -777,6 +781,9 @@ impl Handler {
},
};
// Step 4. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
let cmd_msg =
WebDriverCommandMsg::LoadUrl(webview_id, url, self.load_status_sender.clone());
self.send_message_to_embedder(cmd_msg)?;
@ -839,6 +846,9 @@ impl Handler {
}
fn handle_current_url(&self) -> WebDriverResult<WebDriverResponse> {
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
self.top_level_script_command(
WebDriverScriptCommand::GetUrl(sender),
@ -864,6 +874,10 @@ impl Handler {
if let VerifyBrowsingContextIsOpen::Yes = verify {
self.verify_top_level_browsing_context_is_open(webview_id)?;
}
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
self.send_message_to_embedder(WebDriverCommandMsg::GetWindowRect(webview_id, sender))?;
let window_rect = wait_for_script_response(receiver)?;
@ -893,6 +907,9 @@ impl Handler {
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
// Step 13. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
// We don't current allow modifying the window x/y positions, so we can just
// return the current window rectangle if not changing dimension.
if params.width.is_none() && params.height.is_none() {
@ -975,6 +992,9 @@ impl Handler {
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
self.send_message_to_embedder(WebDriverCommandMsg::GoBack(
webview_id,
self.load_status_sender.clone(),
@ -988,6 +1008,9 @@ impl Handler {
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
self.send_message_to_embedder(WebDriverCommandMsg::GoForward(
webview_id,
self.load_status_sender.clone(),
@ -1001,6 +1024,9 @@ impl Handler {
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
let cmd_msg = WebDriverCommandMsg::Refresh(webview_id, self.load_status_sender.clone());
self.send_message_to_embedder(cmd_msg)?;
@ -1014,6 +1040,9 @@ impl Handler {
}
fn handle_title(&self) -> WebDriverResult<WebDriverResponse> {
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
self.top_level_script_command(
@ -1072,8 +1101,12 @@ impl Handler {
// Step 1. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
let session = self.session_mut().unwrap();
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
// Step 3. Close session's current top-level browsing context.
let session = self.session_mut().unwrap();
session.window_handles.remove(&webview_id);
let cmd_msg = WebDriverCommandMsg::CloseWebView(session.webview_id);
self.send_message_to_embedder(cmd_msg)?;
@ -1103,8 +1136,14 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let session = self.session().unwrap();
// Step 2. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(session.webview_id)?;
// Step 3. Handle any user prompt.
self.handle_any_user_prompts(session.webview_id)?;
let cmd_msg = WebDriverCommandMsg::NewWebView(sender, self.load_status_sender.clone());
// Step 5. Create a new top-level browsing context by running the window open steps.
// This MUST be done without invoking the focusing steps.
@ -1171,6 +1210,10 @@ impl Handler {
// Step 1.2. Return success with data null.
return Ok(WebDriverResponse::Void);
}
// Step 3. Handle any user prompt.
self.handle_any_user_prompts(webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetParentFrameId(sender);
// TODO: Track Parent Browsing Context directly in the session, as expected by Spec.
@ -1220,6 +1263,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetBrowsingContextId(frame_id, sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
self.handle_any_user_prompts(self.session()?.webview_id)?;
match wait_for_script_response(receiver)? {
Ok(browsing_context_id) => {
@ -1239,6 +1283,10 @@ impl Handler {
if parameters.value.is_empty() {
return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
}
// Step 6. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
match parameters.using {
LocatorStrategy::CSSSelector => {
@ -1304,6 +1352,10 @@ impl Handler {
if parameters.value.is_empty() {
return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
}
// Step 6. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
match parameters.using {
@ -1366,6 +1418,10 @@ impl Handler {
if parameters.value.is_empty() {
return Err(WebDriverError::new(ErrorStatus::InvalidArgument, ""));
}
// Step 6. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
match parameters.using {
@ -1432,6 +1488,7 @@ impl Handler {
}
fn handle_get_shadow_root(&self, element: WebElement) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementShadowRoot(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1450,6 +1507,7 @@ impl Handler {
// https://w3c.github.io/webdriver/webdriver-spec.html#get-element-rect
fn handle_element_rect(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementRect(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1469,6 +1527,7 @@ impl Handler {
/// <https://w3c.github.io/webdriver/#dfn-get-element-text>
fn handle_element_text(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementText(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1482,6 +1541,7 @@ impl Handler {
///<https://w3c.github.io/webdriver/#get-active-element>
fn handle_active_element(&self) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetActiveElement(sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1503,6 +1563,7 @@ impl Handler {
}
fn handle_computed_role(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetComputedRole(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1515,6 +1576,7 @@ impl Handler {
}
fn handle_element_tag_name(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementTagName(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1531,6 +1593,7 @@ impl Handler {
element: &WebElement,
name: &str,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementAttribute(
element.to_string(),
@ -1551,6 +1614,7 @@ impl Handler {
element: &WebElement,
name: &str,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementProperty(
@ -1573,6 +1637,7 @@ impl Handler {
element: &WebElement,
name: &str,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd =
WebDriverScriptCommand::GetElementCSS(element.to_string(), name.to_owned(), sender);
@ -1586,6 +1651,7 @@ impl Handler {
}
fn handle_get_cookies(&self) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookies(sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1601,6 +1667,7 @@ impl Handler {
}
fn handle_get_cookie(&self, name: String) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookie(name, sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1622,6 +1689,7 @@ impl Handler {
&self,
params: &AddCookieParameters,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cookie_builder = CookieBuilder::new(params.name.to_owned(), params.value.to_owned())
@ -1645,6 +1713,7 @@ impl Handler {
}
fn handle_delete_cookie(&self, name: String) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::DeleteCookie(name, sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1655,6 +1724,7 @@ impl Handler {
}
fn handle_delete_cookies(&self) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::DeleteCookies(sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1723,6 +1793,10 @@ impl Handler {
// Step 1. If session's current browsing context is no longer open,
// return error with error code no such window.
self.verify_browsing_context_is_open(browsing_context)?;
// Step 2. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
// Step 5. Let actions by tick be the result of trying to extract an action sequence
let actions_by_tick = self.extract_an_action_sequence(parameters);
@ -1741,7 +1815,8 @@ impl Handler {
// return error with error code no such window.
self.verify_browsing_context_is_open(session.browsing_context_id)?;
// TODO: Step 2. User prompts. No user prompt implemented yet.
// Step 2. User prompts. No user prompt implemented yet.
self.handle_any_user_prompts(self.session()?.webview_id)?;
// Skip: Step 3. We don't support "browsing context input state map" yet.
@ -1774,6 +1849,8 @@ impl Handler {
&self,
parameters: &JavascriptCommandParameters,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let func_body = &parameters.script;
let args_string: Vec<_> = parameters
.args
@ -1804,6 +1881,8 @@ impl Handler {
&self,
parameters: &JavascriptCommandParameters,
) -> WebDriverResult<WebDriverResponse> {
self.handle_any_user_prompts(self.session()?.webview_id)?;
let func_body = &parameters.script;
let mut args_string: Vec<_> = parameters
.args
@ -1883,7 +1962,9 @@ impl Handler {
element: &WebElement,
keys: &SendKeysParameters,
) -> WebDriverResult<WebDriverResponse> {
// Step 3-8
// Step 4. Handle any user prompt.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::WillSendKeys(
element.to_string(),
@ -1914,6 +1995,14 @@ impl Handler {
/// <https://w3c.github.io/webdriver/#element-click>
fn handle_element_click(&mut self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
// Step 1. If session's current browsing context is no longer open,
// return error with error code no such window.
let browsing_context_id = self.session()?.browsing_context_id;
self.verify_browsing_context_is_open(browsing_context_id)?;
// Step 2. Handle any user prompts.
self.handle_any_user_prompts(self.session()?.webview_id)?;
let (sender, receiver) = ipc::channel().unwrap();
let webview_id = self.session()?.webview_id;
let browsing_context_id = self.session()?.browsing_context_id;
@ -2035,6 +2124,9 @@ impl Handler {
// Step 1. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(self.session()?.webview_id)?;
self.handle_any_user_prompts(self.session()?.webview_id)?;
let mut img = None;
let interval = 1000;

View file

@ -2,16 +2,180 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use embedder_traits::{WebDriverCommandMsg, WebDriverUserPromptAction};
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use base::id::WebViewId;
use embedder_traits::{WebDriverCommandMsg, WebDriverUserPrompt, WebDriverUserPromptAction};
use ipc_channel::ipc;
use serde_json::{Map, Value};
use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
use webdriver::response::{ValueResponse, WebDriverResponse};
use crate::{Handler, wait_for_script_response};
const KNOWN_PROMPT_HANDLERS: [&str; 5] = [
"dismiss",
"accept",
"dismiss and notify",
"accept and notify",
"ignore",
];
const VALID_PROMPT_TYPES: [&str; 6] = [
"alert",
"beforeUnload",
"confirm",
"default",
"file",
"prompt",
];
/// <https://w3c.github.io/webdriver/#dfn-prompt-handler-configuration>
#[derive(Clone, Debug)]
pub(crate) struct PromptHandlerConfiguration {
handler: WebDriverUserPromptAction,
notify: bool,
}
pub(crate) type UserPromptHandler = HashMap<WebDriverUserPrompt, PromptHandlerConfiguration>;
/// <https://w3c.github.io/webdriver/#dfn-deserialize-as-an-unhandled-prompt-behavior>
pub(crate) fn deserialize_unhandled_prompt_behaviour(
value_param: Value,
) -> Result<UserPromptHandler, WebDriverError> {
// Step 2-5.
let (value, is_string_value) = match value_param {
Value::Object(map) => (map, false),
Value::String(..) => {
let mut map = Map::new();
map.insert("fallbackDefault".to_string(), value_param);
(map, true)
},
_ => {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
"Expected an object or a string for unhandled prompt behavior.",
));
},
};
// Step 6. Let user prompt handler be a new empty map.
let mut user_prompt_handler = UserPromptHandler::new();
// Step 7. For each key-value pair in value:
for (prompt_type, handler) in value {
// Step 7.1. If `is_string_value` is false and prompt type is not one of
// the valid prompt types, return error with error code invalid argument.
if !is_string_value && !VALID_PROMPT_TYPES.contains(&prompt_type.as_str()) {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("Invalid prompt type: {}", prompt_type),
));
}
// Step 7.2. If known prompt handlers does not contain an entry with
// handler key `handler` return error with error code invalid argument.
let handle_str = match handler {
Value::String(s) => s,
_ => {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("Expected a string for handler, got: {:?}", handler),
));
},
};
if !KNOWN_PROMPT_HANDLERS.contains(&handle_str.as_str()) {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("Unknown prompt handler: {}", handle_str),
));
}
// Step 7.3 - 7.6.
let (handler, notify) = match handle_str.as_str() {
"accept and notify" => (
WebDriverUserPromptAction::new_from_str("accept").unwrap(),
true,
),
"dismiss and notify" => (
WebDriverUserPromptAction::new_from_str("dismiss").unwrap(),
true,
),
"ignore" => (
WebDriverUserPromptAction::new_from_str("ignore").unwrap(),
false,
),
"accept" => (
WebDriverUserPromptAction::new_from_str("accept").unwrap(),
false,
),
"dismiss" => (
WebDriverUserPromptAction::new_from_str("dismiss").unwrap(),
false,
),
_ => unreachable!(),
};
// Step 7.7 - 7.8.
user_prompt_handler.insert(
WebDriverUserPrompt::new_from_str(&prompt_type).unwrap(),
PromptHandlerConfiguration { handler, notify },
);
}
Ok(user_prompt_handler)
}
pub(crate) fn default_unhandled_prompt_behavior() -> &'static str {
"dismiss and notify"
}
/// <https://www.w3.org/TR/webdriver2/#dfn-get-the-prompt-handler>
fn get_user_prompt_handler(
user_prompt_handler: &UserPromptHandler,
prompt_type: WebDriverUserPrompt,
) -> PromptHandlerConfiguration {
// Step 2. If handlers contains type return handlers[type].
if let Some(handler) = user_prompt_handler.get(&prompt_type) {
return (*handler).clone();
}
// Step 3. If handlers contains default return handlers[default].
if let Some(handler) = user_prompt_handler.get(&WebDriverUserPrompt::Default) {
return (*handler).clone();
}
// Step 4. If prompt type is "beforeUnload" return a configuration with handler "accept" and notify false.
if prompt_type == WebDriverUserPrompt::BeforeUnload {
return PromptHandlerConfiguration {
handler: WebDriverUserPromptAction::Accept,
notify: false,
};
}
// Step 5. If handlers contains fallbackDefault return handlers[fallbackDefault].
if let Some(handler) = user_prompt_handler.get(&WebDriverUserPrompt::FallbackDefault) {
return (*handler).clone();
}
// Step 6. Return a configuration with handler "dismiss" and notify true.
PromptHandlerConfiguration {
handler: WebDriverUserPromptAction::Dismiss,
notify: true,
}
}
fn webdriver_response_single_data(
key: &'static str,
value: Value,
) -> Option<BTreeMap<Cow<'static, str>, Value>> {
Some([(Cow::Borrowed(key), value)].into_iter().collect())
}
impl Handler {
/// <https://w3c.github.io/webdriver/#dismiss-alert>
pub(crate) fn handle_dismiss_alert(&mut self) -> WebDriverResult<WebDriverResponse> {
pub(crate) fn handle_dismiss_alert(&self) -> WebDriverResult<WebDriverResponse> {
// Step 1. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(self.session()?.webview_id)?;
@ -31,12 +195,12 @@ impl Handler {
"No user prompt is currently active.",
)),
// Step 4. Return success with data null.
Ok(()) => Ok(WebDriverResponse::Void),
Ok(_) => Ok(WebDriverResponse::Void),
}
}
/// <https://w3c.github.io/webdriver/#accept-alert>
pub(crate) fn handle_accept_alert(&mut self) -> WebDriverResult<WebDriverResponse> {
pub(crate) fn handle_accept_alert(&self) -> WebDriverResult<WebDriverResponse> {
// Step 1. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(self.session()?.webview_id)?;
@ -56,11 +220,11 @@ impl Handler {
"No user prompt is currently active.",
)),
// Step 4. Return success with data null.
Ok(()) => Ok(WebDriverResponse::Void),
Ok(_) => Ok(WebDriverResponse::Void),
}
}
pub(crate) fn handle_get_alert_text(&mut self) -> WebDriverResult<WebDriverResponse> {
pub(crate) fn handle_get_alert_text(&self) -> WebDriverResult<WebDriverResponse> {
// Step 1. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(self.session()?.webview_id)?;
@ -90,4 +254,49 @@ impl Handler {
))),
}
}
/// <https://w3c.github.io/webdriver/#dfn-handle-any-user-prompts>
pub(crate) fn handle_any_user_prompts(
&self,
webview_id: WebViewId,
) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::CurrentUserPrompt(webview_id, sender))?;
match wait_for_script_response(receiver)? {
// Step 1. If the current user prompt is null, return success with data null.
None => Ok(WebDriverResponse::Void),
Some(prompt_type) => {
// Step 2 - 4. Get user prompt handler for the prompt type.
let handler =
get_user_prompt_handler(&self.session()?.user_prompt_handler, prompt_type);
// Step 5. Perform the substeps based on handler's handler
let (sender, receiver) = ipc::channel().unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::HandleUserPrompt(
webview_id,
handler.handler.clone(),
sender,
))?;
if handler.notify || handler.handler == WebDriverUserPromptAction::Ignore {
// Step 6. If handler's notify is true, return annotated unexpected alert open error.
let alert_text = wait_for_script_response(receiver)?
.unwrap_or_default()
.unwrap_or_default();
Err(WebDriverError::new_with_data(
ErrorStatus::UnexpectedAlertOpen,
"Handle any user prompt: Unexpected alert open.",
webdriver_response_single_data("text", Value::String(alert_text)),
None,
))
} else {
// Step 7. Return success with data null.
Ok(WebDriverResponse::Void)
}
},
}
}
}