Ctrl+click should synthesize a contextmenu event

Except on Windows.

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1421323
gecko-commit: d62ce3e3ee8ad7ed946c6b5bf6d7a793dcbecfe0
gecko-integration-branch: autoland
gecko-reviewers: ato
diff --git a/webdriver/tests/actions/control_click.py b/webdriver/tests/actions/control_click.py
new file mode 100644
index 0000000..f9d4448
--- /dev/null
+++ b/webdriver/tests/actions/control_click.py
@@ -0,0 +1,77 @@
+import pytest
+
+from tests.actions.support.refine import filter_dict, get_events
+from tests.actions.support.keys import Keys
+
+
+@pytest.mark.parametrize("modifier, prop", [
+    (Keys.CONTROL, "ctrlKey"),
+    (Keys.R_CONTROL, "ctrlKey"),
+])
+def test_control_click(session, test_actions_page, key_chain, mouse_chain, modifier, prop):
+    os = session.capabilities["platformName"]
+    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])
+    if os == "windows_nt":
+        expected = [
+            {"type": "mousemove"},
+            {"type": "mousedown"},
+            {"type": "mouseup"},
+            {"type": "click"},
+        ]
+    else:
+        expected = [
+            {"type": "mousemove"},
+            {"type": "mousedown"},
+            {"type": "contextmenu"},
+            {"type": "mouseup"},
+        ]
+    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):
+    # The context menu stays visible during subsequent tests so let's not
+    # display it in the first place.
+    session.execute_script("""
+        var keyReporter = document.getElementById("keys");
+        document.addEventListener("contextmenu", function(e) {
+          e.preventDefault();
+        });
+    """)
+    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");
+        keyReporter.addEventListener("mousedown", recordPointerEvent);
+        keyReporter.addEventListener("mouseup", 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
diff --git a/webdriver/tests/actions/modifier_click.py b/webdriver/tests/actions/modifier_click.py
index 85a23d4..fbfd837 100644
--- a/webdriver/tests/actions/modifier_click.py
+++ b/webdriver/tests/actions/modifier_click.py
@@ -43,12 +43,13 @@
 
 def test_many_modifiers_click(session, test_actions_page, key_chain, mouse_chain):
     outer = session.find.css("#outer", all=False)
+    dblclick_timeout = 800
     key_chain \
         .pause(0) \
-        .key_down(Keys.CONTROL) \
+        .key_down(Keys.ALT) \
         .key_down(Keys.SHIFT) \
-        .pause(0) \
-        .key_up(Keys.CONTROL) \
+        .pause(dblclick_timeout) \
+        .key_up(Keys.ALT) \
         .key_up(Keys.SHIFT)
     mouse_chain \
         .pointer_move(0, 0, origin=outer) \
@@ -61,7 +62,7 @@
     session.actions.perform([key_chain.dict, mouse_chain.dict])
     expected = [
         {"type": "mousemove"},
-        # shift and ctrl presses
+        # shift and alt pressed
         {"type": "mousedown"},
         {"type": "mouseup"},
         {"type": "click"},
@@ -78,6 +79,6 @@
         e.update(defaults)
     for e in expected[1:4]:
         e["shiftKey"] = True
-        e["ctrlKey"] = True
+        e["altKey"] = True
     events = [filter_dict(e, expected[0]) for e in get_events(session)]
     assert events == expected