Bug 1433463 - WebDriver:ElementSendKeys should not run unfocussing steps. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Thu, 22 Feb 2018 11:26:01 +0000
changeset 758434 21ec7e94b244d0d304daedb79d956817692e9bb8
parent 758396 ea3da643422c58d65335f1778dd6c89c09911585
push id100054
push userbmo:ato@sny.no
push dateThu, 22 Feb 2018 13:19:45 +0000
reviewersautomatedtester
bugs1433463
milestone60.0a1
Bug 1433463 - WebDriver:ElementSendKeys should not run unfocussing steps. r?automatedtester According to the WebDriver standard the Element Send Keys command should not run the unfocussing steps. Not blurring the element causes the DOM "change" event not to fire, but the specification only expects the "input" event to fire. The standard does, however, expect the Element Clear command to run the unfocussing steps and to blur the element for historical reasons. MozReview-Commit-ID: FHD1whho0jT
testing/marionette/interaction.js
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/webdriver/tests/element_send_keys/form_controls.py
testing/web-platform/tests/webdriver/tests/element_send_keys/interactability.py
--- a/testing/marionette/interaction.js
+++ b/testing/marionette/interaction.js
@@ -572,18 +572,16 @@ async function webdriverSendKeysToElemen
   if (el.type == "file") {
     await interaction.uploadFile(el, value);
   } else if ((el.type == "date" || el.type == "time") &&
       Preferences.get("dom.forms.datetime")) {
     interaction.setFormControlValue(el, value);
   } else {
     event.sendKeysToElement(value, el, win);
   }
-
-  el.blur();
 }
 
 async function legacySendKeysToElement(el, value, a11y) {
   const win = getWindow(el);
 
   if (el.type == "file") {
     await interaction.uploadFile(el, value);
   } else if ((el.type == "date" || el.type == "time") &&
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -584736,17 +584736,17 @@
    "bea28e051bc747d863dad9d1fd4ef8ffce432b54",
    "testharness"
   ],
   "service-workers/service-worker/state.https.html": [
    "ecb0e2fd22e7c92a98ae612a2032a92edf8520d9",
    "testharness"
   ],
   "service-workers/service-worker/svg-target-reftest.https.html": [
-   "c8d97ffed68ca40b4154bde36d9a0ca65d2e3816",
+   "9eb665d5cd1f62f2591130e372fd6dc1e9c61f64",
    "reftest"
   ],
   "service-workers/service-worker/synced-state.https.html": [
    "c6a3d6e8aa7a70e1bc670f89192240bac081bfe9",
    "testharness"
   ],
   "service-workers/service-worker/uncontrolled-page.https.html": [
    "881f51c7f9c64f6d69746e1e195c11cf6e29fb3e",
@@ -592480,21 +592480,21 @@
    "7d40a7641dbf04cd78f1dba630afa2e8d80dad13",
    "wdspec"
   ],
   "webdriver/tests/element_send_keys/__init__.py": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
   "webdriver/tests/element_send_keys/form_controls.py": [
-   "7c4a249f9575a69268b5f2970a5623fc1724e6e1",
+   "a1ade96c599a336684ee5a46dbc1716aac8ed9ae",
    "wdspec"
   ],
   "webdriver/tests/element_send_keys/interactability.py": [
-   "bd5d26173017dc3cbdc282809028639a7b4a214a",
+   "197bf11c6cae354d9f3cc07f836a857345046e1c",
    "wdspec"
   ],
   "webdriver/tests/element_send_keys/scroll_into_view.py": [
    "fb192d5d1d93aa729b07cadcadfa630587bd0b39",
    "wdspec"
   ],
   "webdriver/tests/execute_async_script/__init__.py": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
@@ -598772,17 +598772,17 @@
    "b0e679dd7720701364abeaca6870d94db5d7ee74",
    "support"
   ],
   "workers/support/iframe_sw_dataUrl.html": [
    "2cd66112b612e7b861af00af5ccc26cc7c5a76f8",
    "support"
   ],
   "workers/support/name-as-accidental-global.js": [
-   "530670268fae610b60066773ee475743b8498b53",
+   "5f75e855287f1a8b391498a3c567b68c75f56416",
    "support"
   ],
   "workers/support/name.js": [
    "27fa41f445888125f84dab8a57ca62b41c09e506",
    "support"
   ],
   "workers/support/nosiniff-error-worker.py": [
    "aa81cbafc77ccc9407cba3ac0bd4498e5076bf2b",
--- a/testing/web-platform/tests/webdriver/tests/element_send_keys/form_controls.py
+++ b/testing/web-platform/tests/webdriver/tests/element_send_keys/form_controls.py
@@ -1,53 +1,60 @@
 import pytest
 
-from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.asserts import (
+    assert_element_has_focus,
+    assert_error,
+    assert_same_element,
+    assert_success,
+)
 from tests.support.inline import inline
 
 
 def element_send_keys(session, element, text):
     return session.transport.send(
         "POST",
         "/session/{session_id}/element/{element_id}/value".format(
             session_id=session.session_id,
             element_id=element.id),
         {"text": text})
 
 
 def add_event_listeners(element):
     element.session.execute_script("""
         let [target] = arguments;
         window.events = [];
-        for (let expected of ["focus", "blur", "change", "keypress", "keydown", "keyup", "input"]) {
+        for (let expected of ["focus", "change", "keypress", "keydown", "keyup", "input"]) {
           target.addEventListener(expected, ({type}) => window.events.push(type));
         }
         """, args=(element,))
 
 
 def get_events(session):
     return session.execute_script("return window.events")
 
 
 def test_input(session):
     session.url = inline("<input>")
     element = session.find.css("input", all=False)
     assert element.property("value") == ""
 
     element_send_keys(session, element, "foo")
     assert element.property("value") == "foo"
+    assert_element_has_focus(element)
 
 
 def test_textarea(session):
     session.url = inline("<textarea>")
     element = session.find.css("textarea", all=False)
     assert element.property("value") == ""
 
     element_send_keys(session, element, "foo")
     assert element.property("value") == "foo"
+    assert_element_has_focus(element)
 
 
 def test_input_append(session):
     session.url = inline("<input value=a>")
     element = session.find.css("input", all=False)
     assert element.property("value") == "a"
 
     element_send_keys(session, element, "b")
@@ -84,11 +91,18 @@ def test_events(session, tag):
                                    "keyup",
                                    "keydown",
                                    "keypress",
                                    "input",
                                    "keyup",
                                    "keydown",
                                    "keypress",
                                    "input",
-                                   "keyup",
-                                   "change",
-                                   "blur"]
+                                   "keyup"]
+
+
+@pytest.mark.parametrize("tag", ["input", "textarea"])
+def test_not_blurred(session, tag):
+    session.url = inline("<%s>" % tag)
+    element = session.find.css(tag, all=False)
+
+    element_send_keys(session, element, "")
+    assert_element_has_focus(element)
--- a/testing/web-platform/tests/webdriver/tests/element_send_keys/interactability.py
+++ b/testing/web-platform/tests/webdriver/tests/element_send_keys/interactability.py
@@ -1,86 +1,86 @@
-from tests.support.asserts import assert_error, assert_same_element, assert_success
+from tests.support.asserts import assert_error, assert_success
 from tests.support.inline import iframe, inline
 
 
 def send_keys_to_element(session, element, text):
     return session.transport.send(
         "POST",
         "/session/{session_id}/element/{element_id}/value".format(
             session_id=session.session_id,
             element_id=element.id),
         {"text": text})
 
 
 def test_body_is_interactable(session):
     session.url = inline("""
-        <body onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <body onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </body>
     """)
 
     element = session.find.css("body", all=False)
     result = session.find.css("input", all=False)
 
     # By default body is the active element
