mirror of
https://github.com/servo/servo.git
synced 2025-07-16 20:03:39 +01:00
webdriver: Evaluate script commands via the WebView
API in servoshell (#37663)
Let `WebDriverCommandMsg::ScriptCommand` goes through embedder first. Give `embedder` the ability to release `webdriver` from waiting for a response of `ExecuteScript`. Tests: https://github.com/longvatrong111/servo/actions/runs/16071375821 No regression compared to CI run on main branch. Fixes: https://github.com/servo/servo/issues/37370 cc: @xiaochengh --------- Signed-off-by: batu_hoang <longvatrong111@gmail.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
562d9e4a21
commit
4499fdeb2b
14 changed files with 75 additions and 150 deletions
|
@ -726,10 +726,10 @@ impl Handler {
|
||||||
if let VerifyBrowsingContextIsOpen::Yes = verify {
|
if let VerifyBrowsingContextIsOpen::Yes = verify {
|
||||||
self.verify_browsing_context_is_open(browsing_context_id)?;
|
self.verify_browsing_context_is_open(browsing_context_id)?;
|
||||||
}
|
}
|
||||||
let msg = EmbedderToConstellationMessage::WebDriverCommand(
|
self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
|
||||||
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd_msg),
|
browsing_context_id,
|
||||||
);
|
cmd_msg,
|
||||||
self.constellation_chan.send(msg).unwrap();
|
))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,10 +746,10 @@ impl Handler {
|
||||||
self.verify_top_level_browsing_context_is_open(webview_id)?;
|
self.verify_top_level_browsing_context_is_open(webview_id)?;
|
||||||
}
|
}
|
||||||
let browsing_context_id = BrowsingContextId::from(webview_id);
|
let browsing_context_id = BrowsingContextId::from(webview_id);
|
||||||
let msg = EmbedderToConstellationMessage::WebDriverCommand(
|
self.send_message_to_embedder(WebDriverCommandMsg::ScriptCommand(
|
||||||
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd_msg),
|
browsing_context_id,
|
||||||
);
|
cmd_msg,
|
||||||
self.constellation_chan.send(msg).unwrap();
|
))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use servo::webrender_api::ScrollLocation;
|
||||||
use servo::webrender_api::units::DeviceIntSize;
|
use servo::webrender_api::units::DeviceIntSize;
|
||||||
use servo::{
|
use servo::{
|
||||||
EventLoopWaker, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent,
|
EventLoopWaker, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent,
|
||||||
WebDriverCommandMsg, WheelDelta, WheelEvent, WheelMode,
|
WebDriverCommandMsg, WebDriverScriptCommand, WheelDelta, WheelEvent, WheelMode,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
|
@ -542,7 +542,16 @@ impl App {
|
||||||
webview.notify_scroll_event(scroll_location, point.to_i32());
|
webview.notify_scroll_event(scroll_location, point.to_i32());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::ScriptCommand(..) |
|
WebDriverCommandMsg::ScriptCommand(
|
||||||
|
browsing_context_id,
|
||||||
|
webdriver_script_command,
|
||||||
|
) => {
|
||||||
|
self.handle_webdriver_script_commnd(&webdriver_script_command, running_state);
|
||||||
|
running_state.forward_webdriver_command(WebDriverCommandMsg::ScriptCommand(
|
||||||
|
browsing_context_id,
|
||||||
|
webdriver_script_command,
|
||||||
|
));
|
||||||
|
},
|
||||||
WebDriverCommandMsg::TakeScreenshot(..) => {
|
WebDriverCommandMsg::TakeScreenshot(..) => {
|
||||||
warn!(
|
warn!(
|
||||||
"WebDriverCommand {:?} is still not moved from constellation to embedder",
|
"WebDriverCommand {:?} is still not moved from constellation to embedder",
|
||||||
|
@ -552,6 +561,24 @@ impl App {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_webdriver_script_commnd(
|
||||||
|
&self,
|
||||||
|
msg: &WebDriverScriptCommand,
|
||||||
|
running_state: &RunningAppState,
|
||||||
|
) {
|
||||||
|
match msg {
|
||||||
|
WebDriverScriptCommand::ExecuteScript(_webview_id, response_sender) => {
|
||||||
|
// Give embedder a chance to interrupt the script command.
|
||||||
|
// Webdriver only handles 1 script command at a time, so we can
|
||||||
|
// safely set a new interrupt sender and remove the previous one here.
|
||||||
|
running_state.set_script_command_interrupt_sender(Some(response_sender.clone()));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
running_state.set_script_command_interrupt_sender(None);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler<AppEvent> for App {
|
impl ApplicationHandler<AppEvent> for App {
|
||||||
|
|
|
@ -19,7 +19,8 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||||
use servo::{
|
use servo::{
|
||||||
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
||||||
KeyboardEvent, LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog,
|
KeyboardEvent, LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog,
|
||||||
WebDriverCommandMsg, WebDriverLoadStatus, WebView, WebViewBuilder, WebViewDelegate,
|
WebDriverCommandMsg, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebView,
|
||||||
|
WebViewBuilder, WebViewDelegate,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ pub(crate) enum AppState {
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct WebDriverSenders {
|
struct WebDriverSenders {
|
||||||
pub load_status_senders: HashMap<WebViewId, IpcSender<WebDriverLoadStatus>>,
|
pub load_status_senders: HashMap<WebViewId, IpcSender<WebDriverLoadStatus>>,
|
||||||
|
pub script_evaluation_interrupt_sender: Option<IpcSender<WebDriverJSResult>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RunningAppState {
|
pub(crate) struct RunningAppState {
|
||||||
|
@ -406,6 +408,36 @@ impl RunningAppState {
|
||||||
.load_status_senders
|
.load_status_senders
|
||||||
.insert(webview_id, sender);
|
.insert(webview_id, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_script_command_interrupt_sender(
|
||||||
|
&self,
|
||||||
|
sender: Option<IpcSender<WebDriverJSResult>>,
|
||||||
|
) {
|
||||||
|
self.webdriver_senders
|
||||||
|
.borrow_mut()
|
||||||
|
.script_evaluation_interrupt_sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt any ongoing WebDriver-based script evaluation.
|
||||||
|
///
|
||||||
|
/// From <https://w3c.github.io/webdriver/#dfn-execute-a-function-body>:
|
||||||
|
/// > The rules to execute a function body are as follows. The algorithm returns
|
||||||
|
/// > an ECMAScript completion record.
|
||||||
|
/// >
|
||||||
|
/// > If at any point during the algorithm a user prompt appears, immediately return
|
||||||
|
/// > Completion { Type: normal, Value: null, Target: empty }, but continue to run the
|
||||||
|
/// > other steps of this algorithm in parallel.
|
||||||
|
fn interrupt_webdriver_script_evaluation(&self) {
|
||||||
|
if let Some(sender) = &self
|
||||||
|
.webdriver_senders
|
||||||
|
.borrow()
|
||||||
|
.script_evaluation_interrupt_sender
|
||||||
|
{
|
||||||
|
sender.send(Ok(WebDriverJSValue::Null)).unwrap_or_else(|err| {
|
||||||
|
info!("Notify dialog appear failed. Maybe the channel to webdriver is closed: {err}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ServoShellServoDelegate;
|
struct ServoShellServoDelegate;
|
||||||
|
@ -452,6 +484,8 @@ impl WebViewDelegate for RunningAppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_simple_dialog(&self, webview: servo::WebView, dialog: SimpleDialog) {
|
fn show_simple_dialog(&self, webview: servo::WebView, dialog: SimpleDialog) {
|
||||||
|
self.interrupt_webdriver_script_evaluation();
|
||||||
|
|
||||||
if self.servoshell_preferences.headless &&
|
if self.servoshell_preferences.headless &&
|
||||||
self.servoshell_preferences.webdriver_port.is_none()
|
self.servoshell_preferences.webdriver_port.is_none()
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,12 +4,3 @@
|
||||||
|
|
||||||
[test_form_control_send_text[textarea\]]
|
[test_form_control_send_text[textarea\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_file_upload]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_not_blurred[input\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_not_blurred[textarea\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -22,33 +22,3 @@
|
||||||
|
|
||||||
[test_strict_display_none]
|
[test_strict_display_none]
|
||||||
expected: ERROR
|
expected: ERROR
|
||||||
|
|
||||||
[test_multiple_files]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_multiple_files_without_multiple_attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_single_file]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_single_file_replaces_without_multiple_attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_transparent]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_obscured]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_outside_viewport]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_display_none]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_not_focused]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -4,18 +4,3 @@
|
||||||
|
|
||||||
[test_textarea_append]
|
[test_textarea_append]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_input]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_textarea]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_input_insert_when_focused]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_textarea_insert_when_focused]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_date]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -22,12 +22,3 @@
|
||||||
|
|
||||||
[test_readonly_element]
|
[test_readonly_element]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_body_is_interactable]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_transparent_element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_obscured_element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -22,6 +22,3 @@
|
||||||
|
|
||||||
[test_element_just_outside_viewport[Just below viewport\]]
|
[test_element_just_outside_viewport[Just below viewport\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_element_outside_of_not_scrollable_viewport]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,33 +1,3 @@
|
||||||
[send_keys.py]
|
[send_keys.py]
|
||||||
[test_null_response_value]
|
[test_no_browsing_context]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_top_browsing_context]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_with_invalid_value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_with_shadow_root]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_from_other_window_handle[open\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_from_other_window_handle[closed\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_from_other_frame[open\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_no_such_element_from_other_frame[closed\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_stale_element_reference[top_context\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_stale_element_reference[child_context\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_surrogates]
|
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,24 +1,6 @@
|
||||||
[key_events.py]
|
[key_events.py]
|
||||||
[test_modifier_key_sends_correct_events[\\ue008-SHIFT\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_non_printable_key_sends_events[\\ue00c-ESCAPE\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_special_key_sends_keydown[EQUALS-expected12\]]
|
[test_special_key_sends_keydown[EQUALS-expected12\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_special_key_sends_keydown[PAUSE-expected45\]]
|
[test_special_key_sends_keydown[PAUSE-expected45\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_modifier_key_sends_correct_events[\\ue00a-ALT\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_modifier_key_sends_correct_events[\\ue009-CONTROL\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_modifier_key_sends_correct_events[\\ue03d-META\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_modifier_key_sends_correct_events[\\ue052-R_ALT\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -5,18 +5,6 @@
|
||||||
[test_pointer_down_closes_browsing_context]
|
[test_pointer_down_closes_browsing_context]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_click_at_coordinates]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_context_menu_at_coordinates]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_middle_click]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_click_element_center]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_click_element_in_shadow_tree[outer-open\]]
|
[test_click_element_in_shadow_tree[outer-open\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,6 @@
|
||||||
[test_scroll_with_key_pressed]
|
[test_scroll_with_key_pressed]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_scroll_not_scrollable]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_scroll_scrollable_overflow]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_scroll_iframe]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_scroll_shadow_tree[outer-open\]]
|
[test_scroll_shadow_tree[outer-open\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[alerts.py]
|
[alerts.py]
|
||||||
expected: TIMEOUT
|
|
||||||
[test_retain_tab_modal_status]
|
[test_retain_tab_modal_status]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_finds_exising_user_prompt_after_tab_switch[confirm\]]
|
[test_finds_exising_user_prompt_after_tab_switch[confirm\]]
|
||||||
expected: FAIL
|
expected: ERROR
|
||||||
|
|
||||||
[test_finds_exising_user_prompt_after_tab_switch[prompt\]]
|
[test_finds_exising_user_prompt_after_tab_switch[prompt\]]
|
||||||
expected: FAIL
|
expected: ERROR
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue