diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index 630ff735351..1f539c55894 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -31,7 +31,7 @@ static WHEELSCROLL_INTERVAL: u64 = 17; // In the spec, `action item` refers to a plain JSON object. // However, we use the name ActionItem here // to be consistent with type names from webdriver crate. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub(crate) enum ActionItem { Null(NullActionItem), Key(KeyActionItem), @@ -222,7 +222,6 @@ impl Handler { }, ActionItem::Key(KeyActionItem::Key(KeyAction::Down(keydown_action))) => { self.dispatch_keydown_action(input_id, keydown_action); - // Step 9. If subtype is "keyDown", append a copy of action // object with the subtype property changed to "keyUp" to // input state's input cancel list. @@ -230,11 +229,12 @@ impl Handler { .unwrap() .input_cancel_list .borrow_mut() - .push(ActionItem::Key(KeyActionItem::Key(KeyAction::Up( - KeyUpAction { + .push(( + input_id.clone(), + ActionItem::Key(KeyActionItem::Key(KeyAction::Up(KeyUpAction { value: keydown_action.value.clone(), - }, - )))); + }))), + )); }, ActionItem::Key(KeyActionItem::Key(KeyAction::Up(keyup_action))) => { self.dispatch_keyup_action(input_id, keyup_action); @@ -246,18 +246,22 @@ impl Handler { pointer_down_action, ))) => { self.dispatch_pointerdown_action(input_id, pointer_down_action); - // Step 10. If subtype is "pointerDown", append a copy of action // object with the subtype property changed to "pointerUp" to // input state's input cancel list. - self.session().unwrap().input_cancel_list.borrow_mut().push( - ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Up( - PointerUpAction { - button: pointer_down_action.button, - ..Default::default() - }, - ))), - ); + self.session() + .unwrap() + .input_cancel_list + .borrow_mut() + .push(( + input_id.clone(), + ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Up( + PointerUpAction { + button: pointer_down_action.button, + ..Default::default() + }, + ))), + )); }, ActionItem::Pointer(PointerActionItem::Pointer(PointerAction::Move( pointer_move_action, diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 61d50389d6d..1512bdb4305 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -64,7 +64,7 @@ use webdriver::response::{ }; use webdriver::server::{self, Session, SessionTeardownKind, WebDriverHandler}; -use crate::actions::{ActionItem, InputSourceState, PointerInputState}; +use crate::actions::{ActionItem, ActionsByTick, InputSourceState, PointerInputState}; #[derive(Default)] pub struct WebDriverMessageIdGenerator { @@ -143,11 +143,19 @@ pub fn start_server(port: u16, constellation_chan: Sender id: Uuid, - browsing_context_id: BrowsingContextId, + + /// webview_id: WebViewId, + /// + browsing_context_id: BrowsingContextId, + + /// window_handles: HashMap, /// Time to wait for injected scripts to run before interrupting them. A [`None`] value @@ -171,7 +179,7 @@ pub struct WebDriverSession { input_state_table: RefCell>, /// - input_cancel_list: RefCell>, + input_cancel_list: RefCell>, } impl WebDriverSession { @@ -201,6 +209,8 @@ impl WebDriverSession { } } +/// The `Handler` for the WebDriver server. +/// Currently, only 1 session is supported. struct Handler { /// The threaded receiver on which we can block for a load-status. /// It will receive messages sent on the load_status_sender, @@ -1614,12 +1624,35 @@ impl Handler { /// fn handle_release_actions(&mut self) -> WebDriverResult { - // 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()?; + // 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(session.browsing_context_id)?; + + // TODO: Step 2. User prompts. No user prompt implemented yet. + // TODO: Step 3. Skip for now because webdriver holds only one session. + // TODO: Step 4. Actions options are not used yet. + // TODO: Step 5. Skip for now because webdriver holds only one session. + + // Step 6. Let undo actions be input cancel list in reverse order. + let mut input_cancel_list = session.input_cancel_list.borrow_mut(); + let undo_actions: ActionsByTick = input_cancel_list + .drain(..) + .rev() + .map(|action| { + let mut map = HashMap::new(); + map.insert(action.0, action.1); + map + }) + .collect(); + + // Step 7. Dispatch undo actions with current browsing context. + if let Err(err) = self.dispatch_actions(undo_actions, session.browsing_context_id) { + return Err(WebDriverError::new(err, "Failed to dispatch undo actions")); + } + + // Step 8. Reset the input state of session's current top-level browsing context. session.input_state_table.borrow_mut().clear(); Ok(WebDriverResponse::Void) diff --git a/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence.py.ini b/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence.py.ini deleted file mode 100644 index 6ba3814b563..00000000000 --- a/tests/wpt/meta/webdriver/tests/classic/release_actions/sequence.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[sequence.py] - [test_release_char_sequence_sends_keyup_events_in_reverse] - expected: FAIL