Implement actions_by_tick for webdriver (#37153)

Implement `actions by tick` according to the spec. 
The major change is `dispatch_actions` should receive a `actions by
ticks` as param.

https://w3c.github.io/webdriver/#dispatching-actions
> The algorithm to [dispatch
actions](https://w3c.github.io/webdriver/#dfn-dispatch-actions) takes a
list of actions grouped by
[tick](https://w3c.github.io/webdriver/#dfn-ticks), and then causes each
action to be run at the appropriate point in the sequence.

Reference for types in webdriver:
https://hackmd.io/b59NiPcLR_Gagh7r6r7BEw?view

cc: @xiaochengh

---------

Signed-off-by: batu_hoang <longvatrong111@gmail.com>
This commit is contained in:
batu_hoang 2025-06-03 16:20:00 +08:00 committed by GitHub
parent 56c0ad8420
commit ad95a74389
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 258 additions and 214 deletions

View file

@ -64,7 +64,7 @@ use webdriver::response::{
};
use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler};
use crate::actions::{InputSourceState, PointerInputState};
use crate::actions::{ActionItem, InputSourceState, PointerInputState};
#[derive(Default)]
pub struct WebDriverMessageIdGenerator {
@ -171,7 +171,7 @@ pub struct WebDriverSession {
input_state_table: RefCell<HashMap<String, InputSourceState>>,
/// <https://w3c.github.io/webdriver/#dfn-input-cancel-list>
input_cancel_list: RefCell<Vec<ActionSequence>>,
input_cancel_list: RefCell<Vec<ActionItem>>,
}
impl WebDriverSession {
@ -1480,20 +1480,22 @@ impl Handler {
fn handle_perform_actions(
&mut self,
parameters: &ActionsParameters,
parameters: ActionsParameters,
) -> WebDriverResult<WebDriverResponse> {
match self.dispatch_actions(&parameters.actions) {
// 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);
// Step 6. Dispatch actions
match self.dispatch_actions(actions_by_tick) {
Ok(_) => Ok(WebDriverResponse::Void),
Err(error) => Err(WebDriverError::new(error, "")),
}
}
/// <https://w3c.github.io/webdriver/#dfn-release-actions>
fn handle_release_actions(&mut self) -> WebDriverResult<WebDriverResponse> {
let input_cancel_list = self.session().unwrap().input_cancel_list.borrow();
if let Err(error) = self.dispatch_actions(&input_cancel_list) {
return Err(WebDriverError::new(error, ""));
}
// TODO: The previous implementation of this function was different from the spec.
// Need to re-implement this to match the spec.
let session = self.session()?;
session.input_state_table.borrow_mut().clear();
@ -1655,7 +1657,7 @@ impl Handler {
// Step 8.1
self.session_mut()?.input_state_table.borrow_mut().insert(
id.clone(),
InputSourceState::Pointer(PointerInputState::new(&PointerType::Mouse)),
InputSourceState::Pointer(PointerInputState::new(PointerType::Mouse)),
);
// Step 8.7. Construct a pointer move action.
@ -1702,7 +1704,11 @@ impl Handler {
},
};
let _ = self.dispatch_actions(&[action_sequence]);
let actions_by_tick = self.actions_by_tick_from_sequence(vec![action_sequence]);
if let Err(e) = self.dispatch_actions(actions_by_tick) {
log::error!("handle_element_click: dispatch_actions failed: {:?}", e);
}
// Step 8.17 Remove an input source with input state and input id.
self.session_mut()?
@ -1940,7 +1946,9 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
self.handle_element_css(element, name)
},
WebDriverCommand::GetPageSource => self.handle_get_page_source(),
WebDriverCommand::PerformActions(ref x) => self.handle_perform_actions(x),
WebDriverCommand::PerformActions(actions_parameters) => {
self.handle_perform_actions(actions_parameters)
},
WebDriverCommand::ReleaseActions => self.handle_release_actions(),
WebDriverCommand::ExecuteScript(ref x) => self.handle_execute_script(x),
WebDriverCommand::ExecuteAsyncScript(ref x) => self.handle_execute_async_script(x),