-    assert_same_element(session, element, session.active_element)
+    assert session.active_element is element
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
-    assert_same_element(session, element, session.active_element)
+    assert session.active_element is element
     assert result.property("value") == "foo"
 
 
 def test_document_element_is_interactable(session):
     session.url = inline("""
-        <html onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <html onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </html>
     """)
 
     body = session.find.css("body", all=False)
     element = session.find.css(":root", all=False)
     result = session.find.css("input", all=False)
 
     # By default body is the active element
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is body
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is element
     assert result.property("value") == "foo"
 
 
 def test_iframe_is_interactable(session):
     session.url = inline(iframe("""
-        <body onkeypress="document.getElementById('result').value += event.key">
-          <input type="text" id="result"/>
+        <body onkeypress="document.querySelector('input').value += event.key">
+          <input>
         </body>
     """))
 
     body = session.find.css("body", all=False)
     frame = session.find.css("iframe", all=False)
 
     # By default the body has the focus
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is body
 
     response = send_keys_to_element(session, frame, "foo")
     assert_success(response)
-    assert_same_element(session, body, session.active_element)
+    assert session.active_element is frame
 
     # Any key events are immediately routed to the nested
     # browsing context's active document.
     session.switch_frame(frame)
     result = session.find.css("input", all=False)
     assert result.property("value") == "foo"
 
 
 def test_transparent_element(session):
-    session.url = inline("<input style=\"opacity: 0;\">")
+    session.url = inline("""<input style="opacity: 0">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
     assert element.property("value") == "foo"
 
 
 def test_readonly_element(session):
@@ -89,18 +89,18 @@ def test_readonly_element(session):
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
     assert element.property("value") == ""
 
 
 def test_obscured_element(session):
     session.url = inline("""
-      <input type="text" />
-      <div style="position: relative; top: -3em; height: 5em; background-color: blue"></div>
+      <input>
+      <div style="position: relative; top: -3em; height: 5em; background: blue;"></div>
     """)
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_success(response)
     assert element.property("value") == "foo"
 
 
@@ -108,29 +108,29 @@ def test_not_a_focusable_element(session
     session.url = inline("<div>foo</div>")
     element = session.find.css("div", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
 def test_not_displayed_element(session):
-    session.url = inline("<input style=\"display: none\">")
+    session.url = inline("""<input style="display: none">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
 def test_hidden_element(session):
-    session.url = inline("<input style=\"visibility: hidden\">")
+    session.url = inline("""<input style="visibility: hidden">""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_error(response, "element not interactable")
 
 
 def test_disabled_element(session):
-    session.url = inline("<input disabled=\"false\">")
+    session.url = inline("""<input disabled>""")
     element = session.find.css("input", all=False)
 
     response = send_keys_to_element(session, element, "foo")
     assert_error(response, "element not interactable")