[WebDriver: Dispatch Action] Check if browsing context still open for each tick action (#37393)

As titled. This is what
[spec](https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner)
requires. The motivation is that the previous action might have changed
the browsing context.

Testing: `./mach test-wpt -r --log-raw "D:\servo test log\all.txt"
.\tests\wpt\tests\webdriver\tests\classic\ --product servodriver`

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye 2025-06-11 17:53:06 +08:00 committed by GitHub
parent 048d4a2a5a
commit 5f1452f9d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 10 deletions

View file

@ -6,6 +6,7 @@ use std::collections::{HashMap, HashSet};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use base::id::BrowsingContextId;
use constellation_traits::EmbedderToConstellationMessage; use constellation_traits::EmbedderToConstellationMessage;
use embedder_traits::{MouseButtonAction, WebDriverCommandMsg, WebDriverScriptCommand}; use embedder_traits::{MouseButtonAction, WebDriverCommandMsg, WebDriverScriptCommand};
use ipc_channel::ipc; use ipc_channel::ipc;
@ -114,6 +115,7 @@ impl Handler {
pub(crate) fn dispatch_actions( pub(crate) fn dispatch_actions(
&self, &self,
actions_by_tick: ActionsByTick, actions_by_tick: ActionsByTick,
browsing_context: BrowsingContextId,
) -> Result<(), ErrorStatus> { ) -> Result<(), ErrorStatus> {
// Step 1. Wait for an action queue token with input state. // Step 1. Wait for an action queue token with input state.
let new_token = self.id_generator.next(); let new_token = self.id_generator.next();
@ -121,7 +123,7 @@ impl Handler {
self.current_action_id.set(Some(new_token)); self.current_action_id.set(Some(new_token));
// Step 2. Let actions result be the result of dispatch actions inner. // Step 2. Let actions result be the result of dispatch actions inner.
let res = self.dispatch_actions_inner(actions_by_tick); let res = self.dispatch_actions_inner(actions_by_tick, browsing_context);
// Step 3. Dequeue input state's actions queue. // Step 3. Dequeue input state's actions queue.
self.current_action_id.set(None); self.current_action_id.set(None);
@ -131,9 +133,17 @@ impl Handler {
} }
/// <https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner> /// <https://w3c.github.io/webdriver/#dfn-dispatch-actions-inner>
fn dispatch_actions_inner(&self, actions_by_tick: ActionsByTick) -> Result<(), ErrorStatus> { fn dispatch_actions_inner(
&self,
actions_by_tick: ActionsByTick,
browsing_context: BrowsingContextId,
) -> Result<(), ErrorStatus> {
// Step 1. For each item tick actions in actions by tick // Step 1. For each item tick actions in actions by tick
for tick_actions in actions_by_tick.iter() { for tick_actions in actions_by_tick.iter() {
// Step 1.1. If browsing context is no longer open,
// return error with error code no such window.
self.verify_browsing_context_is_open(browsing_context)
.map_err(|e| e.error)?;
// Step 1.2. Let tick duration be the result of // Step 1.2. Let tick duration be the result of
// computing the tick duration with argument tick actions. // computing the tick duration with argument tick actions.
let tick_duration = compute_tick_duration(tick_actions); let tick_duration = compute_tick_duration(tick_actions);

View file

@ -1543,14 +1543,15 @@ impl Handler {
&mut self, &mut self,
parameters: ActionsParameters, parameters: ActionsParameters,
) -> WebDriverResult<WebDriverResponse> { ) -> WebDriverResult<WebDriverResponse> {
let browsing_context = self.session()?.browsing_context_id;
// Step 1. If session's current browsing context is no longer open, // Step 1. If session's current browsing context is no longer open,
// return error with error code no such window. // return error with error code no such window.
self.verify_browsing_context_is_open(self.session()?.browsing_context_id)?; self.verify_browsing_context_is_open(browsing_context)?;
// Step 5. Let actions by tick be the result of trying to extract an action sequence // 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); let actions_by_tick = self.extract_an_action_sequence(parameters);
// Step 6. Dispatch actions // Step 6. Dispatch actions with current browsing context
match self.dispatch_actions(actions_by_tick) { match self.dispatch_actions(actions_by_tick, browsing_context) {
Ok(_) => Ok(WebDriverResponse::Void), Ok(_) => Ok(WebDriverResponse::Void),
Err(error) => Err(WebDriverError::new(error, "")), Err(error) => Err(WebDriverError::new(error, "")),
} }
@ -1782,9 +1783,11 @@ impl Handler {
}, },
}; };
// Step 8.16. Dispatch a list of actions with session's current browsing context
let actions_by_tick = self.actions_by_tick_from_sequence(vec![action_sequence]); let actions_by_tick = self.actions_by_tick_from_sequence(vec![action_sequence]);
if let Err(e) =
if let Err(e) = self.dispatch_actions(actions_by_tick) { self.dispatch_actions(actions_by_tick, self.session()?.browsing_context_id)
{
log::error!("handle_element_click: dispatch_actions failed: {:?}", e); log::error!("handle_element_click: dispatch_actions failed: {:?}", e);
} }

View file

@ -1,7 +1,4 @@
[refresh.py] [refresh.py]
[test_no_top_browsing_context]
expected: FAIL
[test_no_browsing_context] [test_no_browsing_context]
expected: FAIL expected: FAIL