Bug 1432864 - Run native focussing steps on interaction commands. r=automatedtester
authorAndreas Tolfsen <ato@sny.no>
Thu, 01 Feb 2018 09:04:00 +0200
changeset 454622 feae5d29e679fb637a0ca44800464fee9f1bc91f
parent 454621 a25a343d7937b33a5771db430776c724870e6c8c
child 454623 cc6e54bee19e7153ae5ac6cc7887805f001c2470
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester
bugs1432864
milestone59.0
Bug 1432864 - Run native focussing steps on interaction commands. r=automatedtester Instead of generating custom focus events when interacting with elements, we can run the HTMLElement.focus() function will do the correct thing. Before this patch we only simulated focus events, whereas this patch will actually focus the element. MozReview-Commit-ID: IoBV2ngqOA5
testing/marionette/event.js
testing/marionette/interaction.js
testing/web-platform/tests/webdriver/tests/interaction/element_clear.py
testing/web-platform/tests/webdriver/tests/support/asserts.py
--- a/testing/marionette/event.js
+++ b/testing/marionette/event.js
@@ -1375,35 +1375,16 @@ event.sendEvent = function(eventType, el
   ev.metaKey = modifiers.meta;
   ev.altKey = modifiers.alt;
   ev.ctrlKey = modifiers.ctrl;
 
   ev.initEvent(eventType, opts.canBubble, true);
   el.dispatchEvent(ev);
 };
 
-event.focus = function(el, opts = {}) {
-  opts.canBubble = opts.canBubble || true;
-  let doc = el.ownerDocument || el.document;
-  let win = doc.defaultView;
-
-  let ev = new win.FocusEvent(el);
-  ev.initEvent("focus", opts.canBubble, true);
-  el.dispatchEvent(ev);
-};
-
-event.blur = function(el, {canBubble = true} = {}) {
-  let doc = el.ownerDocument || el.document;
-  let win = doc.defaultView;
-
-  let ev = new win.FocusEvent(el);
-  ev.initEvent("blur", canBubble, true);
-  el.dispatchEvent(ev);
-};
-
 event.mouseover = function(el, modifiers = {}, opts = {}) {
   return event.sendEvent("mouseover", el, modifiers, opts);
 };
 
 event.mousemove = function(el, modifiers = {}, opts = {}) {
   return event.sendEvent("mousemove", el, modifiers, opts);
 };
 
--- a/testing/marionette/interaction.js
+++ b/testing/marionette/interaction.js
@@ -265,17 +265,17 @@ interaction.selectOption = function(el) 
     throw new TypeError(pprint`Expected <option> element, got ${el}`);
   }
 
   let containerEl = element.getContainer(el);
 
   event.mouseover(containerEl);
   event.mousemove(containerEl);
   event.mousedown(containerEl);
-  event.focus(containerEl);
+  containerEl.focus();
 
   if (!el.disabled) {
     // Clicking <option> in <select> should not be deselected if selected.
     // However, clicking one in a <select multiple> should toggle
     // selectedness the way holding down Control works.
     if (containerEl.multiple) {
       el.selected = !el.selected;
     } else if (!el.selected) {
@@ -335,20 +335,20 @@ interaction.clearElement = function(el) 
     clearResettableElement(el);
   }
 };
 
 function clearContentEditableElement(el) {
   if (el.innerHTML === "") {
     return;
   }
-  event.focus(el);
+  el.focus();
   el.innerHTML = "";
   event.change(el);
-  event.blur(el);
+  el.blur();
 }
 
 function clearResettableElement(el) {
   if (!element.isMutableFormControl(el)) {
     throw new InvalidElementStateError(pprint`Not an editable form control: ${el}`);
   }
 
   let isEmpty;
@@ -361,20 +361,20 @@ function clearResettableElement(el) {
       isEmpty = el.value === "";
       break;
   }
 
   if (el.validity.valid && isEmpty) {
     return;
   }
 
-  event.focus(el);
+  el.focus();
   el.value = "";
   event.change(el);
-  event.blur(el);
+  el.blur();
 }
 
 /**
  * Waits until the event loop has spun enough times to process the
  * DOM events generated by clicking an element, or until the document
  * is unloaded.
  *
  * @param {Element} el
@@ -486,17 +486,17 @@ interaction.uploadFile = async function(
   fs.push(file);
 
   // <input type=file> opens OS widget dialogue
   // which means the mousedown/focus/mouseup/click events
   // occur before the change event
   event.mouseover(el);
   event.mousemove(el);
   event.mousedown(el);
-  event.focus(el);
+  el.focus();
   event.mouseup(el);
   event.click(el);
 
   el.mozSetFileArray(fs);
 
   event.change(el);
 };
 
--- a/testing/web-platform/tests/webdriver/tests/interaction/element_clear.py
+++ b/testing/web-platform/tests/webdriver/tests/interaction/element_clear.py
@@ -1,11 +1,15 @@
 import pytest
 
-from tests.support.asserts import assert_error, assert_success
+from tests.support.asserts import (
+    assert_element_has_focus,
+    assert_error,
+    assert_success,
+)
 from tests.support.inline import inline
 
 
 def add_event_listeners(element):
     element.session.execute_script("""
         let [target] = arguments;
         window.events = [];
         for (let expected of ["focus", "blur", "change"]) {
@@ -103,16 +107,17 @@ def test_input(session, type, value, def
 
     response = element_clear(session, element)
     assert_success(response)
     assert element.property("value") == default
     events = get_events(session)
     assert "focus" in events
     assert "change" in events
     assert "blur" in events
+    assert_element_has_focus(session.execute_script("return document.body"))
 
 
 @pytest.mark.parametrize("type",
                          ["number",
                           "range",
                           "email",
                           "password",
                           "search",
@@ -257,28 +262,30 @@ def test_contenteditable(session):
     element = session.find.css("p", all=False)
     add_event_listeners(element)
     assert element.property("innerHTML") == "foobar"
 
     response = element_clear(session, element)
     assert_success(response)
     assert element.property("innerHTML") == ""
     assert get_events(session) == ["focus", "change", "blur"]
+    assert_element_has_focus(session.execute_script("return document.body"))
 
 
 
 def test_designmode(session):
     session.url = inline("foobar")
     element = session.find.css("body", all=False)
     assert element.property("innerHTML") == "foobar"
     session.execute_script("document.designMode = 'on'")
 
     response = element_clear(session, element)
     assert_success(response)
     assert element.property("innerHTML") == "<br>"
+    assert_element_has_focus(session.execute_script("return document.body"))
 
 
 def test_resettable_element_focus_when_empty(session):
     session.url = inline("<input>")
     element = session.find.css("input", all=False)
     add_event_listeners(element)
     assert element.property("value") == ""
 
--- a/testing/web-platform/tests/webdriver/tests/support/asserts.py
+++ b/testing/web-platform/tests/webdriver/tests/support/asserts.py
@@ -151,9 +151,8 @@ def assert_element_has_focus(target_elem
 
 
 def assert_move_to_coordinates(point, target, events):
     for e in events:
         if e["type"] != "mousemove":
             assert e["pageX"] == point["x"]
             assert e["pageY"] == point["y"]
             assert e["target"] == target
-