webdriver: Implement send alert text (#38140)

Implement webdriver `SendAlertText` command

Tests:
https://github.com/longvatrong111/servo/actions/runs/16342669929
https://github.com/longvatrong111/servo/actions/runs/16342671477

cc: @xiaochengh

---------

Signed-off-by: batu_hoang <hoang.binh.trong@huawei.com>
Signed-off-by: batu_hoang <longvatrong111@gmail.com>
This commit is contained in:
batu_hoang 2025-07-18 05:24:50 +08:00 committed by GitHub
parent 3ce95b2ba5
commit f0e10e63e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 91 additions and 46 deletions

View file

@ -172,6 +172,14 @@ impl SimpleDialog {
}
}
pub fn set_message(&mut self, text: String) {
match self {
SimpleDialog::Alert { message, .. } => *message = text,
SimpleDialog::Confirm { message, .. } => *message = text,
SimpleDialog::Prompt { message, .. } => *message = text,
}
}
pub fn dismiss(&self) {
match self {
SimpleDialog::Alert {

View file

@ -166,6 +166,7 @@ pub enum WebDriverCommandMsg {
IpcSender<Result<Option<String>, ()>>,
),
GetAlertText(WebViewId, IpcSender<Result<String, ()>>),
SendAlertText(WebViewId, String),
AddLoadStatusSender(WebViewId, IpcSender<WebDriverLoadStatus>),
RemoveLoadStatusSender(WebViewId),
}

View file

@ -827,10 +827,13 @@ impl Handler {
recv(self.load_status_receiver) -> res => {
match res {
Ok(WebDriverLoadStatus::Blocked) => {
Err(WebDriverError::new(
ErrorStatus::UnexpectedAlertOpen,
"Load is blocked",
))
// TODO: evaluate the correctness later
// Load status is block means an user prompt is shown.
// Alot of tests expect this to return success
// then the user prompt is handled in the next command.
// If user prompt can't be handler, next command returns
// an error anyway.
Ok(WebDriverResponse::Void)
}
_ => {
Ok(WebDriverResponse::Void)
@ -2519,6 +2522,7 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
WebDriverCommand::DismissAlert => self.handle_dismiss_alert(),
WebDriverCommand::AcceptAlert => self.handle_accept_alert(),
WebDriverCommand::GetAlertText => self.handle_get_alert_text(),
WebDriverCommand::SendAlertText(text) => self.handle_send_alert_text(text.text),
WebDriverCommand::DeleteCookies => self.handle_delete_cookies(),
WebDriverCommand::DeleteCookie(name) => self.handle_delete_cookie(name),
WebDriverCommand::GetTimeouts => self.handle_get_timeouts(),

View file

@ -224,6 +224,7 @@ impl Handler {
}
}
/// <https://www.w3.org/TR/webdriver2/#dfn-get-alert-text>
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.
@ -255,6 +256,56 @@ impl Handler {
}
}
/// <https://www.w3.org/TR/webdriver2/#dfn-send-alert-text>
pub(crate) fn handle_send_alert_text(
&self,
text: String,
) -> WebDriverResult<WebDriverResponse> {
let webview_id = self.session()?.webview_id;
// Step 3. 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 (sender, receiver) = ipc::channel().unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::CurrentUserPrompt(webview_id, sender))?;
match wait_for_script_response(receiver)? {
// Step 4. If the current user prompt is null, return error with error code no such alert.
None => Err(WebDriverError::new(
ErrorStatus::NoSuchAlert,
"No user prompt is currently active.",
)),
Some(prompt_type) => {
match prompt_type {
// Step 5. If the current user prompt is alert or confirm,
// return error with error code element not interactable.
WebDriverUserPrompt::Alert | WebDriverUserPrompt::Confirm => {
Err(WebDriverError::new(
ErrorStatus::ElementNotInteractable,
"Cannot send text to an alert or confirm prompt.",
))
},
// Step 5. If the current user prompt is prompt
WebDriverUserPrompt::Prompt => {
// Step 6. Send the text to the current user prompt.
self.send_message_to_embedder(WebDriverCommandMsg::SendAlertText(
webview_id, text,
))?;
Ok(WebDriverResponse::Void)
},
// Step 5. Otherwise, return error with error code unsupported operation.
_ => Err(WebDriverError::new(
ErrorStatus::UnsupportedOperation,
"Current user prompt type is not supported.",
)),
}
},
}
}
/// <https://w3c.github.io/webdriver/#dfn-handle-any-user-prompts>
pub(crate) fn handle_any_user_prompts(
&self,

View file

@ -620,6 +620,9 @@ impl App {
warn!("Failed to send response of GetAlertText: {error}");
};
},
WebDriverCommandMsg::SendAlertText(webview_id, text) => {
running_state.set_alert_text_of_newest_dialog(webview_id, text);
},
WebDriverCommandMsg::TakeScreenshot(..) => {
warn!(
"WebDriverCommand {:?} is still not moved from constellation to embedder",

View file

@ -381,6 +381,14 @@ impl RunningAppState {
.and_then(|dialog| dialog.message())
}
pub(crate) fn set_alert_text_of_newest_dialog(&self, webview_id: WebViewId, text: String) {
if let Some(dialogs) = self.inner_mut().dialogs.get_mut(&webview_id) {
if let Some(dialog) = dialogs.last_mut() {
dialog.set_message(text);
}
}
}
pub(crate) fn get_focused_webview_index(&self) -> Option<usize> {
let focused_id = self.inner().focused_webview_id?;
self.webviews()

View file

@ -168,6 +168,12 @@ impl Dialog {
}
}
pub fn set_message(&mut self, text: String) {
if let Dialog::SimpleDialog(dialog) = self {
dialog.set_message(text);
}
}
pub fn update(&mut self, ctx: &egui::Context) -> bool {
match self {
Dialog::File {

View file

@ -3,7 +3,7 @@
expected: ERROR
[test_accept_confirm]
expected: FAIL
expected: ERROR
[test_accept_prompt]
expected: FAIL
@ -11,11 +11,8 @@
[test_accept_in_popup_window]
expected: FAIL
[test_null_response_value]
expected: FAIL
[test_accept_alert]
expected: FAIL
[test_unexpected_alert]
expected: FAIL
[test_no_browsing_context]
expected: ERROR

View file

@ -3,7 +3,7 @@
expected: ERROR
[test_dismiss_confirm]
expected: FAIL
expected: ERROR
[test_dismiss_prompt]
expected: FAIL
@ -11,11 +11,8 @@
[test_dismiss_in_popup_window]
expected: FAIL
[test_null_response_value]
expected: FAIL
[test_dismiss_alert]
expected: FAIL
[test_unexpected_alert]
expected: FAIL
[test_no_browsing_context]
expected: ERROR

View file

@ -1,31 +1,4 @@
[send.py]
[test_null_response_value]
expected: ERROR
[test_invalid_input[None\]]
expected: ERROR
[test_invalid_input[text1\]]
expected: ERROR
[test_invalid_input[42\]]
expected: ERROR
[test_no_top_browsing_context]
expected: FAIL
[test_no_browsing_context]
expected: FAIL
[test_no_user_prompt]
expected: FAIL
[test_alert_element_not_interactable[alert\]]
expected: FAIL
[test_alert_element_not_interactable[confirm\]]
expected: FAIL
[test_chained_alert_element_not_interactable[alert\]]
expected: FAIL
@ -43,6 +16,3 @@
[test_send_alert_text[Fed\\terer\]]
expected: FAIL
[test_unexpected_alert]
expected: FAIL