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
--- 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
@@ -132,8 +132,19 @@ def assert_same_element(session, a, b):
try:
a_markup = session.execute_script("return arguments[0].outerHTML;", args=(a,))
b_markup = session.execute_script("return arguments[0].outerHTML;", args=(b,))
message += " Actual: `%s`. Expected: `%s`." % (a_markup, b_markup)
except WebDriverException:
pass
raise AssertionError(message)
+
+
+def assert_element_has_focus(target_element):
+ session = target_element.session
+
+ active_element = session.execute_script("return document.activeElement")
+ active_tag = active_element.property("localName")
+ target_tag = target_element.property("localName")
+
+ assert active_element == target_element, (
+ "Focussed element is <%s>, not <%s>" % (active_tag, target_tag))