Bug 1367430 - Set modifier-key properties for mouse action; r=ato
authorMaja Frydrychowicz <mjzffr@gmail.com>
Wed, 24 May 2017 16:42:04 +0200
changeset 410939 9c79509cd7563afd6284528c62504ff63c2b4229
parent 410938 d0c59bcdd5bc46b2fb2e6742fccbf5effb36537d
child 410940 364a31932fe3f0be6d7c8e68aefe05f225fcdad9
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1367430
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1367430 - Set modifier-key properties for mouse action; r=ato When synthesizing a MouseEvent for the performActions command, set shiftKey, ctrlKey, etc., based on inputStateMap. MozReview-Commit-ID: Knw3gxuAcSB
testing/marionette/action.js
testing/web-platform/tests/webdriver/actions/sequence.py
testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -893,16 +893,30 @@ action.Key = class {
 
 /** Collect properties associated with MouseEvent */
 action.Mouse = class {
   constructor(type, button = 0) {
     this.type = type;
     assert.positiveInteger(button);
     this.button = button;
     this.buttons = 0;
+    this.altKey = false;
+    this.shiftKey = false;
+    this.metaKey = false;
+    this.ctrlKey = false;
+    // set modifier properties based on whether any corresponding keys are
+    // pressed on any key input source
+    for (let inputState of action.inputStateMap.values()) {
+      if (inputState.type == "key") {
+        this.altKey = inputState.alt || this.altKey;
+        this.ctrlKey = inputState.ctrl || this.ctrlKey;
+        this.metaKey = inputState.meta || this.metaKey;
+        this.shiftKey = inputState.shift || this.shiftKey;
+      }
+    }
   }
 
   update(inputState) {
     let allButtons = Array.from(inputState.pressed);
     this.buttons = allButtons.reduce((a, i) => a + Math.pow(2, i), 0);
   }
 };
 
--- a/testing/web-platform/tests/webdriver/actions/sequence.py
+++ b/testing/web-platform/tests/webdriver/actions/sequence.py
@@ -1,9 +1,12 @@
+import pytest
+
 from support.refine import get_keys, filter_dict, get_events
+from support.keys import Keys
 
 
 def test_no_actions_send_no_events(session, key_reporter, key_chain):
     key_chain.perform()
     assert len(get_keys(key_reporter)) == 0
     assert len(get_events(session)) == 0
 
 
@@ -24,8 +27,118 @@ def test_release_char_sequence_sends_key
     events = [filter_dict(e, expected[0]) for e in get_events(session)]
     assert events == expected
 
 
 def test_release_no_actions_sends_no_events(session, key_reporter):
     session.actions.release()
     assert len(get_keys(key_reporter)) == 0
     assert len(get_events(session)) == 0
+
+
+@pytest.mark.parametrize("modifier, prop", [
+    (Keys.CONTROL, "ctrlKey"),
+    (Keys.ALT, "altKey"),
+    (Keys.META, "metaKey"),
+    (Keys.SHIFT, "shiftKey"),
+    (Keys.R_CONTROL, "ctrlKey"),
+    (Keys.R_ALT, "altKey"),
+    (Keys.R_META, "metaKey"),
+    (Keys.R_SHIFT, "shiftKey"),
+])
+def test_control_click(session,
+                       test_actions_page,
+                       key_chain,
+                       mouse_chain,
+                       modifier,
+                       prop):
+    key_chain \
+        .pause(0) \
+        .key_down(modifier) \
+        .pause(200) \
+        .key_up(modifier)
+    outer = session.find.css("#outer", all=False)
+    mouse_chain.click(element=outer)
+    session.actions.perform([key_chain.dict, mouse_chain.dict])
+    expected = [
+        {"type": "mousemove"},
+        {"type": "mousedown"},
+        {"type": "mouseup"},
+        {"type": "click"},
+    ]
+    defaults = {
+        "altKey": False,
+        "metaKey": False,
+        "shiftKey": False,
+        "ctrlKey": False
+    }
+    for e in expected:
+        e.update(defaults)
+        if e["type"] != "mousemove":
+            e[prop] = True
+    filtered_events = [filter_dict(e, expected[0]) for e in get_events(session)]
+    assert expected == filtered_events
+
+
+def test_release_control_click(session, key_reporter, key_chain, mouse_chain):
+    key_chain \
+        .pause(0) \
+        .key_down(Keys.CONTROL)
+    mouse_chain \
+        .pointer_move(0, 0, origin=key_reporter) \
+        .pointer_down()
+    session.actions.perform([key_chain.dict, mouse_chain.dict])
+    session.execute_script("""
+        var keyReporter = document.getElementById("keys");
+        ["mousedown", "mouseup"].forEach((e) => {
+            keyReporter.addEventListener(e, recordPointerEvent);
+          });
+        resetEvents();
+    """)
+    session.actions.release()
+    expected = [
+        {"type": "mouseup"},
+        {"type": "keyup"},
+    ]
+    events = [filter_dict(e, expected[0]) for e in get_events(session)]
+    assert events == expected
+
+
+def test_many_modifiers_click(session, test_actions_page, key_chain, mouse_chain):
+    outer = session.find.css("#outer", all=False)
+    key_chain \
+        .pause(0) \
+        .key_down(Keys.CONTROL) \
+        .key_down(Keys.SHIFT) \
+        .pause(0) \
+        .key_up(Keys.CONTROL) \
+        .key_up(Keys.SHIFT)
+    mouse_chain \
+        .pointer_move(0, 0, origin=outer) \
+        .pause(0) \
+        .pointer_down() \
+        .pointer_up() \
+        .pause(0) \
+        .pause(0) \
+        .pointer_down()
+    session.actions.perform([key_chain.dict, mouse_chain.dict])
+    expected = [
+        {"type": "mousemove"},
+        # shift and ctrl presses
+        {"type": "mousedown"},
+        {"type": "mouseup"},
+        {"type": "click"},
+        # no modifiers pressed
+        {"type": "mousedown"},
+    ]
+    defaults = {
+        "altKey": False,
+        "metaKey": False,
+        "shiftKey": False,
+        "ctrlKey": False
+    }
+    for e in expected:
+        e.update(defaults)
+    for e in expected[1:4]:
+        e["shiftKey"] = True
+        e["ctrlKey"] = True
+    events = [filter_dict(e, expected[0]) for e in get_events(session)]
+    assert events == expected
--- a/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
+++ b/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html
@@ -65,24 +65,32 @@
 
         function recordPointerEvent(event) {
           allEvents.events.push({
             "type": event.type,
             "button": event.button,
             "buttons": event.buttons,
             "pageX": event.pageX,
             "pageY": event.pageY,
+            "ctrlKey": event.ctrlKey,
+            "metaKey": event.metaKey,
+            "altKey": event.altKey,
+            "shiftKey": event.shiftKey,
             "target": event.target.id
           });
           appendMessage(`${event.type}(` +
               `button: ${event.button}, ` +
               `pageX: ${event.pageX}, ` +
               `pageY: ${event.pageY}, ` +
               `button: ${event.button}, ` +
               `buttons: ${event.buttons}, ` +
+              `ctrlKey: ${event.ctrlKey}, ` +
+              `altKey: ${event.altKey}, ` +
+              `metaKey: ${event.metaKey}, ` +
+              `shiftKey: ${event.shiftKey}, ` +
               `target id: ${event.target.id})`);
         }
 
         function recordFirstPointerMove(event) {
           recordPointerEvent(event);
           window.removeEventListener("mousemove", recordFirstPointerMove);
         }