Bug 1430575 - Add validity state check for WebDriver:ElementClear. r?automatedtester
This patch checks that the element satisfies its form control
constraints, as well as being empty, before deciding not to clear
the element. This will make it possible to clear elements that
have invalid input.
The "clear a resettable element" algorithm is missing a check of
the <input> element's ValidityState. WebDriver:ElementClear has
a subtle bug that only manifests in Gecko because Blink rejects
invalid key input to validation fields such as <input type=number>,
but Gecko does not.
The value property of <input type=number> will not be updated unless
the input is actually valid, which means the first step of the algorithm
will pass irregardless of whether the user has actually modified it.
MozReview-Commit-ID: C2M3Fl1iKx6
--- a/testing/marionette/interaction.js
+++ b/testing/marionette/interaction.js
@@ -324,41 +324,56 @@ interaction.clearElement = function(el)
if (!element.isInView(el)) {
element.scrollIntoView(el);
}
if (!element.isInView(el)) {
throw new ElementNotInteractableError(
pprint`Element ${el} could not be scrolled into view`);
}
- let attr;
if (element.isEditingHost(el)) {
- attr = "innerHTML";
+ clearContentEditableElement(el);
} else {
- attr = "value";
+ clearResettableElement(el);
+ }
+};
+
+function clearContentEditableElement(el) {
+ if (el.innerHTML === "") {
+ return;
+ }
+ event.focus(el);
+ el.innerHTML = "";
+ event.blur(el);
+}
+
+function clearResettableElement(el) {
+ if (!element.isMutableFormControl(el)) {
+ throw new InvalidElementStateError(pprint`Not an editable form control: ${el}`);
}
+ let isEmpty;
switch (el.type) {
case "file":
- if (el.files.length == 0) {
- return;
- }
+ isEmpty = el.files.length == 0;
break;
default:
- if (el[attr] === "") {
- return;
- }
+ isEmpty = el.value === "";
break;
}
+ if (el.validity.valid && isEmpty) {
+ return;
+ }
+
event.focus(el);
- el[attr] = "";
+ el.value = "";
event.blur(el);
-};
+}
/**
* 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
* Element that is expected to receive the click.
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -535032,17 +535032,17 @@
"d94cfadf60dc146f80f7c1dc9937d7841600f9ef",
"testharness"
],
"fetch/api/response/response-init-001.html": [
"a45bf860ad19e31ff95c3add7b6f4ad7c0573254",
"testharness"
],
"fetch/api/response/response-init-002.html": [
- "9806050696657f48e609bbc943ba15a78d6464d1",
+ "5b87fa0d008f633d73bd87ab1755eee719b104cc",
"testharness"
],
"fetch/api/response/response-static-error.html": [
"96b1d4f58925cb9ba5a07aef28aa4b869c67f93b",
"testharness"
],
"fetch/api/response/response-static-redirect.html": [
"e497388ce041fd300200d23c63caadb1fe53d1c1",
@@ -583356,17 +583356,17 @@
"817011a8cdff7cfd7e445fb8ecb84e5d91f03993",
"wdspec"
],
"webdriver/tests/get_window_rect.py": [
"c9139c16aa950c734c776887d6a762b867790812",
"wdspec"
],
"webdriver/tests/interaction/element_clear.py": [
- "109a1b9fed21b257503321b42bd670f9c36a0bcc",
+ "222a472b70c38e9178bdb64cc13a99053169a831",
"wdspec"
],
"webdriver/tests/interaction/send_keys_content_editable.py": [
"9c071e60e1203cf31120f20874b5f38ba41dacc3",
"wdspec"
],
"webdriver/tests/interface.html": [
"6625887cfa7f461dc428c11861fce71c47bef57d",
--- a/testing/web-platform/tests/webdriver/tests/interaction/element_clear.py
+++ b/testing/web-platform/tests/webdriver/tests/interaction/element_clear.py
@@ -307,16 +307,58 @@ def test_resettable_element_focus_when_e
assert element.property("value") == ""
response = element_clear(session, element)
assert_success(response)
assert element.property("value") == ""
assert session.execute_script("return window.events") == []
+@pytest.mark.parametrize("type,invalid_value",
+ [("number", "foo"),
+ ("range", "foo"),
+ ("email", "foo"),
+ ("url", "foo"),
+ ("color", "foo"),
+ ("date", "foo"),
+ ("datetime", "foo"),
+ ("datetime-local", "foo"),
+ ("time", "foo"),
+ ("month", "foo"),
+ ("week", "foo")])
+def test_resettable_element_does_not_satisfy_validation_constraints(session, type, invalid_value):
+ """
+ Some UAs allow invalid input to certain types of constrained
+ form controls. For example, Gecko allows non-valid characters
+ to be typed into <input type=number> but Chrome does not.
+ Since we want to test that Element Clear works for clearing the
+ invalid characters in these UAs, it is fine to skip this test
+ where UAs do not allow the element to not satisfy its constraints.
+ """
+ session.url = inline("<input type=%s>" % type)
+ element = session.find.css("input", all=False)
+
+ def is_valid(element):
+ return session.execute_script("""
+ let [input] = arguments;
+ return input.validity.valid;
+ """, args=(element,))
+
+ # value property does not get updated if the input is invalid
+ element.send_keys(invalid_value)
+
+ # UA does not allow invalid input for this form control type
+ if is_valid(element):
+ return
+
+ response = element_clear(session, element)
+ assert_success(response)
+ assert is_valid(element)
+
+
@pytest.mark.parametrize("type",
["checkbox",
"radio",
"hidden",
"submit",
"button",
"image"])
def test_non_editable_inputs(session, type):