summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/forms/the-input-element
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/semantics/forms/the-input-element')
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-active-contenteditable.html25
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html25
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-dynamic.html12
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-ref.html2
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/button.html66
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/change-to-empty-value.html31
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur-with-click.html158
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur.html52
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-being-disabled.html90
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-prevented-default.html55
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-untrusted-event.html48
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox-click-events.html109
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox.html149
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/checked.xhtml19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/clone.html150
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/cloning-steps.html64
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/color.html45
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/date.html90
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local-trailing-zeros.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-weekmonth.html51
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/datetime.html60
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/defaultValue-clobbering.html36
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/disabled-click-picker-manual.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/email-set-value.html30
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/email.html66
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/event-select-manual.html39
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/file-manual.html30
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/files.html83
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change-on-blur.html61
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change.html55
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive-child.html5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive.html30
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/hidden.html74
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/image-click-form-data.html28
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/image01-ref.html5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/image01.html7
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-checkvalidity.html44
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-disabled-fieldset-dynamic.html38
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-form-detach-style-crash.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-height.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-importNode-to-detached-document-crash.html11
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-labels.html49
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-list.html67
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-seconds-leading-zeroes.html52
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-setcustomvalidity.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-weekmonth.html22
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown.html43
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup-weekmonth.html22
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup.html44
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-submit-remove-jssubmit.html36
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-button.html51
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-empty-crash.html8
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-value.html33
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox-switch.tentative.window.js19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox.html60
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-number-rtl-invalid-crash.html11
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-types.js24
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-untrusted-key-event.html225
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-validationmessage.html40
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-validity.html40
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-value-invalidstateerr.html41
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-invalidstateerr.html41
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-stepping.html83
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate.html108
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-invalidstateerr.html39
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-stepping.html94
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber.html151
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-whitespace.html34
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-width.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/input-willvalidate.html40
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/invalid-datalist-options-crash.html6
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/large-step-crash.html9
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-manual.html37
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-number.html19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength.html55
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/minlength.html55
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/month.html100
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-cr.html1
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-crlf.html19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-ref.html5
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder.html19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/number-constraint-validation.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/number-disabled.html18
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/number.html57
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/password-delete-space.html20
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/password.html79
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/pattern_attribute.html117
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update-ref.html2
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-disconnected-group-owner.html168
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-double-activate-pseudo.html22
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-groupname-case.html83
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-input-cancel.html41
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-keyboard-navigation-order.html70
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-morphed.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio-multiple-selected.html21
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/radio.html351
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-2.html43
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size-ref.html97
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size.html85
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-added-repaint.html19
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-change-repaint.html24
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-duplicate-id-repaint.html26
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-nonexistent.html20
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-add-repaint.html21
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-remove-repaint.html20
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-value-change-repaint.html20
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html52
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value-ref.html7
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value.html27
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01-notref.html3
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01.html13
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02-ref.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03-notref.html9
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04-ref.html7
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04.html15
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05-ref.html7
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/range.html245
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/required_attribute.html34
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/reset.html113
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/image-submit-click.html15
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/loadresolver.html6
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers1
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/show-picker-child-iframe.html26
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers1
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/search_input.html35
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/selection-pointer.html56
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/selection-weekmonth.html57
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/selection.html140
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-cross-origin-iframe.html79
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-disabled-readonly.html43
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-user-gesture.html31
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/telephone.html84
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/text.html104
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/time-2.html42
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/time-datalist-crash.html15
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/time-focus-dynamic-value-change.html31
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/time.html357
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html11
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state-weekmonth.html169
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state.html166
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/url.html59
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode-weekmonth.html37
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode.html304
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-input-element/week.html41
151 files changed, 7959 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-active-contenteditable.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-active-contenteditable.html
new file mode 100644
index 0000000000..88a9a35cc5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-active-contenteditable.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<link rel="help" href="http://crbug.com/1007941">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<!-- This behavior is not explicitly specified. -->
+
+<a id=anchorid href="nonexistant">anchor</a>
+
+<script>
+anchorid.addEventListener('mousedown', () => {
+ anchorid.contentEditable = true;
+});
+
+promise_test(async () => {
+ await test_driver.click(anchorid);
+ assert_equals(document.querySelector(':active'), null);
+}, 'Anchor elements should not stay :active when contentEditable is enabled.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html
new file mode 100644
index 0000000000..e958f10df8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<!-- This behavior is not explicitly specified. -->
+
+<a id=anchorid href="javascript:window.anchornavigated = true;">anchor</a>
+
+<script>
+promise_test(async () => {
+ window.anchornavigated = false;
+
+ anchorid.contentEditable = true;
+ await test_driver.click(anchorid);
+
+ assert_false(window.anchornavigated, "Anchor's javascript: url was run.");
+
+}, 'Anchor elements should not be able to navigate if they have contentEditable.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-dynamic.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-dynamic.html
new file mode 100644
index 0000000000..68ea51185c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-dynamic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<link rel="match" href="auto-direction-ref.html">
+<body>
+<script>
+const dirInput = document.createElement('input')
+dirInput.setAttribute('dir', 'auto')
+dirInput.setAttribute('value', 'شنينسنمس')
+document.body.appendChild(dirInput)
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-ref.html
new file mode 100644
index 0000000000..675ba50914
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/auto-direction-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<input dir="auto" value="شنينسنمس">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/button.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/button.html
new file mode 100644
index 0000000000..3c826a9754
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/button.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type button</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#button-state-(type=button)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<form id=f1>
+ <input type=button id=b1 name=b1>
+</form>
+<form>
+ <input id=i1 value="foo">
+ <input type=button id=b2 name=b2>
+</form>
+<form>
+ <input type=radio id=i2 checked name=b3>
+ <input type=button id=b3 name=b3>
+</form>
+<form>
+ <input type=checkbox id=i3>
+ <input type=button id=b4 name=b4>
+</form>
+
+<script>
+ var t = async_test("clicking on button should not submit a form"),
+ b1 = document.getElementById('b1'),
+ b2 = document.getElementById('b2'),
+ b3 = document.getElementById('b3'),
+ b4 = document.getElementById('b4'),
+ i1 = document.getElementById('i1'),
+ i2 = document.getElementById('i2'),
+ i3 = document.getElementById('i3');
+
+ test(function(){
+ assert_false(b1.willValidate);
+ }, "the element is barred from constraint validation");
+
+ document.getElementById('f1').onsubmit = t.step_func(function(e) {
+ e.preventDefault();
+ assert_unreached("form has been submitted");
+ });
+
+ t.step(function() {
+ b1.click();
+ });
+ t.done();
+
+ test(function(){
+ i1.value = "bar";
+ b2.click();
+ assert_equals(i1.value, "bar");
+ }, "clicking on button should not reset other form fields");
+
+ test(function(){
+ assert_true(i2.checked);
+ b3.click();
+ assert_true(i2.checked);
+ }, "clicking on button should not unchecked radio buttons");
+
+ test(function(){
+ assert_false(i3.indeterminate);
+ b4.click();
+ assert_false(i3.indeterminate);
+ }, "clicking on button should not change its indeterminate IDL attribute");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/change-to-empty-value.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/change-to-empty-value.html
new file mode 100644
index 0000000000..fd1eeb4584
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/change-to-empty-value.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Change event when clearing an input</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1881457">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<input type="text" value="abc">
+<script>
+promise_test(async function() {
+ let input = document.querySelector("input");
+ let changeFired = false;
+ input.addEventListener("change", () => {
+ changeFired = true;
+ }, { once: true });
+ input.focus();
+ assert_equals(document.activeElement, input, "Should focus input");
+ assert_false(changeFired, "Shouldn't have fired change event after focus");
+ input.select();
+ const kBackspaceKey = "\uE003";
+ await test_driver.send_keys(input, kBackspaceKey)
+ assert_false(changeFired, "Shouldn't have fired change event after select");
+ input.blur();
+ assert_true(changeFired, "Should've have fired change event after blur");
+ assert_equals(input.value, "", "Should've have cleared the value");
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur-with-click.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur-with-click.html
new file mode 100644
index 0000000000..2d5d008622
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur-with-click.html
@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+* {
+ font-size: 20px;
+}
+</style>
+</head>
+<body>
+
+<!-- This behavior is not explicitly specified. -->
+
+<input type=checkbox id=cb1 checked> <label for=cb1>ghi</label>
+<input type=radio id=r1 checked> <label for=r1>jkl</label>
+<label id=lc>abc <input type=checkbox id=cb2 checked></label>
+<label id=lr>def <input type=radio id=r2 checked></label>
+
+<script>
+promise_test(async () => {
+ await new Promise(resolve => {
+ addEventListener("load", resolve, { once: true });
+ });
+}, "Wait for load");
+
+const tabKey = "\uE004";
+promise_test(async t => {
+ const checkbox = document.querySelector("input[type=checkbox]");
+ // pointerdown on the checkbox
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: checkbox })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), checkbox,
+ "Checkboxes should be :active while it is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Checkboxes should not be :active after tab is used to change focus.");
+}, "Checkboxes should clear :active when the user tabs away from them while pressing it with a pointing device");
+
+promise_test(async t => {
+ const radio = document.querySelector("input[type=radio]");
+ // pointerdown on the radio
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: radio })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), radio,
+ "Radios should be :active while it is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Radios should not be :active after tab is used to change focus.");
+}, "Radios should clear :active when the user tabs away from them while pressing it with a pointing device");
+
+promise_test(async t => {
+ const checkbox = document.querySelector("label > input[type=checkbox]");
+ const label = checkbox.parentElement;
+ // pointerdown on the label
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: label })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), checkbox,
+ "Checkboxes should be :active while the label is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Checkboxes should not be :active after tab is used to change focus.");
+}, "Checkboxes should clear :active when the user tabs away from them while pressing the parent label with a pointing device");
+
+promise_test(async t => {
+ const radio = document.querySelector("label > input[type=radio]");
+ const label = radio.parentElement;
+ const radioRect = radio.getBoundingClientRect();
+ const labelRect = label.getBoundingClientRect();
+ // pointerdown on the label
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: label })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), radio,
+ "Radios should be :active while the label is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Radios should not be :active after tab is used to change focus.");
+}, "Radios should clear :active when the user tabs away from them while pressing the parent label with a pointing device");
+
+promise_test(async t => {
+ const label = document.querySelector("label[for=cb1]");
+ // pointerdown on the label
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: label })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), label.control,
+ "Checkboxes should be :active while the label is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Checkboxes should not be :active after tab is used to change focus.");
+}, "Checkboxes should clear :active when the user tabs away from them while pressing the following label with a pointing device");
+
+promise_test(async t => {
+ const label = document.querySelector("label[for=r1]");
+ // pointerdown on the label
+ await (new test_driver.Actions()
+ .pointerMove(2, 2, { origin: label })
+ .pointerDown())
+ .send();
+ t.add_cleanup(async () => {
+ // Release the pointer
+ await (new test_driver.Actions().pointerUp()).send();
+ });
+ assert_equals(document.querySelector("input:active"), label.control,
+ "Radios should be :active while the label is pressed");
+
+ // Press tab
+ await (new test_driver.Actions().keyDown(tabKey).keyUp(tabKey)).send();
+ assert_equals(document.querySelector(":active"), null,
+ "Radios should not be :active after tab is used to change focus.");
+}, "Radios should clear :active when the user tabs away from them while pressing the following label with a pointing device");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur.html
new file mode 100644
index 0000000000..cc88996fe7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-onblur.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<link rel="help" href="http://crbug.com/1157510">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<!-- This behavior is not explicitly specified. -->
+
+<input type=checkbox id=checkbox checked>
+<input type=radio id=radio checked>
+
+<script>
+promise_test(async t => {
+ checkbox.focus();
+
+ // Hold spacebar down
+ await (new test_driver.Actions()).keyDown('\uE00D').send();
+ t.add_cleanup(async () => {
+ // Release spacebar
+ await (new test_driver.Actions()).keyUp('\uE00D').send();
+ });
+ assert_equals(document.querySelector('input:active'), checkbox,
+ 'Checkboxes should be :active while the spacebar is pressed down.');
+
+ // Press tab
+ await (new test_driver.Actions()).keyDown('\uE004').keyUp('\uE004').send();
+ assert_equals(document.querySelector(':active'), null,
+ 'Checkboxes should not be :active after tab is used to change focus.');
+}, 'Checkboxes should clear :active when the user tabs away from them while holding spacebar.');
+
+promise_test(async t => {
+ radio.focus();
+
+ // Hold spacebar down
+ await (new test_driver.Actions()).keyDown('\uE00D').send();
+ t.add_cleanup(async () => {
+ // Release spacebar
+ await (new test_driver.Actions()).keyUp('\uE00D').send();
+ });
+ assert_equals(document.querySelector('input:active'), radio,
+ 'Radios should be :active while the spacebar is pressed down.');
+
+ // Press tab
+ await (new test_driver.Actions()).keyDown('\uE004').keyUp('\uE004').send();
+ assert_equals(document.querySelector(':active'), null,
+ 'Radios should not be :active after tab is used to change focus.');
+}, 'Radios should clear :active when the user tabs away from them while holding spacebar.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-being-disabled.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-being-disabled.html
new file mode 100644
index 0000000000..5f725b85f4
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-being-disabled.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Tests active state of checkbox/radio when pressing space key but it's disabled by a keydown event listener</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+<input type="checkbox">
+<input type="radio">
+<script>
+const spaceKey = "\uE00D";
+
+function disableTarget(event) {
+ event.target.disabled = true;
+}
+
+// If a `keydown` event listener disables the event target, default event
+// handler in browser shouldn't activate the disabled element. Otherwise,
+// the browser loses a chance to inactivate the disabled element because
+// it won't get keyup events until it's enabled again.
+
+promise_test(async t => {
+ const checkbox = document.querySelector("input[type=checkbox]");
+ checkbox.focus();
+ checkbox.addEventListener("keydown", disableTarget);
+ await (new test_driver.Actions()).keyDown(spaceKey).send();
+ let released = false;
+ t.add_cleanup(async () => {
+ if (!released) {
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ }
+ checkbox.removeEventListener("keydown", disableTarget);
+ checkbox.remove();
+ });
+ test(() => {
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The checkbox shouldn't be activated"
+ );
+ }, "Space key press shouldn't activate the disabled checkbox");
+
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ released = true;
+
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The disabled checkbox should be inactivated even if activated accidentally"
+ );
+}, "Space key shouldn't active the checkbox when it's disabled by a keydown event listener");
+
+promise_test(async t => {
+ const radio = document.querySelector("input[type=radio]");
+ radio.focus();
+ radio.addEventListener("keydown", disableTarget);
+ await (new test_driver.Actions()).keyDown(spaceKey).send();
+ let released = false;
+ t.add_cleanup(async () => {
+ if (!released) {
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ }
+ radio.removeEventListener("keydown", disableTarget);
+ radio.disabled = false;
+ });
+ test(() => {
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The radio shouldn't be activated"
+ );
+ }, "Space key press shouldn't activate the disabled radio");
+
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ released = true;
+
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The disabled radio should be inactivated even if it's accidentally activated"
+ );
+}, "Space key shouldn't active the radio when it's disabled by a keydown event listener");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-prevented-default.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-prevented-default.html
new file mode 100644
index 0000000000..877cd70e29
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-prevented-default.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Tests active state of checkbox/radio when pressing space key but its default prevented</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+<input type="checkbox">
+<input type="radio">
+<script>
+const spaceKey = "\uE00D";
+
+function preventDefault(event) {
+ event.preventDefault();
+}
+
+promise_test(async t => {
+ const checkbox = document.querySelector("input[type=checkbox]");
+ checkbox.focus();
+ checkbox.addEventListener("keydown", preventDefault);
+ await (new test_driver.Actions()).keyDown(spaceKey).send();
+ t.add_cleanup(async () => {
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ checkbox.removeEventListener("keydown", preventDefault);
+ });
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The checkbox shouldn't be activated"
+ );
+}, "Space key shouldn't active the checkbox when its default is prevented");
+
+promise_test(async t => {
+ const radio = document.querySelector("input[type=radio]");
+ radio.focus();
+ radio.addEventListener("keydown", preventDefault);
+ await (new test_driver.Actions()).keyDown(spaceKey).send();
+ t.add_cleanup(async () => {
+ await (new test_driver.Actions()).keyUp(spaceKey).send();
+ radio.removeEventListener("keydown", preventDefault);
+ });
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The radio shouldn't be activated"
+ );
+}, "Space key shouldn't active the radio when its default is prevented");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-untrusted-event.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-untrusted-event.html
new file mode 100644
index 0000000000..190757d8d3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkable-active-space-key-untrusted-event.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Tests active state of checkbox/radio when pressing space key emulated with untrusted key events</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<input type="checkbox">
+<input type="radio">
+<script>
+function sendSpaceKeyEvent(eventType, target) {
+ const eventData = { keyCode: 32, which: 32, key: " ", code: "Space"};
+ const spaceKeyEvent = new KeyboardEvent(eventType, eventData);
+ target.dispatchEvent(spaceKeyEvent);
+}
+
+test(t => {
+ const checkbox = document.querySelector("input[type=checkbox]");
+ checkbox.focus();
+ sendSpaceKeyEvent("keydown", checkbox);
+ t.add_cleanup(() => {
+ sendSpaceKeyEvent("keyup", checkbox);
+ });
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The checkbox shouldn't be activated"
+ );
+}, "Space key shouldn't active the checkbox when space key press is emulated by untrusted events");
+
+test(t => {
+ const radio = document.querySelector("input[type=radio]");
+ radio.focus();
+ sendSpaceKeyEvent("keydown", radio);
+ t.add_cleanup(() => {
+ sendSpaceKeyEvent("keyup", radio);
+ });
+ assert_equals(
+ document.querySelector("input:active"),
+ null,
+ "The radio shouldn't be activated"
+ );
+}, "Space key shouldn't active the radio when space key press is emulated by untrusted events");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox-click-events.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox-click-events.html
new file mode 100644
index 0000000000..5051fdd4e6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox-click-events.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Checkbox click events</title>
+<link rel="author" title="jeffcarp" href="mailto:gcarpenterv@gmail.com">
+<link rel=help href="https://html.spec.whatwg.org/#checkbox-state-(type=checkbox)">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+test(() => {
+
+ const input = document.createElement("input");
+ input.type = "checkbox";
+
+ const values = [];
+
+ input.addEventListener("click", e => {
+ values.push(input.checked);
+ e.preventDefault();
+ values.push(input.checked);
+ });
+
+ input.click();
+
+ values.push(input.checked);
+ assert_array_equals(values, [true, true, false]);
+
+}, "clicking and preventDefaulting a checkbox causes the checkbox to be checked during the click handler but reverted");
+
+test(() => {
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ document.body.appendChild(input);
+ const events = [];
+
+ input.addEventListener("change", () => {
+ events.push("change");
+ });
+ input.addEventListener("click", () => {
+ events.push("click");
+ });
+ input.addEventListener("input", () => {
+ events.push("input");
+ });
+
+ assert_false(input.checked);
+
+ input.click();
+
+ assert_true(input.checked);
+ assert_array_equals(events, ["click", "input", "change"]);
+
+}, "a checkbox input emits click, input, change events in order after synthetic click");
+
+test(() => {
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ document.body.appendChild(input);
+ const events = [];
+
+ input.addEventListener("change", () => {
+ events.push("change");
+ });
+ input.addEventListener("click", () => {
+ events.push("click");
+ });
+ input.addEventListener("input", () => {
+ events.push("input");
+ });
+
+ assert_false(input.checked);
+
+ const event = new MouseEvent("click", { bubbles: true, cancelable: true });
+ input.dispatchEvent(event);
+
+ assert_true(input.checked);
+ assert_array_equals(events, ["click", "input", "change"]);
+
+}, "a checkbox input emits click, input, change events in order after dispatching click event");
+
+test(() => {
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ document.body.appendChild(input);
+ const events = [];
+
+ input.addEventListener("change", () => {
+ events.push("change");
+ });
+ input.addEventListener("click", e => {
+ e.preventDefault();
+ events.push("click");
+ });
+ input.addEventListener("input", () => {
+ events.push("input");
+ });
+
+ assert_false(input.checked);
+
+ input.click();
+
+ assert_false(input.checked);
+ assert_array_equals(events, ["click"]);
+}, "checkbox input respects cancel behavior on synthetic clicks");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox.html
new file mode 100644
index 0000000000..c48083d685
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checkbox.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type checkbox</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#checkbox-state-(type=checkbox)">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<input type=checkbox id=checkbox1>
+<input type=checkbox id=checkbox2 disabled>
+<input type=checkbox id=checkbox3>
+<input type=checkbox id=checkbox4 checked>
+<input type=checkbox id=checkbox5>
+<input type=checkbox id=checkbox6>
+<script>
+ var checkbox1 = document.getElementById('checkbox1'),
+ checkbox2 = document.getElementById('checkbox2'),
+ checkbox3 = document.getElementById('checkbox3'),
+ checkbox4 = document.getElementById('checkbox4'),
+ checkbox5 = document.getElementById('checkbox5'),
+ checkbox6 = document.getElementById('checkbox6'),
+ c1_click_fired = false,
+ c1_input_fired = false,
+ c1_change_fired = false,
+ t1 = async_test("click on mutable checkbox fires a click event, then an input event, then a change event"),
+ t2 = async_test("click on non-mutable checkbox doesn't fire the input or change event"),
+ t3 = async_test("pre-activation steps on unchecked checkbox"),
+ t4 = async_test("pre-activation steps on checked checkbox"),
+ t5 = async_test("canceled activation steps on unchecked checkbox"),
+ t6 = async_test("canceled activation steps on unchecked checkbox (indeterminate=true in onclick)");
+
+ checkbox1.onclick = t1.step_func(function(e) {
+ c1_click_fired = true;
+ assert_false(c1_input_fired, "click event should fire before input event");
+ assert_false(c1_change_fired, "click event should fire before change event");
+ assert_false(e.isTrusted, "click()-initiated click event should not be trusted");
+ });
+ checkbox1.oninput = t1.step_func(function(e) {
+ c1_input_fired = true;
+ assert_true(c1_click_fired, "input event should fire after click event");
+ assert_false(c1_change_fired, "input event should fire before change event");
+ assert_true(e.bubbles, "event should bubble");
+ assert_true(e.isTrusted, "click()-initiated event should be trusted");
+ assert_false(e.cancelable, "event should not be cancelable");
+ assert_true(checkbox1.checked, "checkbox is checked");
+ assert_false(checkbox1.indeterminate, "checkbox is not indeterminate");
+ });
+
+ checkbox1.onchange = t1.step_func(function(e) {
+ c1_change_fired = true;
+ assert_true(c1_click_fired, "change event should fire after click event");
+ assert_true(c1_input_fired, "change event should fire after input event");
+ assert_true(e.bubbles, "event should bubble")
+ assert_true(e.isTrusted, "click()-initiated event should be trusted");
+ assert_false(e.cancelable, "event should not be cancelable");
+ assert_true(checkbox1.checked, "checkbox is checked");
+ assert_false(checkbox1.indeterminate, "checkbox is not indeterminate");
+ });
+
+ checkbox2.oninput= t2.step_func(function(e) {
+ assert_unreached("event input fired");
+ });
+
+ checkbox2.onchange = t2.step_func(function(e) {
+ assert_unreached("event change fired");
+ });
+
+ t1.step(function() {
+ checkbox1.click();
+ assert_true(c1_input_fired);
+ assert_true(c1_change_fired);
+ t1.done();
+ });
+
+ t2.step(function() {
+ checkbox2.click();
+ t2.done();
+ });
+
+ t3.step(function() {
+ checkbox3.indeterminate = true;
+ checkbox3.click();
+ assert_true(checkbox3.checked);
+ assert_false(checkbox3.indeterminate);
+ t3.done();
+ });
+
+ t4.step(function() {
+ checkbox4.indeterminate = true;
+ checkbox4.click();
+ assert_false(checkbox4.checked);
+ assert_false(checkbox4.indeterminate);
+ t4.done();
+ });
+
+ checkbox5.onclick = t5.step_func(function(e) {
+ e.preventDefault();
+ /*
+ The prevention of the click doesn't have an effect until after all the
+ click event handlers have been run.
+ */
+ assert_true(checkbox5.checked);
+ assert_false(checkbox5.indeterminate);
+ t5.step_timeout(function() {
+ /*
+ The click event has finished being dispatched, so the checkedness and
+ determinateness have been toggled back by now because the event
+ was preventDefault-ed.
+ */
+ assert_false(checkbox5.checked);
+ assert_false(checkbox5.indeterminate);
+ t5.done();
+ }, 0);
+ });
+
+ t5.step(function(){
+ assert_false(checkbox5.checked);
+ assert_false(checkbox5.indeterminate);
+ checkbox5.click();
+ });
+
+ checkbox6.onclick = t6.step_func(function(e) {
+ checkbox6.indeterminate = true;
+ e.preventDefault();
+ /*
+ The prevention of the click doesn't have an effect until after all the
+ click event handlers have been run.
+ */
+ assert_true(checkbox6.checked);
+ assert_true(checkbox6.indeterminate);
+ t6.step_timeout(function() {
+ /*
+ The click event has finished being dispatched, so the checkedness and
+ determinateness have been toggled back by now because the event
+ was preventDefault-ed.
+ */
+ assert_false(checkbox6.checked);
+ assert_false(checkbox6.indeterminate);
+ t6.done();
+ }, 0);
+ });
+
+ t6.step(function(){
+ assert_false(checkbox6.checked);
+ assert_false(checkbox6.indeterminate);
+ checkbox6.click();
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/checked.xhtml b/testing/web-platform/tests/html/semantics/forms/the-input-element/checked.xhtml
new file mode 100644
index 0000000000..70aeb51097
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/checked.xhtml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>input@checked is immediately reflected to 'checked' IDL attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<input style="display: none" type="checkbox" checked="">
+<script>
+test(function(){
+assert_true(document.querySelector('input').checked, 'Examining "checked" IDL attribute value:')
+});
+</script>
+</input>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/clone.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/clone.html
new file mode 100644
index 0000000000..0f7e053baa
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/clone.html
@@ -0,0 +1,150 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Test input value retention upon clone</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>form {display: none;} </style>
+<form>
+<p><input type=checkbox> This checkbox is initially unchecked.</p>
+<p><input type=checkbox checked="checked"> This checkbox is initially checked.</p>
+<p><input type=radio name=radio> This radiobutton is initially unchecked.</p>
+<p><input type=radio checked="checked" name=radio> This radiobutton is initially checked.</p>
+<p><input type=hidden value="DEFAULT
+DEFAULT"> This hidden field has the initial value "DEFAULT\nDEFAULT".</p>
+<p><input type=text value=DEFAULT> This text field has the initial value "DEFAULT".</p>
+<p><input type=search value=DEFAULT> This search field has the initial value "DEFAULT".</p>
+<p><input type=tel value=DEFAULT> This phone number field has the initial value "DEFAULT".</p>
+<p><input type=url value=https://default.invalid/> This URL field has the initial value "https://default.invalid/".</p>
+<p><input type=email value=default@default.invalid> This email field has the initial value "default@default.invalid".</p>
+<p><input type=password value=DEFAULT> This password field has the initial value "DEFAULT".</p>
+<p><input type=date value=2015-01-01> This date field has the initial value "2015-01-01".</p>
+<p><input type=month value=2015-01> This month field has the initial value "2015-01".</p>
+<p><input type=week value=2015-W01> This week field has the initial value "2015-W01".</p>
+<p><input type=time value=12:00> This time field has the initial value "12:00".</p>
+<p><input type=datetime-local value=2015-01-01T12:00> This datetime (local) field has the initial value "2015-01-01T12:00".</p>
+<p><input type=number value=1> This number field has the initial value "1".</p>
+<p><input type=range value=1> This range control has the initial value "1".</p>
+<p><input type=color value=#ff0000> This color picker has the initial value "#FF0000".</p>
+<p><input type="button" value="Clone" onclick="clone();"></p>
+</form>
+<script>
+setup(function() {
+ let form = document.getElementsByTagName("form")[0];
+ let inputs = form.getElementsByTagName("input");
+ inputs[0].checked = true;
+ inputs[1].checked = false;
+ inputs[2].checked = true;
+ inputs[4].value = "CHANGED\nCHANGED";
+ inputs[5].value = "CHANGED";
+ inputs[6].value = "CHANGED";
+ inputs[7].value = "CHANGED";
+ inputs[8].value = "https://changed.invalid/";
+ inputs[9].value = "changed@changed.invalid";
+ inputs[10].value = "CHANGED";
+ inputs[11].value = "2016-01-01";
+ inputs[12].value = "2016-01";
+ inputs[13].value = "2016-W01";
+ inputs[14].value = "12:30";
+ inputs[15].value = "2016-01-01T12:30";
+ inputs[16].value = "2";
+ inputs[17].value = "2";
+ inputs[18].value = "#00ff00";
+ let clone = form.cloneNode(true);
+ document.body.appendChild(clone);
+});
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_true(inputs[0].checked, "Should have retained checked state");
+}, "Checkbox must retain checked state.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_false(inputs[1].checked, "Should have retained unchecked state");
+}, "Checkbox must retain unchecked state.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_true(inputs[2].checked, "Should have retained checked state");
+}, "Radiobutton must retain checked state.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_false(inputs[3].checked, "Should have retained unchecked state");
+}, "Radiobutton must retain unchecked state.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[4].value, "CHANGED\nCHANGED", "Should have retained the changed value.");
+}, "Hidden field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[5].value, "CHANGED", "Should have retained the changed value.");
+}, "Text field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[6].value, "CHANGED", "Should have retained the changed value.");
+}, "Search field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[7].value, "CHANGED", "Should have retained the changed value.");
+}, "Phone number field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[8].value, "https://changed.invalid/", "Should have retained the changed value.");
+}, "URL field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[9].value, "changed@changed.invalid", "Should have retained the changed value.");
+}, "Email field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[10].value, "CHANGED", "Should have retained the changed value.");
+}, "Password field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[11].value, "2016-01-01", "Should have retained the changed value.");
+}, "Date field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[12].value, "2016-01", "Should have retained the changed value.");
+}, "Month field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[13].value, "2016-W01", "Should have retained the changed value.");
+}, "Week field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[14].value, "12:30", "Should have retained the changed value.");
+}, "Time field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[15].value, "2016-01-01T12:30", "Should have retained the changed value.");
+}, "Datetime (local) field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[16].value, "2", "Should have retained the changed value.");
+}, "Number field must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[17].value, "2", "Should have retained the changed value.");
+}, "Range control must retain changed value.");
+test(function() {
+ let clone = document.getElementsByTagName("form")[1];
+ let inputs = clone.getElementsByTagName("input");
+ assert_equals(inputs[18].value, "#00ff00", "Should have retained the changed value.");
+}, "Color picker must retain changed value.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/cloning-steps.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/cloning-steps.html
new file mode 100644
index 0000000000..fe468509e8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/cloning-steps.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Cloning of input elements</title>
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode">
+<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone">
+<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone-ext">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#the-input-element:concept-node-clone-ext">
+<link rel="author" title="Matthew Phillips" href="mailto:matthew@matthewphillips.info">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script type=module>
+import inputTypes from "./input-types.js";
+
+test(function() {
+ var input = document.createElement("input");
+ input.value = "foo bar";
+
+ var copy = input.cloneNode();
+ assert_equals(copy.value, "foo bar");
+}, "input element's value should be cloned");
+
+test(function() {
+ var input = document.createElement("input");
+ input.value = "foo bar";
+
+ var copy = input.cloneNode();
+ copy.setAttribute("value", "something else");
+
+ assert_equals(copy.value, "foo bar");
+}, "input element's dirty value flag should be cloned, so setAttribute doesn't affect the cloned input's value");
+
+for (const inputType of inputTypes) {
+ test(function() {
+ var input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.indeterminate = true;
+
+ var copy = input.cloneNode();
+ assert_equals(copy.indeterminate, true);
+ }, `input[type=${inputType}] element's indeterminateness should be cloned`);
+
+ test(function() {
+ var input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.checked = true;
+
+ var copy = input.cloneNode();
+ assert_equals(copy.checked, true);
+ }, `input[type=${inputType}] element's checkedness should be cloned`);
+
+ test(function() {
+ var input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.checked = false;
+
+ var copy = input.cloneNode();
+ copy.setAttribute("checked", "checked");
+
+ assert_equals(copy.checked, false);
+ }, `input[type=${inputType}] element's dirty checkedness should be cloned, so setAttribute doesn't affect the cloned input's checkedness`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/color.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/color.html
new file mode 100644
index 0000000000..6164815f66
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/color.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Form input type=color</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/common-microsyntaxes.html#colors">
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/states-of-the-type-attribute.html#color-state-(type=color)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ var colors = [
+ {value: "", expected: "#000000", testname: "Empty value should return #000000"},
+ {expected: "#000000", testname: "Missing value should return #000000"},
+ {value: "#ffffff", expected: "#ffffff", testname: "Valid simple color: should return #ffffff"},
+ {value: "#FFFFFF", expected: "#ffffff", testname: "Valid simple color (containing LATIN CAPITAL LETTERS): should return #ffffff (converted to ASCII lowercase)"},
+ {value: "#0F0F0F", expected: "#0f0f0f", testname: "Zero-padding"},
+ {value: "#fff", expected: "#000000", testname: "Invalid simple color: not 7 characters long"},
+ {value: "fffffff", expected: "#000000", testname: "Invalid simple color: no starting # sign"},
+ {value: "#gggggg", expected: "#000000", testname: "Invalid simple color: non ASCII hex digits"},
+ {value: "foobar", expected: "#000000", testname: "Invalid simple color: foobar"},
+ {value: "#ffffff\u0000", expected: "#000000", testname: "Invalid color: trailing Null (U+0000)"},
+ {value: "#ffffff;", expected: "#000000", testname: "Invalid color: trailing ;"},
+ {value: " #ffffff", expected: "#000000", testname: "Invalid color: leading space"},
+ {value: "#ffffff ", expected: "#000000", testname: "Invalid color: trailing space"},
+ {value: " #ffffff ", expected: "#000000", testname: "Invalid color: leading+trailing spaces"},
+ {value: "crimson", expected: "#000000", testname: "Invalid color: keyword crimson"},
+ {value: "bisque", expected: "#000000", testname: "Invalid color: keyword bisque"},
+ {value: "currentColor", expected: "#000000", testname: "Invalid color: keyword currentColor"},
+ {value: "transparent", expected: "#000000", testname: "Invalid color: keyword transparent"},
+ {value: "ActiveBorder", expected: "#000000", testname: "Invalid color: keyword ActiveBorder"},
+ {value: "inherit", expected: "#000000", testname: "Invalid color: keyword inherit"},
+ {value: "rgb(1,1,1)", expected: "#000000", testname: "Invalid color: rgb(1,1,1)"},
+ {value: "rgb(1,1,1,1)", expected: "#000000", testname: "Invalid color: rgb(1,1,1,1)"},
+ {value: "#FFFFF\u1F4A9", expected: "#000000", testname: "Invalid color: PILE OF POO (U+1F4A9)"}
+ ];
+ for (var i = 0; i < colors.length; i++) {
+ var w = colors[i];
+ test(function() {
+ var input = document.createElement("input");
+ input.type = "color";
+ input.value = w.value;
+ assert_equals(input.value, w.expected);
+ }, w.testname);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/date.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/date.html
new file mode 100644
index 0000000000..9b95b86b16
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/date.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Inputs Date</title>
+ <link rel="author" title="Morishita Hiromitsu" href="mailto:hero@asterisk-works.jp">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#date-state-(type=date)">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dates-and-times">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>Inputs Date</h1>
+ <div style="display: none">
+ <input id="valid" type="date" value="2011-11-01" min="2011-01-01" max="2011-12-31" />
+ <input id="too_small_value" type="date" value="1999-01-31" min="2011-01-01" max="2011-12-31"/>
+ <input id="too_large_value" type="date" value="2099-01-31" min="2011-01-01" max="2011-12-31"/>
+ <input id="invalid_min" type="date" value="2011-01-01" min="1999-1" max="2011-12-31"/>
+ <input id="invalid_max" type="date" value="2011-01-01" min="2011-01-01" max="2011-13-162-777"/>
+ <input id="min_larger_than_max" type="date" value="2011-01-01" min="2099-01-01" max="2011-12-31"/>
+ <input id="invalid_value" type="date" value="invalid-date" min="2011-01-01" max="2011-12-31"/>
+ </div>
+
+ <div id="log"></div>
+
+ <script type="text/javascript">
+ test(function() {
+ assert_equals(document.getElementById("valid").type, "date")
+ }, "date type support on input element");
+
+ test(function() {
+ assert_equals(document.getElementById("valid").value, "2011-11-01");
+ assert_equals(document.getElementById("too_small_value").value, "1999-01-31");
+ assert_equals(document.getElementById("too_large_value").value, "2099-01-31");
+ }, "The value attribute, if specified and not empty, must have a value that is a valid date string.");
+
+ test(function() {
+ assert_equals(document.getElementById("valid").min, "2011-01-01");
+ assert_equals(document.getElementById("invalid_min").min, "1999-1");
+ }, "The min attribute must be reflected verbatim by the min property.");
+
+ test(function() {
+ assert_equals(document.getElementById("valid").max, "2011-12-31");
+ assert_equals(document.getElementById("min_larger_than_max").max, "2011-12-31");
+ assert_equals(document.getElementById("invalid_max").max, "2011-13-162-777");
+ }, "The max attribute must be reflected verbatim by the max property.");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_value").value, "");
+ }, "User agents must not allow the user to set the value to a non-empty string that is not a valid date string.");
+ test(function() {
+ var numDays = [
+ // the number of days in month month of year year is: 31 if month is 1, 3, 5, 7, 8, 10, or 12;
+ {value: "2014-01-31", expected: "2014-01-31", testname: "January has 31 days"},
+ {value: "2014-01-32", expected: "", testname: "January has 31 days"},
+ {value: "2014-03-31", expected: "2014-03-31", testname: "March has 31 days"},
+ {value: "2014-03-32", expected: "", testname: "March has 31 days"},
+ {value: "2014-05-31", expected: "2014-05-31", testname: "May has 31 days"},
+ {value: "2014-05-32", expected: "", testname: "May has 31 days"},
+ {value: "2014-07-31", expected: "2014-07-31", testname: "July has 31 days"},
+ {value: "2014-07-32", expected: "", testname: "July has 31 days"},
+ {value: "2014-08-31", expected: "2014-08-31", testname: "August has 31 days"},
+ {value: "2014-08-32", expected: "", testname: "August has 31 days"},
+ {value: "2014-10-31", expected: "2014-10-31", testname: "October has 31 days"},
+ {value: "2014-10-32", expected: "", testname: "October has 31 days"},
+ {value: "2014-12-31", expected: "2014-12-31", testname: "December has 31 days"},
+ {value: "2014-12-32", expected: "", testname: "December has 31 days"},
+ // the number of days in month month of year year is: 30 if month is 4, 6, 9, or 11;
+ {value: "2014-04-30", expected: "2014-04-30", testname: "April has 30 days"},
+ {value: "2014-04-31", expected: "", testname: "April has 30 days"},
+ {value: "2014-06-30", expected: "2014-06-30", testname: "June has 30 days"},
+ {value: "2014-06-31", expected: "", testname: "June has 30 days"},
+ {value: "2014-09-30", expected: "2014-09-30", testname: "September has 30 days"},
+ {value: "2014-09-31", expected: "", testname: "September has 30 days"},
+ {value: "2014-11-30", expected: "2014-11-30", testname: "November has 30 days"},
+ {value: "2014-11-31", expected: "", testname: "November has 30 days"},
+ // leap years
+ {value: "2014-02-28", expected: "2014-02-28", testname: "2014 is not a leap year: February has 28 days"},
+ {value: "2014-02-29", expected: "", testname: "2014 is not a leap year: February has 28 days: value should be empty"},
+ {value: "2016-02-29", expected: "2016-02-29", testname: "2016 is a leap year: February has 29 days"}
+ ];
+ for (var i = 0; i < numDays.length; i++) {
+ var input = document.createElement("input");
+ input.type = "date";
+ input.value = numDays[i].value;
+ assert_equals(input.value, numDays[i].expected, numDays[i].testname);
+ }
+ }, "Number of days");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local-trailing-zeros.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local-trailing-zeros.html
new file mode 100644
index 0000000000..0fb031d510
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local-trailing-zeros.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/common-microsyntaxes.html#local-dates-and-times">
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/states-of-the-type-attribute.html#local-date-and-time-state-(type=datetime-local)">
+
+<input id=input type=datetime-local value="2022-04-19T12:34:56.010">
+
+<script>
+test(() => {
+ assert_equals(input.value, '2022-04-19T12:34:56.01');
+}, 'Verifies that trailing zeros in the milliseconds portion of the date strings are removed.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local.html
new file mode 100644
index 0000000000..2fe24d7e8a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-local.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Form input type=datetime-local</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/common-microsyntaxes.html#local-dates-and-times">
+<link rel=help href="https://html.spec.whatwg.org/multipage/multipage/states-of-the-type-attribute.html#local-date-and-time-state-(type=datetime-local)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ var datetimeLocal = [
+ {value: "", expected: "", testname: "empty value"},
+ {value: "2014-01-01T11:11:11.111", expected: "2014-01-01T11:11:11.111", testname: "datetime-local input value set to 2014-01-01T11:11:11.111 without min/max"},
+ {value: "2014-01-01 11:11:11.111", expected: "2014-01-01T11:11:11.111", testname: "datetime-local input value set to 2014-01-01 11:11:11.111 without min/max"},
+ {value: "2014-01-01 11:11", expected: "2014-01-01T11:11", testname: "datetime-local input value set to 2014-01-01 11:11 without min/max"},
+ {value: "2014-01-01 00:00:00.000", expected: "2014-01-01T00:00", testname: "datetime-local input value set to 2014-01-01 00:00:00.000 without min/max"},
+ {value: "2014-01-0 11:11", expected: "", testname: "datetime-local input value set to 2014-01-0 11:11 without min/max"},
+ {value: "2014-01-01 11:1", expected: "", testname: "datetime-local input value set to 2014-01-01 11:1 without min/max"},
+ {value: "2014-01-01 11:1d1", expected: "", testname: "invalid datetime-local input value 1"},
+ {value: "2014-01-01H11:11", expected: "", testname: "invalid datetime-local input value 2"},
+ {value: "2014-01-01 11:11:", expected: "", testname: "invalid datetime-local input value 3"},
+ {value: "2014-01-01 11-11", expected: "", testname: "invalid datetime-local input value 4"},
+ {value: "2014-01-01 11:11:123", expected: "", testname: "invalid datetime-local input value 5"},
+ {value: "2014-01-01 11:11:12.1234", expected: "", testname: "invalid datetime-local input value 6"},
+ {value: "2014-01-01 11:12", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:12", testname: "Value >= min attribute"},
+ {value: "2014-01-01 11:10", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:10", testname: "Value < min attribute"},
+ {value: "2014-01-01 11:10", attributes: { max: "2014-01-01 11:11" }, expected: "2014-01-01T11:10", testname: "Value <= max attribute"},
+ {value: "2014-01-01 11:12", attributes: { max: "2014-01-01 11:11" }, expected: "2014-01-01T11:12", testname: "Value > max attribute"}
+ ];
+ for (var i = 0; i < datetimeLocal.length; i++) {
+ var w = datetimeLocal[i];
+ test(function() {
+ var input = document.createElement("input");
+ input.type = "datetime-local";
+ input.value = w.value;
+ for(var attr in w.attributes) {
+ input[attr] = w.attributes[attr];
+ }
+ assert_equals(input.value, w.expected);
+ }, w.testname);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-weekmonth.html
new file mode 100644
index 0000000000..4a7b66ddd1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime-weekmonth.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Date and Time Inputs</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+ <link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-type">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-value">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-min">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-max">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-step">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepup">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepdown">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+
+ <h1>Date and Time Inputs</h1>
+ <div style="display: none">
+ <input type="month" value="2011-01" min="2011-01" max="2011-12" step="2" />
+ <input type="week" value="2011-W40" min="2011-W20" max="2011-W50" step="2" />
+ </div>
+
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].type, "month")}, "month type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].value, "2011-01")}, "[month] The value must be a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].min, "2011-01")}, "[month] The min attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].max, "2011-12")}, "[month] The max attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].step, "2")}, "[month] The step attribute must be expressed in seconds");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[0].stepUp) == "function")}, "[month] stepUp method support on input 'month' element");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[0].stepDown) == "function")}, "[month] stepDown method support on input 'month' element");
+
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].type, "week")}, "week type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].value, "2011-W40")}, "[week] The value must be a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].min, "2011-W20")}, "[week] The min attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].max, "2011-W50")}, "[week] The max attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].step, "2")}, "[week] The step attribute must be expressed in seconds");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[1].stepUp) == "function")}, "[week] stepUp method support on input 'week' element");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[1].stepDown) == "function")}, "[week] stepDown method support on input 'week' element");
+
+ </script>
+
+ </body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime.html
new file mode 100644
index 0000000000..e762060ea7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/datetime.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Date and Time Inputs</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+ <link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-type">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-value">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-min">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-max">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-step">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepup">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepdown">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+
+ <h1>Date and Time Inputs</h1>
+ <div style="display: none">
+ <input type="date" value="2011-12-01" min="2011-12-01" max="2011-12-31" step="5" />
+ <input type="time" value= "12:00" min="11:30" max="14:00" step="600" />
+ <input type="datetime-local" value="2011-12-01T12:00" min="2011-12-01T12:00" max="2011-12-31T22:00" step="7200" />
+ </div>
+
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].type, "date")}, "date type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].value, "2011-12-01")}, "[date] The value must be a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].min, "2011-12-01")}, "[date] The min attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].max, "2011-12-31")}, "[date] The max attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].step, "5")}, "[date] The step attribute must be expressed in seconds");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[0].stepUp) == "function")}, "[date] stepUp method support on input 'date' element");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[0].stepDown) == "function")}, "[date] stepDown method support on input 'date' element");
+
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].type, "time")}, "[time] time type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].value, "12:00")}, "[time] The value must be a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].min, "11:30")}, "[time] The min attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].max, "14:00")}, "[time] The max attribute must have a value that is a valid global date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[1].step, "600")}, "[time] The step attribute must be expressed in seconds");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[1].stepUp) == "function")}, "[time] stepUp method support on input 'time' element");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[1].stepDown) == "function")}, "[time] stepDown method support on input 'time' element");
+
+ test(function() {assert_equals(document.getElementsByTagName("input")[2].type, "datetime-local")}, "datetime-local type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[2].value, "2011-12-01T12:00")}, "[datetime-local] The must be a valid local date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[2].min, "2011-12-01T12:00")}, "[datetime-local] The min attribute must have a value that is a valid local date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[2].max, "2011-12-31T22:00")}, "[datetime-local] The max attribute must have a value that is a valid local date and time string");
+ test(function() {assert_equals(document.getElementsByTagName("input")[2].step, "7200")}, "[datetime-local] The step attribute must be expressed in seconds");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[2].stepUp) == "function")}, "[datetime-local] stepUp method support on input 'datetime-local' element");
+ test(function() {assert_true(typeof(document.getElementsByTagName("input")[2].stepDown) == "function")}, "[datetime-local] stepDown method support on input 'datetime-local' element");
+
+ </script>
+
+ </body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/defaultValue-clobbering.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/defaultValue-clobbering.html
new file mode 100644
index 0000000000..41ff967c19
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/defaultValue-clobbering.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<meta name="assert" content="Assigning to defaultValue does not modify text a user has already typed in.">
+
+<!-- This behavior is not explicitly specified. -->
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<div>
+ email with leading whitespace: <input id=emailinput type=email>
+</div>
+<div>
+ number with trailing incomplete exponent: <input id=numberinput type=number>
+</div>
+
+<script>
+promise_test(async () => {
+ await test_driver.send_keys(emailinput, ' user');
+ assert_false(emailinput.validity.valid, '" user" should not be a valid value for type=email.');
+
+ emailinput.defaultValue = emailinput.value;
+ assert_false(emailinput.validity.valid, 'Assigning to defaultValue should not affect input.validity.');
+}, 'Visible value and validity should not be affected when assigning to the defaultValue property for type=email.');
+
+promise_test(async () => {
+ await test_driver.send_keys(numberinput, '123e');
+ assert_false(numberinput.validity.valid, '"123e" should not be a valid value for type=number.');
+
+ numberinput.defaultValue = numberinput.value;
+ assert_false(numberinput.validity.valid, 'Assigning to defaultValue should not affect input.validity.');
+}, 'Visible value and validity should not be affected when assigning to the defaultValue property for type=number.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/disabled-click-picker-manual.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/disabled-click-picker-manual.html
new file mode 100644
index 0000000000..b77f981e6c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/disabled-click-picker-manual.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Disabled input elements must not open pickers</title>
+<p>
+ Click the Open buttons below. If clicking them does not open any pickers, then consider this as a passing test.<br>
+ (This is manual because we don't have an event to check whether the picker is opened or not.)
+</p>
+<input disabled type="color" id="color"><button>Open</button><br>
+<input disabled type="file" id="file"><button>Open</button>
+<script>
+ for (const button of document.getElementsByTagName("button")) {
+ button.onclick = () => {
+ const input = button.previousElementSibling;
+ input.dispatchEvent(new MouseEvent("click"));
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/email-set-value.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/email-set-value.html
new file mode 100644
index 0000000000..95245fb824
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/email-set-value.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Input Email setValue</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#e-mail-state-(type=email)">
+<link rel="help" href="https://crbug.com/423785">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input type="email">
+
+<script>
+promise_test(async () => {
+ let input = document.querySelector("input");
+ let unsanitized = ' foo@bar ';
+ let sanitized = unsanitized.trim();
+ await test_driver.send_keys(input, unsanitized);
+ input.select();
+ assert_equals(input.value, sanitized, "value is sanitized");
+ assert_equals(window.getSelection().toString(), unsanitized,
+ "visible value is unsanitized");
+ input.value = sanitized;
+ input.select();
+ assert_equals(window.getSelection().toString(), sanitized,
+ "visible value is sanitized after setValue(sanitized)");
+},
+"setValue(sanitizedValue) is reflected in visible text field content");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/email.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/email.html
new file mode 100644
index 0000000000..c187d89bad
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/email.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<title>Input Email</title>
+<link rel="author" title="Kazuki Kanamori" href="mailto:yogurito@gmail.com">
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#e-mail-state-(type=email)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input type="email" id="single_email" value="user@example.com"/>
+<input type="email" id="multiple_email" value="user1@example.com, user2@test.com" multiple/>
+<div id="log"></div>
+
+<script type="text/javascript">
+ var single = document.getElementById('single_email'),
+ mult = document.getElementById('multiple_email');
+
+ test(function(){
+ assert_false(single.multiple);
+ }, "single_email doesn't have the multiple attribute");
+
+ test(function(){
+ single.value = 'user2@example.com\u000A';
+ assert_equals(single.value, 'user2@example.com');
+ single.value = 'user3@example.com\u000D';
+ assert_equals(single.value, 'user3@example.com');
+ }, 'value should be sanitized: strip line breaks');
+
+ test(function(){
+ single.value = 'user4@example.com';
+ assert_true(single.validity.valid);
+ single.value = 'example.com';
+ assert_false(single.validity.valid);
+ }, 'Email address validity');
+
+ test(function(){
+ single.setAttribute('multiple', true);
+ single.value = ' user@example.com , user2@example.com ';
+ assert_equals(single.value, 'user@example.com,user2@example.com');
+ single.removeAttribute('multiple');
+ assert_equals(single.value, 'user@example.com,user2@example.com');
+ }, 'When the multiple attribute is removed, the user agent must run the value sanitization algorithm');
+
+ test(function(){
+ assert_true(mult.multiple);
+ }, "multiple_email has the multiple attribute");
+
+ test(function(){
+ mult.value = ' user1@example.com , user2@test.com, user3@test.com ';
+ assert_equals(mult.value, 'user1@example.com,user2@test.com,user3@test.com');
+ }, "run the value sanitization algorithm after setting a new value");
+
+ test(function(){
+ mult.value = 'user1@example.com,user2@test.com,user3@test.com';
+ assert_true(mult.validity.valid);
+
+ mult.value = 'u,ser1@example.com,user2@test.com,user3@test.com';
+ assert_false(mult.validity.valid);
+ }, "valid value is a set of valid email addresses separated by a single ','");
+
+ test(function(){
+ mult.removeAttribute('multiple');
+ mult.value = 'user1@example.com , user2@example.com';
+ assert_equals(mult.value, 'user1@example.com , user2@example.com');
+ mult.setAttribute('multiple', true);
+ assert_equals(mult.value, 'user1@example.com,user2@example.com');
+ }, 'When the multiple attribute is set, the user agent must run the value sanitization algorithm');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/event-select-manual.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/event-select-manual.html
new file mode 100644
index 0000000000..ed0b21e9f3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/event-select-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTMLInputElement Test: select event</title>
+<link rel="author" title="Intel" href="www.intel.com/">
+<meta name="flags" content="interact">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-select">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<form id="testForm" name="testForm">
+ <input id="testInput" type="text" value="0123456789"/>
+</form>
+
+<h2>Description</h2>
+<p>
+ This test validates that select characters in input element should fired select event.
+</p>
+
+<h2>Test steps:</h2>
+<ol>
+ <li>
+ Select any numeric characters in the input flag below
+ </li>
+</ol>
+
+<script>
+
+let input = document.getElementById("testInput");
+
+setup({explicit_done : true, explicit_timeout : true});
+
+on_event(input, "select", evt => {
+ test(() => {
+ assert_greater_than(input.value.substring(input.selectionStart, input.selectionEnd).length, 0, "Check if the select event captured when text selected");
+ });
+ done();
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/file-manual.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/file-manual.html
new file mode 100644
index 0000000000..9e2d47c423
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/file-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type file</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<p>Manual test: clicking on the input should open a prompt allowing you to select a file.</p>
+<input type=file id=file>
+<script>
+ setup({explicit_timeout:true});
+
+ var input = document.getElementById('file'),
+ t1 = async_test("selecting files should fire the input event at the input element"),
+ t2 = async_test("selecting files should fire the change event at the input element");
+
+ document.getElementById('file').oninput = t1.step_func_done(function(e) {
+ assert_true(e.bubbles, "input event bubbles");
+ assert_true(e.isTrusted, "input event should be trusted");
+ assert_false(e.cancelable, "input event should not be cancelable");
+ })
+ document.getElementById('file').onchange = t2.step_func_done(function(e) {
+ assert_true(e.bubbles, "change event bubbles");
+ assert_true(e.isTrusted, "change event should be trusted");
+ assert_false(e.cancelable, "change event should not be cancelable");
+ assert_true(input.files instanceof FileList);
+ assert_equals(input.value, "C:\\fakepath\\" + input.files[0].name);
+ })
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/files.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/files.html
new file mode 100644
index 0000000000..43ebd71906
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/files.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLInputElement#files</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+var types = [
+ "hidden",
+ "text",
+ "search",
+ "tel",
+ "url",
+ "email",
+ "password",
+ "date",
+ "month",
+ "week",
+ "time",
+ "datetime-local",
+ "number",
+ "range",
+ "color",
+ "checkbox",
+ "radio",
+ "submit",
+ "image",
+ "reset",
+ "button",
+];
+
+types.forEach(function(type) {
+ test(function() {
+ const input = document.createElement("input"),
+ input2 = document.createElement("input");
+ input.type = type;
+ input2.type = "file";
+ assert_equals(input.files, null, "files should be null");
+
+ input.files = input2.files;
+ assert_equals(input.files, null, "files should remain null as it cannot be set when it does not apply");
+ }, "files for input type=" + type);
+});
+
+test(function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ assert_not_equals(input.files, null);
+ assert_true(input.files instanceof FileList, "files should be a FileList");
+ var files = input.files;
+ assert_equals(input.files, files, "files should return the same object");
+}, "files for input type=file");
+
+test(() => {
+ const i1 = document.createElement("input"),
+ i2 = document.createElement("input");
+ i1.type = "file";
+ i2.type = "file";
+
+ const files = i2.files;
+ i1.files = i2.files;
+ assert_equals(i1.files, files, "FileList should not be copied");
+ assert_equals(i2.files, files, "FileList can be shared across input elements");
+
+ i1.files = null;
+ assert_equals(i1.files, files, "files cannot be set to null");
+
+ assert_throws_js(TypeError, () => i1.files = [], "files cannot be set to an array");
+ assert_throws_js(TypeError, () => i1.files = [new File([], "x")], "files cannot be set to an array (even when it contains File objects)");
+}, "setting <input type=file>.files");
+
+test(() => {
+ const i = document.createElement("input");
+ i.type = "file";
+
+ let dt = new DataTransfer();
+
+ const files = dt.files;
+ i.files = files;
+ assert_equals(i.files, files, "FileList should not be copied");
+ assert_equals(dt.files, files, "FileList can be shared across input / DataTransfer");
+}, "setting <input type=file>.files from DataTransfer");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change-on-blur.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change-on-blur.html
new file mode 100644
index 0000000000..23292d3a83
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change-on-blur.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Input type switch on blur event should clean up properly</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script type=module>
+import inputTypes from "./input-types.js";
+
+function tick() {
+ return new Promise(resolve => {
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+}
+
+function test_from_to(fromType, toType, capture) {
+ if (fromType == toType) {
+ return;
+ }
+ promise_test(async function(t) {
+ const input = document.createElement("input");
+ input.type = fromType;
+ document.body.appendChild(input);
+ input.focus();
+ assert_equals(document.activeElement, input, `${fromType} input should be focused`);
+ function onFocus() {
+ t.assert_unreached("shouldn't be getting spurious focus events");
+ }
+ function onBlur() {
+ input.type = toType;
+ }
+ input.addEventListener("focus", onFocus);
+ input.addEventListener("blur", onBlur, capture);
+ await tick();
+
+ assert_equals(document.activeElement, input, `${fromType} input should still be focused after tick`);
+ assert_true(input.matches(":focus"), `${fromType} input should match :focus`);
+ assert_true(input.matches(":focus-visible"), `${fromType} input should match :focus-visible`);
+
+ input.blur();
+
+ assert_equals(document.activeElement, document.body, `${fromType} input should not remain focused after blur`);
+ assert_false(input.matches(":focus"), `${fromType} input should not match :focus`);
+ assert_false(input.matches(":focus-visible"), `${fromType} input should not match :focus-visible`);
+ assert_equals(input.type, toType, `${fromType} input should have changed to ${toType}`);
+ input.removeEventListener("focus", onFocus);
+ input.removeEventListener("blur", onBlur);
+ }, `${fromType} -> ${toType} ${capture}`);
+}
+
+for (let type of inputTypes) {
+ if (type == "hidden") {
+ continue; // hidden inputs are not focusable
+ }
+ for (let capture of [true, false]) {
+ test_from_to(type, "text", capture);
+ test_from_to("text", type, capture);
+ }
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change.html
new file mode 100644
index 0000000000..982cda6c92
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/focus-dynamic-type-change.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Input type switch on focused input shouldn't blur</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script type=module>
+import inputTypes from "./input-types.js";
+
+function tick() {
+ return new Promise(resolve => {
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+}
+
+function test_from_to(fromType, toType) {
+ if (fromType == toType) {
+ return;
+ }
+ promise_test(async function(t) {
+ const input = document.createElement("input");
+ input.type = fromType;
+ document.body.appendChild(input);
+ input.focus();
+ assert_equals(document.activeElement, input, `${fromType} input should be focused`);
+ function onFocus() {
+ t.assert_unreached("shouldn't be getting spurious focus events");
+ }
+ function onBlur() {
+ t.assert_unreached("shouldn't be getting spurious blur events");
+ }
+ input.addEventListener("focus", onFocus);
+ input.addEventListener("blur", onBlur);
+ input.type = toType;
+ assert_equals(document.activeElement, input, `${fromType} input should be focused after change to ${toType}`);
+ assert_true(input.matches(":focus"), `${fromType} input should still match :focus`);
+ assert_true(input.matches(":focus-visible"), `${fromType} input should still match :focus-visible`);
+ await tick();
+ assert_equals(document.activeElement, input, `${fromType} input should still be focused after change to ${toType}`);
+ assert_true(input.matches(":focus"), `${fromType} input should still match :focus`);
+ assert_true(input.matches(":focus-visible"), `${fromType} input should still match :focus-visible`);
+ input.removeEventListener("focus", onFocus);
+ input.removeEventListener("blur", onBlur);
+ }, `${fromType} -> ${toType}`);
+}
+
+for (let type of inputTypes) {
+ if (type == "hidden") {
+ continue; // hidden inputs are not focusable
+ }
+ test_from_to(type, "text");
+ test_from_to("text", type);
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive-child.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive-child.html
new file mode 100644
index 0000000000..92c9981a11
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive-child.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+parent.postMessage(location.href, "*");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive.html
new file mode 100644
index 0000000000..537500c91f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden-charset-case-sensitive.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="help" href="https://html.spec.whatwg.org/#hidden-state-(type=hidden):attr-fe-name-charset">
+<meta name="assert" content="special input@name value “_charset_” is case-sensitive">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<form target="child" method="GET" action="hidden-charset-case-sensitive-child.html">
+ <input type="hidden" name="_charset_">
+ <input type="hidden" name="_CHARSET_">
+ <input type="hidden" name="_ChArSeT_">
+ <input type="hidden" name="_charſet_">
+</form>
+<iframe name="child"></iframe>
+<script>
+// #attr-fe-name-charset only affects form submission, so we need to do that
+async_test(function() {
+ // we use a message rather than the iframe’s load event to avoid dealing with
+ // spurious load events that some browsers dispatch on the initial about:blank
+ addEventListener("message", this.step_func_done(event => {
+ const params = new URL(event.data).searchParams;
+
+ assert_equals(params.get("_charset_"), "UTF-8", "lowercase valid");
+ assert_equals(params.get("_CHARSET_"), "UTF-8", "uppercase valid");
+ assert_equals(params.get("_ChArSeT_"), "UTF-8", "mixed case invalid");
+ assert_equals(params.get("_charſet_"), "", "non-ASCII invalid");
+ }));
+
+ document.querySelector("form").submit();
+}, "keyword _charset_");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden.html
new file mode 100644
index 0000000000..9274b5cddb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/hidden.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Hidden input element</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#hidden-state-(type=hidden)">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Hidden input element</h1>
+ <div style="display: none">
+
+ <input id="hidden" type="hidden" />
+ <input id="hidden_with_value" type="hidden" value="foo" />
+
+ </div>
+ <div id="log"></div>
+ <script type="text/javascript">
+
+ test(
+ function() {
+ assert_equals(document.getElementById("hidden").value, "");
+ assert_equals(document.getElementById("hidden_with_value").value, "foo");
+ }, "Value returns the current value for hidden");
+
+ test(
+ function() {
+ document.getElementById("hidden").value = "A";
+ assert_equals(document.getElementById("hidden").value, "A");
+ document.getElementById("hidden").value = "B";
+ assert_equals(document.getElementById("hidden").value, "B");
+ }, "Setting value changes the current value for hidden");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("hidden").files, null);
+ }, "files attribute must return null for hidden");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("hidden").valueAsDate, null);
+ }, "valueAsDate attribute must return null for hidden");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("hidden").valueAsNumber, NaN);
+ }, "valueAsNumber attribute must return NaN for hidden");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("hidden").list, null);
+ }, "list attribute must return null for hidden");
+
+ test(
+ function() {
+ var el = document.getElementById("hidden");
+ assert_throws_dom("InvalidStateError", function() { el.stepDown(); }, "");
+ }, "stepDown does not apply for hidden");
+
+ test(
+ function() {
+ var el = document.getElementById("hidden");
+ assert_throws_dom("InvalidStateError", function() { el.stepUp(); }, "");
+ }, "stepUp does not apply for hidden");
+
+ test(function(){
+ var el = document.getElementById("hidden");
+ assert_false(el.willValidate);
+ }, "input type=hidden is barred from constraint validation");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/image-click-form-data.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/image-click-form-data.html
new file mode 100644
index 0000000000..87b77e4805
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/image-click-form-data.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Check form-data for image submit button with non-empty 'value' attribute</title>
+<link rel="author" title="Shanmuga Pandi" href="mailto:shanmuga.m@samsung.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-form-data-set">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+// promise_test instead of async_test because this test use window.success, and so can't run at the same time.
+
+promise_test(t => {
+ return new Promise(resolve => {
+ window.success = t.step_func(locationLoaded => {
+ const expected = (new URL("resources/image-submit-click.html?name.x=0&name.y=0", location.href)).href;
+ assert_equals(locationLoaded, expected);
+ resolve();
+ });
+
+ const iframe = document.createElement("iframe");
+ iframe.src = "resources/image-submit-click.html";
+ document.body.appendChild(iframe);
+ });
+}, "Image submit button should not add extra form data if 'value' attribute is present with non-empty value");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/image01-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/image01-ref.html
new file mode 100644
index 0000000000..62c141d960
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/image01-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type image reference file</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<img src="/media/poster.png"/>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/image01.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/image01.html
new file mode 100644
index 0000000000..e9028dceec
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/image01.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type image</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#image-button-state-(type=image)">
+<link rel="match" href="image01-ref.html">
+<input type=image id=image src="/media/poster.png">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-checkvalidity.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-checkvalidity.html
new file mode 100644
index 0000000000..b336204fcc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-checkvalidity.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_checkValidity</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ id="input_form">
+ <p><input type='hidden' id='input_text'></p>
+ </form>
+ <script>
+
+ var input = document.getElementById("input_text");
+
+ try
+ {
+ var ret = input.checkValidity();
+
+ test(function() {
+ assert_equals(ret, true, "calling of checkValidity method is failed.");
+ });
+ }
+ catch (e) {
+ test(function() {
+ assert_unreached("Error is raised.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-disabled-fieldset-dynamic.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-disabled-fieldset-dynamic.html
new file mode 100644
index 0000000000..eefcd972bf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-disabled-fieldset-dynamic.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1861027">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<fieldset id="fieldset" disabled>
+ <input id="target">
+</fieldset>
+<script>
+const target = document.getElementById("target");
+const fieldset = document.getElementById("fieldset");
+promise_test(async function() {
+ await new Promise(r => window.addEventListener("load", r, { once: true }));
+ assert_true(target.matches(":disabled"), "Fieldset disables the input");
+ assert_true(target.matches(":read-only"), "Disabled implies read-only");
+
+ // Try to focus, it shouldn't be focusable.
+ target.focus();
+
+ assert_not_equals(document.activeElement, target, "Should not be focusable");
+
+ fieldset.removeAttribute("disabled");
+
+ assert_false(target.matches(":disabled"), "Should go back to writable");
+ assert_false(target.matches(":read-only"), "No longer read-only");
+
+ // Should be focusable now.
+ target.focus();
+
+ assert_equals(document.activeElement, target, "Should not be focusable");
+
+ await test_driver.send_keys(target, "A");
+ assert_equals(target.value, "A", "Typing should work");
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-form-detach-style-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-form-detach-style-crash.html
new file mode 100644
index 0000000000..5472563763
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-form-detach-style-crash.html
@@ -0,0 +1,17 @@
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1800543">
+<script>
+document.addEventListener('DOMContentLoaded', () => {
+ b.setCustomValidity("x")
+ a.reportValidity()
+ c.appendChild(a)
+ document.adoptNode(d)
+ document.documentElement.style.display = 'none'
+})
+</script>
+<form id="a">
+<textarea id="b">a</textarea>
+</form>
+<dl id="d">
+<canvas id="c"></canvas>
+</dl>
+<input form="a">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-height.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-height.html
new file mode 100644
index 0000000000..dea4f41765
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-height.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_height</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='image' id='input_text'></p>
+ </form>
+
+ <script>
+
+ var input_text = document.getElementById("input_text");
+ input_text.height = 30;
+
+ if (typeof(input_text.height) == "number") {
+ test(function() {
+ assert_equals(input_text.height, 30, "formTarget attribute is not correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("height attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-importNode-to-detached-document-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-importNode-to-detached-document-crash.html
new file mode 100644
index 0000000000..5e0cff4fa3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-importNode-to-detached-document-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<body>
+<p>This test passes if it does not crash.</p>
+<input id="input" type="image" src="data:image/gif;base64,">
+<iframe id="iframe"></iframe>
+<script>
+let i_doc = iframe.contentDocument;
+iframe.remove();
+i_doc.importNode(input);
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-labels.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-labels.html
new file mode 100644
index 0000000000..77f4d8b31a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-labels.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_labels</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ id="input_form">
+ <p><label>Full name:<label>(name)<input name=fn id='input_text1'> <small>Format: First Last</small></label></label></p>
+ <p><label>Age: <input name=age type=number min=0 id='input_text2'></label></p>
+ <p><label>Post code: <input name=pc> <small>Format: AB12 3CD</small></label></p>
+ </form>
+ <script>
+
+ var input1 = document.getElementById("input_text1");
+ var input2 = document.getElementById("input_text2");
+
+ if (typeof(input1.labels) == "object") {
+ if (input1.labels.length == 2 && input2.labels.length == 1) {
+ test(function() {
+ assert_true(true, "labels attribute is correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("labels attribute is not correct.");
+ });
+ }
+ } else {
+ test(function() {
+ assert_unreached("labels attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-list.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-list.html
new file mode 100644
index 0000000000..006a8fbd8f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-list.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>input list attribute</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_list</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <datalist id="thelist">
+ <option value="one">one</option>
+ <option value="two">two</option>
+ </datalist>
+
+ <p id="non_datalist_first">
+ <datalist id="non_datalist_first">
+ <option value="one">one</option>
+ <option value="two">two</option>
+ </datalist>
+
+ <datalist id="datalist_first">
+ <option value="one">one</option>
+ <option value="two">two</option>
+ </datalist>
+ <p id="datalist_first">
+
+ <p><input list="thelist" id='input_with_list'></p>
+ <p><input id='input_without_list'></p>
+ <p><input list="input_with_list" id='input_with_nondatalist_list'></p>
+ <p><input list="not_an_id" id='input_with_missing_list'></p>
+ <p><input list="non_datalist_first" id='input_with_non_datalist_first'></p>
+ <p><input list="datalist_first" id='input_with_datalist_first'></p>
+ </form>
+
+ <script>
+ test(function() {
+ assert_equals(document.getElementById("input_with_list").list, document.getElementById("thelist"));
+ }, "getting .list of input must return the datalist with that id");
+ test(function() {
+ assert_equals(document.getElementById("input_without_list").list, null);
+ }, "getting .list of input must return null if it has no list attribute");
+ test(function() {
+ assert_equals(document.getElementById("input_with_nondatalist_list").list, null);
+ }, "getting .list of input must return null if the list attribute is a non-datalist's id");
+ test(function() {
+ assert_equals(document.getElementById("input_with_missing_list").list, null);
+ }, "getting .list of input must return null if the list attribute is no element's id");
+ test(function() {
+ assert_equals(document.getElementById("input_with_non_datalist_first").list, null);
+ }, "getting .list of input must return null if the list attribute is used in a non-datalist earlier than a datalist");
+ test(function() {
+ assert_equals(document.getElementById("input_with_datalist_first").list, document.querySelector("datalist#datalist_first"));
+ }, "getting .list of input must return the datalist with that id even if a later non-datalist also has the id");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-seconds-leading-zeroes.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-seconds-leading-zeroes.html
new file mode 100644
index 0000000000..d94bee1029
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-seconds-leading-zeroes.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<html>
+ <head>
+ <title>HTMLInputElement leading zeroes in seconds/millis</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h3>input times and datetimes with leading zeroes in seconds/millis</h3>
+ <!-- This test ensures that seconds and milliseconds are being
+ output with the appropriate field widths when sanitizing
+ datetime-locals and times, e.g. that we don't see "12:30:1".
+ The spec is not specific about how much precision to use
+ in a sanitized time string, but an invalid string would
+ fail at .valueAsNumber -->
+ <hr>
+ <div id="log"></div>
+
+ <input id="inp">
+ <script>
+ var inp=document.getElementById("inp");
+ var cases = [
+ ["datetime-local", "2000-01-01T12:30:01", 946729801000],
+ ["datetime-local", "2000-01-01T12:30:00.5", 946729800500],
+ ["datetime-local", "2000-01-01T12:30:00.04", 946729800040],
+ ["datetime-local", "2000-01-01T12:30:00.003", 946729800003],
+
+ ["time", "12:30:01", 45001000],
+ ["time", "12:30:00.5", 45000500],
+ ["time", "12:30:00.04", 45000040],
+ ["time", "12:30:00.003", 45000003],
+ ];
+
+ for (var i in cases) {
+ var c = cases[i];
+ test(function() {
+ inp.setAttribute("type", c[0]);
+ inp.value = c[1];
+ assert_equals(inp.valueAsNumber, c[2]);
+ },"Expected valueAsNumber=" +c[2] + " from " + c[1]);
+ if (c[0] == "datetime-local") {
+ test(function() {
+ inp.setAttribute("type", c[0]);
+ inp.value = c[1];
+ assert_in_array(inp.value, [c[1], c[1].replace("T", " ")]);
+ },"Expected digits unchanged in round-trip of " + c[1])
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-setcustomvalidity.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-setcustomvalidity.html
new file mode 100644
index 0000000000..accb24d8f9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-setcustomvalidity.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<title>input setCustomValidity</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<input id='input_test'>
+
+<script>
+
+test(() => {
+ let elem = document.getElementById("input_test");
+ assert_false(elem.validity.customError);
+ elem.setCustomValidity("custom error");
+ assert_true(elem.validity.customError);
+}, "input setCustomValidity is correct")
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-weekmonth.html
new file mode 100644
index 0000000000..c50f67fce5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown-weekmonth.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<title>Forms</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<h3>input_stepDown</h3>
+<input type="month" id="month_input" min="2011-02" step="1" value="2010-02">
+<input type="week" id="week_input" min="2011-W02" step="1" value="2010-W02">
+
+<script>
+ function testStepDownOverflow(id, value, type) {
+ test(function() {
+ var input = document.getElementById(id);
+ input.stepDown();
+ assert_equals(input.value, value, "value shouldn't change.");
+ }, "Calling stepDown() on input - " + type + " - where value < min should not modify value.");
+ }
+
+ testStepDownOverflow("month_input", "2010-02", "month");
+ testStepDownOverflow("week_input", "2010-W02", "week");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown.html
new file mode 100644
index 0000000000..3cd246f015
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepdown.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<title>Forms</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<h3>input_stepDown</h3>
+<input type='number' id='input_number'>
+<input type="number" id="number_input" min="300" step="1" value="200">
+<input type="date" id="date_input" min="2011-02-10" step="1" value="2010-02-10">
+<input type="datetime-local" id="dtl_input" min="2011-02-10T20:13" step="1" value="2010-02-10T20:13">
+<input type="time" id="time_input" min="21:13" step="60" value="20:13">
+
+<script>
+ var input_number = document.getElementById("input_number");
+ input_number.max = "30";
+ input_number.step = "3";
+ input_number.value = "30";
+ input_number.stepDown(5);
+
+ if (typeof(input_number.stepDown) == "function") {
+ test(function() {
+ assert_equals(input_number.value, "15", "call of stepDown method is failed.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("stepDown attribute is not exist.");
+ });
+ }
+
+ function testStepDownOverflow(id, value, type) {
+ test(function() {
+ var input = document.getElementById(id);
+ input.stepDown();
+ assert_equals(input.value, value, "value shouldn't change.");
+ }, "Calling stepDown() on input - " + type + " - where value < min should not modify value.");
+ }
+
+ testStepDownOverflow("number_input", "200", "number");
+ testStepDownOverflow("date_input", "2010-02-10", "date");
+ testStepDownOverflow("dtl_input", "2010-02-10T20:13", "datetime-local");
+ testStepDownOverflow("time_input", "20:13", "time");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup-weekmonth.html
new file mode 100644
index 0000000000..09316b0854
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup-weekmonth.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<title>Forms</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<h3>input_stepUp</h3>
+<input type="month" id="month_input" max="2009-02" step="1" value="2010-02">
+<input type="week" id="week_input" max="2009-W02" step="1" value="2010-W02">
+
+<script>
+ function testStepUpOverflow(id, value, type) {
+ test(function() {
+ var input = document.getElementById(id);
+ input.stepUp();
+ assert_equals(input.value, value, "value shouldn't change.");
+ }, "Calling stepUp() on input -" + type + "- where value > max should not modify value.");
+ }
+
+ testStepUpOverflow("month_input", "2010-02", "month");
+ testStepUpOverflow("week_input", "2010-W02", "week");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup.html
new file mode 100644
index 0000000000..f6f97eecbe
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-stepup.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<title>Forms</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<h3>input_stepUp</h3>
+<input type='number' id='input_number'> <br/>
+<input type="number" id="number_input" max="100" step="1" value="200">
+<input type="date" id="date_input" max="2009-02-10" step="1" value="2010-02-10">
+<input type="datetime-local" id="dtl_input" max="2009-02-10T20:13" step="1" value="2010-02-10T20:13">
+<input type="time" id="time_input" max="19:13" step="60" value="20:13">
+
+<script>
+
+ var input_number = document.getElementById("input_number");
+ input_number.max = "30";
+ input_number.step = "3";
+ input_number.value = "0";
+ input_number.stepUp(5);
+
+ if (typeof(input_number.stepUp) == "function") {
+ test(function() {
+ assert_equals(input_number.value, "15", "call of stepUp method is failed.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("stepUp attribute is not exist.");
+ });
+ }
+
+ function testStepUpOverflow(id, value, type) {
+ test(function() {
+ var input = document.getElementById(id);
+ input.stepUp();
+ assert_equals(input.value, value, "value shouldn't change.");
+ }, "Calling stepUp() on input -" + type + "- where value > max should not modify value.");
+ }
+
+ testStepUpOverflow("number_input", "200", "number");
+ testStepUpOverflow("date_input", "2010-02-10", "date");
+ testStepUpOverflow("dtl_input", "2010-02-10T20:13", "datetime-local");
+ testStepUpOverflow("time_input", "20:13", "time");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-submit-remove-jssubmit.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-submit-remove-jssubmit.html
new file mode 100644
index 0000000000..f992ff9ed5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-submit-remove-jssubmit.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-2">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe name="frame" id="frame"></iframe>
+<form id="form" target="frame" action="does_not_exist.html">
+ <input id="input" name="name" value="foo">
+ <input id="submitbutton" type="submit"></input>
+</form>
+
+<script>
+async_test(t => {
+ window.addEventListener('load', () => {
+ const frame = document.getElementById('frame');
+ frame.addEventListener('load', t.step_func_done(() => {
+ const expected = (new URL("does_not_exist.html?name=bar", location.href)).href;
+ assert_equals(frame.contentWindow.location.href, expected);
+ }));
+
+ const form = document.getElementById('form');
+ const input = document.getElementById('input');
+ const submitButton = document.getElementById('submitbutton');
+ submitButton.addEventListener('click', event => {
+ submitButton.remove();
+ form.submit();
+ input.value = "bar";
+ form.submit();
+ input.value = "baz";
+ });
+
+ submitButton.click();
+ });
+}, 'This test will pass if a form navigation successfully occurs when clicking a <input type=submit> element with a onclick event handler which removes the input and then calls form.submit().');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-button.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-button.html
new file mode 100644
index 0000000000..0f269355a5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-button.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<head>
+<title>input type button</title>
+<link rel="author" title="Takeharu.Oshida" href="mailto:georgeosddev@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#button-state-(type=button)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<div id="hide" style="display">
+ <input type="button"/>
+ <input type="button" value="BUTTON"/>
+ <form action="/" method="get" onsubmit="isSubmitted = true;return false;">
+ <input type="button" value="mutable"/>
+ </form>
+ <form action="/" method="get" onsubmit="isSubmitted = true;return false;">
+ <input type="button" value="immutable" disabled/>
+ </form>
+</div>
+<script>
+var isSubmitted = false;
+var buttons = document.getElementsByTagName("input");
+
+test(function() {
+ assert_equals(buttons[0].click(), undefined, "The input element represents a button with no default behavior");
+},"default behavior");
+
+test(function() {
+ assert_equals(buttons[0].value, "", "It must be the empty string");
+},"empty value attribute");
+
+test(function() {
+ document.getElementById("hide").style.display = "block";
+ assert_not_equals(buttons[0].offsetWidth, buttons[1].offsetWidth, "If the element has a value attribute, the button's label must be the value of that attribute");
+ document.getElementById("hide").style.display = "none";
+},"label value");
+
+test(function() {
+ isSubmitted = false;
+ buttons[2].click();
+ assert_equals(isSubmitted, false, "If the element is mutable, the element's activation behavior is to do nothing.");
+},"mutable element's activation behavior is to do nothing.");
+
+test(function() {
+ isSubmitted = false;
+ buttons[3].click()
+ assert_equals(isSubmitted, false, "If the element is immutable, the element has no activation behavior.");
+},"immutable element has no activation behavior.");
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-empty-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-empty-crash.html
new file mode 100644
index 0000000000..6e44250ccb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-empty-crash.html
@@ -0,0 +1,8 @@
+<script>
+document.addEventListener('DOMContentLoaded', () => {
+ a.type = "foo"
+ document.execCommand("insertHorizontalRule", false)
+ a.type = "text"
+})
+</script>
+<input id="a" type="color">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-value.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-value.html
new file mode 100644
index 0000000000..74aeef7cd5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-change-value.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Input type switch from / to color</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://html.spec.whatwg.org/#input-type-change">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1833477">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+function runTest(focus) {
+ let input = document.createElement("input");
+ input.type = "color";
+ document.body.appendChild(input);
+ if (focus) {
+ input.focus();
+ }
+ assert_equals(input.value, "#000000", "Invalid color should return a non-empty sanitized value");
+ input.type = "text";
+ assert_equals(input.value, "", "Value dirty flag should remain false");
+ input.type = "color";
+ input.value = "#ffffff";
+ assert_equals(input.value, "#ffffff", "Valid color is returned");
+ input.type = "text";
+ assert_equals(input.value, "#ffffff", "Value dirty flag should remain true");
+ if (focus) {
+ assert_equals(document.activeElement, input, "Focus is preserved");
+ }
+}
+test(() => runTest(false), "Without focus");
+test(() => runTest(true), "With focus");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox-switch.tentative.window.js b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox-switch.tentative.window.js
new file mode 100644
index 0000000000..6128a62a0f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox-switch.tentative.window.js
@@ -0,0 +1,19 @@
+test(t => {
+ const input = document.createElement("input");
+ input.switch = true;
+
+ assert_true(input.hasAttribute("switch"));
+ assert_equals(input.getAttribute("switch"), "");
+ assert_equals(input.type, "text");
+}, "switch IDL attribute, setter");
+
+test(t => {
+ const container = document.createElement("div");
+ container.innerHTML = "<input type=checkbox switch>";
+ const input = container.firstChild;
+
+ assert_true(input.hasAttribute("switch"));
+ assert_equals(input.getAttribute("switch"), "");
+ assert_equals(input.type, "checkbox");
+ assert_true(input.switch);
+}, "switch IDL attribute, getter");
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox.html
new file mode 100644
index 0000000000..7dd2f26b12
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-checkbox.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<head>
+<title>input type checkbox</title>
+<link rel="author" title="Gary Gao" href="mailto:angrytoast@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#checkbox-state-(type=checkbox)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div style="display:none;">
+ <input id="checkbox_default" type="checkbox" width="20" />
+
+ <input id="checkbox_checked" type="checkbox" checked />
+
+ <input id="checkbox_indeterminate" type="checkbox" />
+
+ <input id="checkbox_default_value" type="checkbox" />
+</div>
+
+<div id="log"></div>
+
+<script>
+ var checkbox_default = document.getElementById('checkbox_default'),
+ checkbox_checked = document.getElementById('checkbox_checked'),
+ checkbox_indeterminate = document.getElementById('checkbox_indeterminate'),
+ checkbox_default_value = document.getElementById('checkbox_default_value');
+
+ test(function() {
+ assert_false(checkbox_default.checked);
+ }, "default checkbox has no checkedness state");
+
+ test(function() {
+ assert_true(checkbox_checked.checked);
+ }, "checkbox with initial state set to checked has checkedness state");
+
+ test(function() {
+ checkbox_default.checked = 'chicken'
+ assert_true(checkbox_default.checked);
+ }, "changing the checked attribute to a string sets the checkedness state");
+
+ test(function() {
+ assert_false(checkbox_indeterminate.indeterminate);
+ }, "a checkbox has an indeterminate state set to false onload");
+
+ test(function() {
+ checkbox_indeterminate.indeterminate = true,
+ assert_true(checkbox_indeterminate.indeterminate);
+ }, "on setting, a checkbox's indeterminate state must be set to the new value and returns the last value it was set to");
+
+ test(function() {
+ assert_equals(checkbox_default_value.value, 'on');
+ }, "default/on: on getting, if the element has a value attribute, it must return that attribute's value; otherwise, it must return the string 'on'");
+
+ test(function() {
+ checkbox_default_value.value = 'chicken'
+ assert_equals(checkbox_default_value.value, 'chicken');
+ }, "on getting, if the element has a value attribute, it must return that attribute's value");
+</script>
+
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-number-rtl-invalid-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-number-rtl-invalid-crash.html
new file mode 100644
index 0000000000..d749d1faad
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-type-number-rtl-invalid-crash.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1835437">
+<script>
+window.onload = () => {
+ a.stepDown(251)
+ document.execCommand("delete", false, null)
+}
+</script>
+<form lang="ar-SA">
+<input id="a" type="number" autofocus dir="auto">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-types.js b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-types.js
new file mode 100644
index 0000000000..4456751052
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-types.js
@@ -0,0 +1,24 @@
+export default [
+ "button",
+ "checkbox",
+ "color",
+ "date",
+ "datetime-local",
+ "email",
+ "file",
+ "hidden",
+ "image",
+ "month",
+ "number",
+ "password",
+ "radio",
+ "range",
+ "reset",
+ "search",
+ "submit",
+ "tel",
+ "text",
+ "time",
+ "url",
+ "week",
+];
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-untrusted-key-event.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-untrusted-key-event.html
new file mode 100644
index 0000000000..eb96b6fd95
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-untrusted-key-event.html
@@ -0,0 +1,225 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Forms</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<form id="input_form">
+ <fieldset>
+ <input type="radio" name="radio" value="1">
+ <input type="radio" name="radio" value="2">
+ </fieldset>
+</form>
+<script type="module">
+import inputTypes from "./input-types.js";
+
+const form = document.querySelector("form");
+form.addEventListener("submit", (e) => {
+ e.preventDefault();
+ assert_true(false, 'form should not be submitted');
+});
+
+const radioButton = document.querySelector("input[type=radio]");
+radioButton.addEventListener("click", function(e) {
+ assert_true(false, `input radio should not be clicked`);
+});
+radioButton.addEventListener("focus", function(e) {
+ assert_true(false, `input radio should not be focused on`);
+});
+radioButton.addEventListener("change", function(e) {
+ assert_true(false, `input radio should not be changed`);
+});
+radioButton.addEventListener("input", function(e) {
+ assert_true(false, `input radio should not have been inputted`);
+});
+
+// Create and append input elements
+for (const inputType of inputTypes) {
+ if (inputType == "radio") {
+ continue;
+ }
+
+ let input = document.createElement("input");
+ input.type = inputType;
+ form.appendChild(input);
+
+ input.addEventListener("click", function(e) {
+ assert_true(false, `input ${inputType} should not be clicked`);
+ });
+ input.addEventListener("focus", function(e) {
+ assert_true(false, `input ${inputType} should not be focused on`);
+ });
+ input.addEventListener("change", function(e) {
+ assert_true(false, `input ${inputType} should not be changed`);
+ });
+ input.addEventListener("input", function(e) {
+ assert_true(false, `input ${inputType} should not have been inputted`);
+ });
+}
+
+// Start tests
+for (const inputType of inputTypes) {
+ let input = document.querySelector(`input[type=${inputType}]`);
+
+ test(() => {
+ // keyCode: Enter
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ keyCode: 13,
+ })
+ );
+
+ // key: Enter
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ key: "Enter",
+ })
+ );
+
+ // keyCode: Space
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ keyCode: 32,
+ })
+ );
+
+ // key: Space
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ key: " ",
+ })
+ );
+
+ // keyCode: Tab
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ keyCode: 9,
+ })
+ );
+
+ // key: Tab
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ key: "Tab",
+ })
+ );
+
+ // keyCode: ArrowUp
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ keyCode: 38,
+ })
+ );
+
+ // key: ArrowUp
+ input.dispatchEvent(
+ new KeyboardEvent("keypress", {
+ key: "ArrowUp",
+ })
+ );
+ }, `Dispatching untrusted keypress events to input ${inputType} should not cause submission, click, change, input, or focus events`);
+
+ test(() => {
+ // keyCode: Enter
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ keyCode: 13,
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ keyCode: 13,
+ })
+ );
+
+ // key: Enter
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ key: "Enter",
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ key: "Enter",
+ })
+ );
+
+ // keyCode: Space
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ keyCode: 32,
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ keyCode: 32,
+ })
+ );
+
+ // key: Space
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ key: " ",
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ key: " ",
+ })
+ );
+
+ // keyCode: Tab
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ keyCode: 9,
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ keyCode: 9,
+ })
+ );
+
+ // key: Tab
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ key: "Tab",
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ key: "Tab",
+ })
+ );
+
+ // keyCode: ArrowUp
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ keyCode: 38,
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ keyCode: 38,
+ })
+ );
+
+ // key: ArrowUp
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", {
+ key: "ArrowUp",
+ })
+ );
+ input.dispatchEvent(
+ new KeyboardEvent("keyup", {
+ key: "ArrowUp",
+ })
+ );
+ }, `Dispatching untrusted keyup/keydown events to input ${inputType} should not cause submission, click, change, input, or focus events`);
+}
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validationmessage.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validationmessage.html
new file mode 100644
index 0000000000..775c06f06e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validationmessage.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_validationMessage</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ id="input_form">
+ <p><input type='hidden' id='input_text'></p>
+ </form>
+ <script>
+
+ var input = document.getElementById("input_text");
+
+ if (typeof(input.validationMessage) == "string") {
+ test(function() {
+ assert_equals(input.validationMessage, "", "validationMessage attribute is not correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("validationMessage attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validity.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validity.html
new file mode 100644
index 0000000000..719144d511
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-validity.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_validity</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ id="input_form">
+ <p><input type='hidden' id='input_text'></p>
+ </form>
+ <script>
+
+ var input = document.getElementById("input_text");
+
+ if (typeof(input.validity) == "object") {
+ test(function() {
+ assert_equals(input.validity.valueMissing, false, "validity attribute is not correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("validity attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-value-invalidstateerr.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-value-invalidstateerr.html
new file mode 100644
index 0000000000..78e6624e7c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-value-invalidstateerr.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_value_INVALID_STATE_ERR</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='file' id='input_file'></p>
+ </form>
+
+ <script>
+
+ var input_file = document.getElementById("input_file");
+ try {
+ input_file.value = "val";
+ test(function() {
+ assert_unreached("INVALID_STATE_ERR error is not raised.");
+ });
+ } catch (e) {
+ test(function() {
+ assert_equals(e.code, e["INVALID_STATE_ERR"], "INVALID_STATE_ERR error is not raised.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-invalidstateerr.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-invalidstateerr.html
new file mode 100644
index 0000000000..bd49a15fc8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-invalidstateerr.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_valueAsDate_INVALID_STATE_ERR</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='checkbox' id='input_checkbox'></p>
+ </form>
+
+ <script>
+ var input_checkbox = document.getElementById("input_checkbox");
+ try {
+ input_checkbox.valueAsDate = new Date('2011-11-01');
+ test(function() {
+ assert_reached("INVALID_STATE_ERR error is not raised.");
+ });
+ }
+ catch (e) {
+ test(function() {
+ assert_equals(e.code, e["INVALID_STATE_ERR"], "INVALID_STATE_ERR error is not raised.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-stepping.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-stepping.html
new file mode 100644
index 0000000000..0985611031
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate-stepping.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>valueAsDate stepping</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_valueAsDate_stepping</h3>
+ <!-- This test verifies that valueAsDate reads and writes Date values,
+ that those values step by the correct default step, and that the values
+ represent the correct times.
+ -->
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='date' id='input_date'></p>
+ <p><input type='time' id='input_time'></p>
+ <p><input type='week' id='input_week'></p>
+ <p><input type='month' id='input_month'></p>
+ </form>
+
+ <script>
+ function test_stepping(inputType, stringValue, steppedString, baseMillis, stepAmount) {
+ test(function() {
+ // put date in, constructed from a UTC timestamp so the test doesn't
+ // vary by local timezone
+ input = document.getElementById("input_" + inputType);
+ input.valueAsDate = new Date(baseMillis)
+
+ // get string out (using startsWith here to allow for optional
+ // seconds and milliseconds)
+ var sanitizedStr = input.value;
+ assert_true(sanitizedStr.startsWith(stringValue),
+ "The input value [" + sanitizedStr + "] must resemble [" + stringValue + "]");
+
+ // get date out
+ var sanitized = input.valueAsDate;
+ assert_equals(sanitized.getTime(), baseMillis, "The input valueAsDate must represent the same time as the original Date.")
+
+ // step up, get new date out
+ input.stepUp()
+ var steppedDate = input.valueAsDate;
+ assert_equals(steppedDate.getTime(), baseMillis + stepAmount, "Stepping must be by the correct amount")
+
+ // get new string out
+ var steppedStrOut = input.value;
+ assert_true(steppedStrOut.startsWith(steppedString),
+ "The changed input value [" + steppedStrOut + "] must resemble ["+steppedString+"]");
+
+ // step back down, get first date out again
+ input.stepDown()
+ var backDown = input.valueAsDate;
+ assert_equals(backDown.getTime(), baseMillis, "Stepping back down must return the date to its original value");
+
+ }, inputType + " should step correctly");
+ }
+
+ var millis_per_day = 24 * 60 * 60 * 1000;
+
+ // jan 1 midnight, step 1 day to jan 2
+ test_stepping("date", "1970-01-01", "1970-01-02", 0, millis_per_day);
+
+ // jan 1 midnight, step 1 minute to 00:01:00
+ test_stepping("time", "00:00", "00:01", 0, 60 * 1000);
+
+ // jan 1 midnight, step 31 days to feb 1
+ test_stepping("month", "1970-01", "1970-02", 0, 31 * millis_per_day);
+
+ // monday jan 5 1970 midnight, step 7 days to jan 12
+ // (this has to start on a monday for stepping up and down to return)
+ test_stepping("week", "1970-W02", "1970-W03", 4 * millis_per_day, 7 * millis_per_day);
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate.html
new file mode 100644
index 0000000000..894983add2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasdate.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<html>
+ <head>
+ <title>HTMLInputElement valueAsDate</title>
+ <link rel="author" title="pmdartus" href="mailto:dartus.pierremarie@gmail.com">
+ <link rel=help href="https://html.spec.whatwg.org/#dom-input-valueasdate">
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h3>input_valueAsDate</h3>
+ <hr>
+ <div id="log"></div>
+
+ <input id="input_date" type="date" />
+ <input id="input_month" type="month" />
+ <input id="input_week" type="week" />
+ <input id="input_time" type="time" />
+
+ <script>
+ "use strict";
+
+ function testValueAsDateGetter(type, element, cases) {
+ for (const [actualValue, expectedValueAsDate] of cases) {
+ test(
+ () => {
+ element.value = actualValue;
+
+ const actualValueAsDate = element.valueAsDate;
+ if (actualValueAsDate instanceof Date) {
+ assert_equals(
+ actualValueAsDate.getTime(),
+ expectedValueAsDate.getTime(),
+ `valueAsDate returns an invalid date (actual: ${actualValueAsDate.toISOString()}, ` +
+ `expected: ${expectedValueAsDate.toISOString()})`
+ );
+ } else {
+ assert_equals(actualValueAsDate, expectedValueAsDate);
+ }
+ },
+ `valueAsDate getter on type ${type} (with value: ${JSON.stringify(actualValue)})`
+ );
+ }
+ }
+
+ function testValueAsDateSetter(type, element, cases) {
+ for (const [valueDateStr, expectedValue] of cases) {
+ test(() => {
+ element.valueAsDate = new Date(valueDateStr);
+ assert_equals(element.value, expectedValue);
+ }, `valueAsDate setter on type ${type} (new Date(${JSON.stringify(valueDateStr)}))`);
+ }
+ }
+
+ const dateInput = document.getElementById("input_date");
+ testValueAsDateGetter("date", dateInput, [
+ ["", null],
+ ["0000-12-10", null],
+ ["2019-00-12", null],
+ ["2019-12-00", null],
+ ["2019-13-10", null],
+ ["2019-02-29", null],
+ ["2019-12-10", new Date("2019-12-10T00:00:00.000Z")],
+ ["2016-02-29", new Date("2016-02-29T00:00:00.000Z")] // Leap year
+ ]);
+ testValueAsDateSetter("date", dateInput, [
+ ["2019-12-10T00:00:00.000Z", "2019-12-10"],
+ ["2016-02-29T00:00:00.000Z", "2016-02-29"] // Leap year
+ ]);
+
+ const monthInput = document.getElementById("input_month");
+ testValueAsDateGetter("month", monthInput, [
+ ["", null],
+ ["0000-12", null],
+ ["2019-00", null],
+ ["2019-12", new Date("2019-12-01T00:00:00.000Z")]
+ ]);
+ testValueAsDateSetter("month", monthInput, [["2019-12-01T00:00:00.000Z", "2019-12"]]);
+
+ const weekInput = document.getElementById("input_week");
+ testValueAsDateGetter("week", weekInput, [
+ ["", null],
+ ["0000-W50", null],
+ ["2019-W00", null],
+ ["2019-W60", null],
+ ["2019-W50", new Date("2019-12-09T00:00:00.000Z")]
+ ]);
+ testValueAsDateSetter("week", weekInput, [["2019-12-09T00:00:00.000Z", "2019-W50"]]);
+
+ const timeInput = document.getElementById("input_time");
+ testValueAsDateGetter("time", timeInput, [
+ ["", null],
+ ["24:00", null],
+ ["00:60", null],
+ ["00:00", new Date("1970-01-01T00:00:00.000Z")],
+ ["12:00", new Date("1970-01-01T12:00:00.000Z")],
+ ["23:59", new Date("1970-01-01T23:59:00.000Z")]
+ ]);
+ testValueAsDateSetter("time", timeInput, [
+ ["1970-01-01T00:00:00.000Z", "00:00"],
+ ["1970-01-01T12:00:00.000Z", "12:00"],
+ ["1970-01-01T23:59:00.000Z", "23:59"]
+ ]);
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-invalidstateerr.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-invalidstateerr.html
new file mode 100644
index 0000000000..a3187ff3fb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-invalidstateerr.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_valueAsNumber_INVALID_STATE_ERR</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='checkbox' id='input_checkbox'></p>
+ </form>
+
+ <script>
+
+ var input_checkbox = document.getElementById("input_checkbox");
+ try {
+ input_checkbox.valueAsNumber = 5;
+ }
+ catch (e) {
+ test(function() {
+ assert_equals(e.code, e["INVALID_STATE_ERR"], "INVALID_STATE_ERR error is not raised.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-stepping.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-stepping.html
new file mode 100644
index 0000000000..c93c25b23f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber-stepping.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>valueAsNumber stepping</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_valueAsNumber_stepping</h3>
+ <!-- This test verifies that valueAsNumber reads and writes number values,
+ that those values step by the correct default step, and that the values
+ represent the correct milliseconds/months.
+ -->
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='date' id='input_date'></p>
+ <p><input type='time' id='input_time'></p>
+ <p><input type='week' id='input_week'></p>
+ <p><input type='month' id='input_month'></p>
+ <p><input type='datetime-local' id='input_datetime-local'></p>
+ <p><input type='range' id='input_range'></p>
+ <p><input type='number' id='input_number'></p>
+ </form>
+
+ <script>
+ function test_stepping(inputType, stringValue, steppedString, baseNumber, stepAmount) {
+ test(function() {
+ // put number in
+ input = document.getElementById("input_" + inputType);
+ input.valueAsNumber = baseNumber
+
+ // get string out
+ // startsWith is here to allow for optional seconds and milliseconds.
+ // the replace("T", " ") fallback is for https://github.com/web-platform-tests/wpt/issues/20994
+ var sanitizedStr = input.value;
+ assert_true(sanitizedStr.startsWith(stringValue) || sanitizedStr.startsWith(stringValue.replace("T", " ")),
+ "The input value [" + sanitizedStr + "] must resemble [" + stringValue + "]");
+
+ // get number out
+ var sanitized = input.valueAsNumber;
+ assert_equals(sanitized, baseNumber, "The input valueAsNumber must equal the original number.")
+
+ // step up, get new date out
+ input.stepUp()
+ var steppedNumber = input.valueAsNumber;
+ assert_equals(steppedNumber, baseNumber + stepAmount, "Stepping must be by the correct amount")
+
+ // get new string out
+ var steppedStrOut = input.value;
+ assert_true(steppedStrOut.startsWith(steppedString) || steppedStrOut.startsWith(steppedString.replace("T", " ")),
+ "The changed input value [" + steppedStrOut + "] must resemble [" + steppedString + "]");
+
+ // step back down, get first date out again
+ input.stepDown()
+ var backDown = input.valueAsNumber;
+ assert_equals(backDown, baseNumber, "Stepping back down must return the number to its original value");
+
+ }, inputType + " should step correctly");
+ }
+
+ var millis_per_day = 24 * 60 * 60 * 1000;
+
+ // jan 1 midnight, step 1 day to jan 2
+ test_stepping("date", "1970-01-01", "1970-01-02", 0, millis_per_day);
+
+ // jan 1 midnight, step 1 minute to 00:01:00
+ test_stepping("time", "00:00", "00:01", 0, 60 * 1000);
+
+ // jan 1 midnight, step 1 month (not counting by milliseconds) to feb 1
+ test_stepping("month", "1970-01", "1970-02", 0, 1);
+
+ // monday jan 5 1970 midnight, step 7 days to jan 12
+ // (this has to start on a monday for stepping up and down to return)
+ test_stepping("week", "1970-W02", "1970-W03", 4 * millis_per_day, 7 * millis_per_day);
+
+ // jan 1 midnight, step 1 minute to 00:01:00
+ test_stepping("datetime-local", "1970-01-01T00:00", "1970-01-01T00:01", 0, 60 * 1000);
+
+ // numbers, for which the default step is 1
+ test_stepping("range", "22", "23", 22, 1);
+ test_stepping("number", "24", "25", 24, 1);
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber.html
new file mode 100644
index 0000000000..1af75eafa3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-valueasnumber.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<html>
+ <head>
+ <title>HTMLInputElement valueAsNumber</title>
+ <link rel="author" title="pmdartus" href="mailto:dartus.pierremarie@gmail.com">
+ <link rel=help href="https://html.spec.whatwg.org/#dom-input-valueasnumber">
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h3>input_valueAsNumber</h3>
+ <hr>
+ <div id="log"></div>
+
+ <input id="input_date" type="date" />
+ <input id="input_month" type="month" />
+ <input id="input_week" type="week" />
+ <input id="input_time" type="time" />
+ <input id="input_datetime-local" type="datetime-local" />
+ <input id="input_number" type="number" />
+ <input id="input_range" type="range" min="0" max="100" />
+
+ <script>
+ "use strict";
+
+ function testValueAsNumberGetter(type, element, cases) {
+ for (const [value, expectedValueAsNumber] of cases) {
+ test(
+ () => {
+ element.value = value;
+ assert_equals(element.valueAsNumber, expectedValueAsNumber);
+ },
+ `valueAsNumber getter on type ${type} (actual value: ${value}, ` +
+ `expected valueAsNumber: ${expectedValueAsNumber})`
+ );
+ }
+ }
+
+ function testValueAsNumberSetter(type, element, cases) {
+ for (const [valueAsNumber, expectedValue] of cases) {
+ test(
+ () => {
+ element.valueAsNumber = valueAsNumber;
+ assert_equals(element.value, expectedValue);
+ },
+ `valueAsNumber setter on type ${type} (actual valueAsNumber: ${valueAsNumber}, ` +
+ `expected value: ${expectedValue})`
+ );
+ }
+ }
+
+ const dateInput = document.getElementById("input_date");
+ testValueAsNumberGetter("date", dateInput, [
+ ["", NaN],
+ ["0000-12-10", NaN],
+ ["2019-00-12", NaN],
+ ["2019-12-00", NaN],
+ ["2019-13-10", NaN],
+ ["2019-02-29", NaN],
+ ["2019-12-10", 1575936000000],
+ ["2016-02-29", 1456704000000] // Leap year
+ ]);
+ testValueAsNumberSetter("date", dateInput, [
+ [0, "1970-01-01"],
+ [1575936000000, "2019-12-10"],
+ [1456704000000, "2016-02-29"] // Leap year
+ ]);
+
+ const monthInput = document.getElementById("input_month");
+ testValueAsNumberGetter("month", monthInput, [
+ ["", NaN],
+ ["0000-12", NaN],
+ ["2019-00", NaN],
+ ["2019-12", 599]
+ ]);
+ testValueAsNumberSetter("month", monthInput, [[599, "2019-12"]]);
+
+ const weekInput = document.getElementById("input_week");
+ testValueAsNumberGetter("week", weekInput, [
+ ["", NaN],
+ ["0000-W50", NaN],
+ ["2019-W00", NaN],
+ ["2019-W60", NaN],
+ ["2019-W50", 1575849600000]
+ ]);
+ testValueAsNumberSetter("week", weekInput, [
+ [0, "1970-W01"],
+ [1575849600000, "2019-W50"]
+ ]);
+
+ const timeInput = document.getElementById("input_time");
+ testValueAsNumberGetter("time", timeInput, [
+ ["", NaN],
+ ["24:00", NaN],
+ ["00:60", NaN],
+ ["00:00", 0],
+ ["12:00", 12 * 3600 * 1000],
+ ["23:59", ((23 * 3600) + (59 * 60)) * 1000]
+ ]);
+ testValueAsNumberSetter("time", timeInput, [
+ [0, "00:00"],
+ [12 * 3600 * 1000, "12:00"],
+ [((23 * 3600) + (59 * 60)) * 1000, "23:59"]
+ ]);
+
+ const dateTimeLocalInput = document.getElementById("input_datetime-local");
+ testValueAsNumberGetter("datetime-local", dateTimeLocalInput, [
+ ["", NaN],
+ ["2019-12-10T00:00", 1575936000000],
+ ["2019-12-10T12:00", 1575979200000]
+ ]);
+ testValueAsNumberSetter("datetime-local", dateTimeLocalInput, [
+ [1575936000000, "2019-12-10T00:00"],
+ [1575979200000, "2019-12-10T12:00"]
+ ]);
+
+ const numberInput = document.getElementById("input_number");
+ testValueAsNumberGetter("number", numberInput, [
+ ["", NaN],
+ ["123", 123],
+ ["123.456", 123.456],
+ ["1e3", 1000],
+ ["1e", NaN],
+ ["-123", -123]
+ ]);
+ testValueAsNumberSetter("number", numberInput, [
+ [123, "123"],
+ [123.456, "123.456"],
+ [1e3, "1000"],
+ [-123, "-123"]
+ ]);
+
+ const rangeInput = document.getElementById("input_range");
+ testValueAsNumberGetter("range", rangeInput, [
+ ["", 50],
+ ["0", 0],
+ ["50", 50],
+ ["100", 100],
+ ["-10", 0], // Realign to the min
+ ["110", 100] // Realign to the max
+ ]);
+ testValueAsNumberSetter("range", rangeInput, [
+ [0, "0"],
+ [50, "50"],
+ [100, "100"]
+ ]);
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-whitespace.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-whitespace.html
new file mode 100644
index 0000000000..8c3c20e877
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-whitespace.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+ <head>
+ <title>Chrome whitespace bug</title>
+ <link rel="author" title="Steinar H. Gunderson" href="mailto:sesse@chromium.org">
+ <link rel="help" href="https://crbug.com/1309014">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <style>
+ [data-foo] { color: red; }
+ div input { color: inherit; }
+ </style>
+ </head>
+ <body>
+ <div id="container" data-foo="foo"><input id="input1"></input></div>
+ <script>
+ async_test(t => {
+ let container = document.getElementById('container');
+ let input = document.getElementById('input1');
+ input.onkeypress = function(e) {
+ container.removeAttribute('data-foo');
+ input.style.display = 'block';
+ };
+ test_driver.send_keys(input, "a b")
+ .then(t.step_func(() => {
+ assert_equals(input.value, "a b");
+ t.done();
+ }));
+ }, "whitespace should not be eaten after parent style recalculation");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-width.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-width.html
new file mode 100644
index 0000000000..5278ff77e1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-width.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_width</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ name="input_form">
+ <p><input type='image' id='input_text'></p>
+ </form>
+
+ <script>
+
+ var input_text = document.getElementById("input_text");
+ input_text.width = 30;
+
+ if (typeof(input_text.width) == "number") {
+ test(function() {
+ assert_equals(input_text.width, 30, "width attribute is not correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("width attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/input-willvalidate.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-willvalidate.html
new file mode 100644
index 0000000000..e4bcf2e11e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/input-willvalidate.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Forms</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <p>
+ <h3>input_willValidate</h3>
+ </p>
+
+ <hr>
+
+ <div id="log"></div>
+
+ <form method="post"
+ enctype="application/x-www-form-urlencoded"
+ action=""
+ id="input_form">
+ <p><input type='hidden' id='input_text'></p>
+ </form>
+ <script>
+
+ var input = document.getElementById("input_text");
+
+ if (typeof(input.willValidate) == "boolean") {
+ test(function() {
+ assert_equals(input.willValidate, false, "willValidate attribute is not correct.");
+ });
+ } else {
+ test(function() {
+ assert_unreached("willValidate attribute is not exist.");
+ });
+ }
+
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/invalid-datalist-options-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/invalid-datalist-options-crash.html
new file mode 100644
index 0000000000..7cdd55196c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/invalid-datalist-options-crash.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+<input max="0" list="ticks" type="range">
+<datalist id="ticks">
+ <option value="0"></option>
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/large-step-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/large-step-crash.html
new file mode 100644
index 0000000000..6c7d577546
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/large-step-crash.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1310229">
+<script>
+const input = document.createElement('input');
+input.type = 'range';
+input.max = "06146014076123948948236985915694585937453938739248525313667193356954648912174625325457686181245605159230507050382951965923880139416566171456307667108838599671206701390275757535304375074544995161254818024615";
+input.step = "55244276720723476767813103100759083382064508394993167470137";
+input.stepUp();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-manual.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-manual.html
new file mode 100644
index 0000000000..fdf6c26441
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-manual.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=utf-8>
+ <title>input max length</title>
+ <link rel="author" title="Sam Gibson" href="mailto:sam@ifdown.net">
+ <link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-maxlength-and-minlength-attributes">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <div id="log"></div>
+ <p>Type a letter anywhere into the input field (do not select any text, or otherwise manipulate the input)</p>
+ <input type=text maxlength=4 id=only-four value="inpu"></input>
+
+ <script>
+ var input;
+ setup(function() {
+ input = document.getElementById('only-four');
+ }, {explicit_done: true, explicit_timeout: true});
+
+
+ on_event(input, 'keyup', function(event) {
+ if ((event.keyCode >= 65 && event.keyCode <= 90) ||
+ (event.keyCode >= 97 && event.keyCode <= 122)) {
+ test(function() {
+ assert_equals(input.value, "inpu");
+ }, 'input content should limit to maxlength')
+
+ done();
+ }
+ });
+ </script>
+ </body>
+</html>
+
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-number.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-number.html
new file mode 100644
index 0000000000..1e1d9f694c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength-number.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>input type=number maxlength</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input type="number" maxlength="1">
+
+<script>
+ async_test(t => {
+ let elem = document.getElementsByTagName("input")[0];
+ test_driver.send_keys(elem, "1234")
+ .then(t.step_func(() => {
+ assert_equals(elem.value, "1234");
+ t.done();
+ }));
+ }, "maxlength doesn't apply to input type=number");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength.html
new file mode 100644
index 0000000000..da5d18d00a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/maxlength.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>input max length</title>
+ <link rel="author" title="Sam Gibson" href="mailto:sam@ifdown.net">
+ <link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-maxlength-and-minlength-attributes">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Text input element</h1>
+
+ <div style="display: none">
+ <input id="none" />
+ <input id="negative" type="-5" />
+ <input id="non-numeric" type="not-a-number" />
+ <input id="assign-negative" />
+ <input id="assign-non-numeric" />
+ </div>
+
+ <div id="log"></div>
+
+ <script type="text/javascript">
+ test(
+ function() {
+ assert_equals(document.getElementById("none").maxLength, -1);
+ }, "Unset maxlength is -1");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("negative").maxLength, -1);
+ }, "Negative maxlength is always -1");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("non-numeric").maxLength, -1);
+ }, "Non-numeric maxlength is -1");
+
+ test(
+ function() {
+ assert_throws_dom("INDEX_SIZE_ERR", function() {
+ document.getElementById("assign-negative").maxLength = -5;
+ });
+ }, "Assigning negative integer throws IndexSizeError");
+
+ test(
+ function() {
+ document.getElementById("assign-non-numeric").maxLength = "not-a-number";
+ assert_equals(document.getElementById("assign-non-numeric").maxLength, 0);
+ }, "Assigning non-numeric to maxlength sets maxlength to 0");
+ </script>
+ </body>
+</html>
+
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/minlength.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/minlength.html
new file mode 100644
index 0000000000..6748e30eaf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/minlength.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>input min length</title>
+ <link rel="author" title="Taryn Hill" href="mailto:Phrohdoh@gmail.com">
+ <link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#the-minlength-and-minlength-attributes">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Text input element</h1>
+
+ <div style="display: none">
+ <input id="none" />
+ <input id="negative" minlength=-5 />
+ <input id="non-numeric" minlength="not-a-number" />
+ <input id="assign-negative" />
+ <input id="assign-non-numeric" />
+ </div>
+
+ <div id="log"></div>
+
+ <script type="text/javascript">
+ test(
+ function() {
+ assert_equals(document.getElementById("none").minLength, -1);
+ }, "Unset minlength is -1");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("negative").minLength, -1);
+ }, "Negative minlength is always -1");
+
+ test(
+ function() {
+ assert_equals(document.getElementById("non-numeric").minLength, -1);
+ }, "Non-numeric minlength is -1");
+
+ test(
+ function() {
+ assert_throws_dom("INDEX_SIZE_ERR", function() {
+ document.getElementById("assign-negative").minLength = -5;
+ });
+ }, "Assigning negative integer throws IndexSizeError");
+
+ test(
+ function() {
+ document.getElementById("assign-non-numeric").minLength = "not-a-number";
+ assert_equals(document.getElementById("assign-non-numeric").minLength, 0);
+ }, "Assigning non-numeric to minlength sets minlength to 0");
+ </script>
+ </body>
+</html>
+
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/month.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/month.html
new file mode 100644
index 0000000000..99be9bca67
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/month.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Inputs Month</title>
+ <link rel="author" title="Morishita Hiromitsu" href="mailto:hero@asterisk-works.jp">
+ <link rel="author" title="kaseijin" href="mailto:pcmkas@gmail.com">
+ <link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#months">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#month-state-(type=month)">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>Inputs Month</h1>
+ <div style="display: none">
+ <input id="valid_value_1" type="month" value="20133-12" />
+ <input id="valid_value_2" type="month" value="2013-12" />
+ <input id="valid_value_3" type="month" value="0003-01" />
+ <input id="valid" type="month" value="2011-11" min="2011-01" max="2011-12" />
+ <input id="invalid_value" type="month" value="invalid-month" min="2011-01" max="2011-12"/>
+ <input id="value_can_be_empty_string" type="month" value="2013-06" />
+ <input id="invalid_value_with_two_digits_year" type="month" value="13-06" />
+ <input id="invalid_value_is_set" type="month" />
+ <input id="step_attribute_is_invalid_value" type="month" value="2013-06" step="invalid_step_value" />
+ <input id="invalid_month_too_high" type="month" value="2013-13" />
+ <input id="invalid_month_too_low" type="month" value="2013-00" />
+ <input id="invalid_year_all_zero" type="month" value="0000-10" />
+ <input id="invalid_month_with_one_number" type="month" value="2013-1" />
+ <input id="invalid_month_non_numerical" type="month" value="2013-abc" />
+ <input id="invalid_date_additional_tuples" type="month" value="2013-11-1-1" />
+ </div>
+
+ <div id="log"></div>
+
+ <script>
+ test(function() {
+ assert_equals(document.getElementById("valid_value_1").value, "20133-12")
+ }, "year can be more than four digits");
+
+ test(function() {
+ assert_equals(document.getElementById("valid_value_2").value, "2013-12")
+ }, "valid value test");
+
+ test(function() {
+ assert_equals(document.getElementById("valid_value_3").value, "0003-01")
+ }, "year can contain prefixes of zero, as long as there are at least four digits");
+
+ test(function() {
+ assert_equals(document.getElementById("valid").type, "month")
+ }, "month type support on input element");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_value").value, "")
+ }, "User agents must not allow the user to set the value to a non-empty string that is not a valid month string.");
+
+ test(function() {
+ document.getElementById("value_can_be_empty_string").value = "";
+ assert_equals(document.getElementById("value_can_be_empty_string").value, "")
+ }, "Month value can be empty string.");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_value_with_two_digits_year").value, "")
+ }, "When value attribute has two digits year value, the value,which is invalid, must return empty string.");
+
+ test(function() {
+ document.getElementById("invalid_value_is_set").value = "invalid value";
+ assert_equals(document.getElementById("invalid_value_is_set").value, "")
+ }, "When value is set with invalid value, the value must return empty string.");
+
+ test(function() {
+ document.getElementById("step_attribute_is_invalid_value").stepUp();
+ assert_equals(document.getElementById("step_attribute_is_invalid_value").value, "2013-07")
+ }, "When step attribute is given invalid value, it must ignore the invalid value and use defaul value instead.");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_month_too_high").value, "");
+ }, "Month should be <= 13: If the value of the element is not a valid month string, then set it to the empty string instead.");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_month_too_low").value, "");
+ }, "Month should be > 0: If the value of the element is not a valid month string, then set it to the empty string instead.>");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_year_all_zero").value, "");
+ }, "Year should be > 0: If the value of the element is not a valid year string, then set it to the empty string instead.>");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_month_with_one_number").value, "");
+ }, "Month should be two digits: If the value of the element is not a valid month string, then set it to the empty string instead.>");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_month_non_numerical").value, "");
+ }, "Month should be two digits not characters: If the value of the element is not a valid month string, then set it to the empty string instead.>");
+
+ test(function() {
+ assert_equals(document.getElementById("invalid_date_additional_tuples").value, "");
+ }, "Value should be two parts: If the value of the element is not a valid month string, then set it to the empty string instead.>");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-cr.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-cr.html
new file mode 100644
index 0000000000..06f07cbbd8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-cr.html
@@ -0,0 +1 @@
+<!doctype html> <html class="reftest-wait"> <meta charset="utf-8"> <title>input multiline placeholder (CR)</title> <link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute"> <meta name="assert" content="input element's placeholder strips newlines (CR)"> <link rel="match" href="multiline-placeholder-ref.html"> <input placeholder="this is a multiline placeholder"> <input placeholder="this is&#xd;a multiline&#xd;&#xd;placeholder"> <input id="dynamic"> <script> document.querySelector("#dynamic") .setAttribute("placeholder", "this is\ra multiline\r\rplaceholder"); document.documentElement.classList.remove("reftest-wait"); </script> </html> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-crlf.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-crlf.html
new file mode 100644
index 0000000000..b4336e24d2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-crlf.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>input multiline placeholder (CRLF)</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute">
+<meta name="assert" content="input element's placeholder strips newlines (CRLF)">
+<link rel="match" href="multiline-placeholder-ref.html">
+<input placeholder="this is
+a multiline
+
+placeholder">
+<input placeholder="this is&#xd;&#xa;a multiline&#xd;&#xa;&#xd;&#xa;placeholder">
+<input id="dynamic">
+<script>
+ document.querySelector("#dynamic")
+ .setAttribute("placeholder", "this is\r\na multiline\r\n\r\nplaceholder");
+ document.documentElement.classList.remove("reftest-wait");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-ref.html
new file mode 100644
index 0000000000..2812f86e1e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder-ref.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<meta charset=utf-8>
+<input placeholder="this isa multilineplaceholder">
+<input placeholder="this isa multilineplaceholder">
+<input placeholder="this isa multilineplaceholder">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder.html
new file mode 100644
index 0000000000..4d2ec43c3f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/multiline-placeholder.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>input multiline placeholder</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute">
+<meta name="assert" content="input element's placeholder strips newlines">
+<link rel="match" href="multiline-placeholder-ref.html">
+<input placeholder="this is
+a multiline
+
+placeholder">
+<input placeholder="this is&#xa;a multiline&#xa;&#xa;placeholder">
+<input id="dynamic">
+<script>
+ document.querySelector("#dynamic")
+ .setAttribute("placeholder", "this is\na multiline\n\nplaceholder");
+ document.documentElement.classList.remove("reftest-wait");
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/number-constraint-validation.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/number-constraint-validation.html
new file mode 100644
index 0000000000..959726bb50
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/number-constraint-validation.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Form input type=number constraint validation</title>
+<link rel="author" title="Adam Vandolder" href="mailto:avandolder@mozilla.com">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#number-state-(type=number)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<div id="log"></div>
+<input type="number">
+<script>
+ const input = document.querySelector("input");
+ const invalidInputNumber = "1.e";
+ const invalidSetNumber = "1.";
+
+ promise_test(async () => {
+ await test_driver.click(input);
+ await test_driver.send_keys(input, invalidInputNumber);
+ assert_equals(input.value.length, 0);
+ assert_true(input.validity.badInput);
+ }, "Unparsable number user input triggers sanitization and causes badInput to be set.");
+
+ promise_test(async () => {
+ input.value = invalidInputNumber;
+ assert_equals(input.value.length, 0);
+ assert_false(input.validity.badInput);
+ }, "Setting .value to an unparsable number triggers sanitization but doesn't set badInput.");
+
+ promise_test(async () => {
+ await test_driver.click(input);
+ await test_driver.send_keys(input, invalidSetNumber);
+ assert_equals(input.value, "1");
+ assert_false(input.validity.badInput);
+ }, "Users inputting a parsable but invalid floating point number doesn't trigger sanitization and doesn't set badInput.");
+
+ promise_test(async () => {
+ input.value = invalidSetNumber;
+ assert_equals(input.value.length, 0);
+ assert_false(input.validity.badInput);
+ }, "Setting .value to a parsable but invalid floating point number triggers sanitization but doesn't set badInput.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/number-disabled.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/number-disabled.html
new file mode 100644
index 0000000000..11cb82fdda
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/number-disabled.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>disabled works properly for number inputs</title>
+<link rel="help" href="https://html.spec.whatwg.org/#enabling-and-disabling-form-controls:-the-disabled-attribute">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1461706">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input type="number" disabled>
+<input type="number" disabled style="-moz-appearance: textfield; -webkit-appearance: textfield">
+<script>
+ test(function() {
+ for (const element of Array.from(document.querySelectorAll('input'))) {
+ element.focus();
+ assert_true(element.disabled);
+ assert_equals(document.activeElement, document.body);
+ }
+ }, "disabled works on number input regardless of appearance");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/number.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/number.html
new file mode 100644
index 0000000000..7d93f20898
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/number.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Form input type=number</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#number-state-(type=number)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ var numbers = [
+ {value: "", expected: "", testname: "empty value"},
+ {value: "11", expected: "11", testname: "value = 11"},
+ {value: "11.12", expected: "11.12", testname: "value = 11.12"},
+ {value: "-11111", expected: "-11111", testname: "value = -11111"},
+ {value: "-11111.123", expected: "-11111.123", testname: "value = -11111.123"},
+ {value: "1e2", expected: "1e2", testname: "value = 1e2"},
+ {value: "1E2", expected: "1E2", testname: "value = 1E2"},
+ {value: "1e+2", expected: "1e+2", testname: "value = 1e+2"},
+ {value: "1e-2", expected: "1e-2", testname: "value = 1e-2"},
+ {value: "1d+2", expected: "", testname: "value is not a valid floating-point number: 1d+2"},
+ {value: "foobar", expected: "", testname: "value not a valid floating-point number: random string"},
+ {value: "11", attributes: { min: "10" }, expected: "11", testname: "Value >= min attribute"},
+ {value: "9", attributes: { min: "10" }, expected: "9", testname: "Value < min attribute"},
+ {value: "19", attributes: { max: "20" }, expected: "19", testname: "Value <= max attribute"},
+ {value: "21", attributes: { max: "20" }, expected: "21", testname: "Value > max attribute"},
+ {value: ".1", expected: ".1", testname: "value with a leading '.'"},
+ {value: "1.", expected: "", testname: "value ending with '.'"},
+ {value: "-0", expected: "-0", testname: "value = -0"},
+ {value: "Infinity", expected: "", testname: " value = Infinity"},
+ {value: "-Infinity", expected: "", testname: "value = -Infinity"},
+ {value: "NaN", expected: "", testname: "value = NaN"},
+ {value: "9007199254740993", expected: "9007199254740993", testname: "value = 2^53+1"},
+ {value: "2e308", expected: "", testname: "value >= Number.MAX_VALUE"},
+ {value: "1e", expected: "", testname: "value = 1e"},
+ {value: "+1", expected: "", testname: "value = +1"},
+ {value: "+", expected: "", testname: "value = '+'"},
+ {value: "-", expected: "", testname: "value = '-'"},
+ {value: "\t1", expected: "", testname: "value with a leading tab"},
+ {value: "\n1", expected: "", testname: "value with a leading newline"},
+ {value: "\f1", expected: "", testname: "value with a leading form feed"},
+ {value: "\r1", expected: "", testname: "value with a leading carriage return"},
+ {value: " 1", expected: "", testname: "value with a leading space"},
+ {value: "1trailing junk", expected: "", testname: "value = 1trailing junk"}
+ ];
+ for (var i = 0; i < numbers.length; i++) {
+ var w = numbers[i];
+ test(function() {
+ var input = document.createElement("input");
+ input.type = "number";
+ input.value = w.value;
+ for(var attr in w.attributes) {
+ input[attr] = w.attributes[attr];
+ }
+ assert_equals(input.value, w.expected);
+ }, w.testname);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/password-delete-space.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/password-delete-space.html
new file mode 100644
index 0000000000..78b3c966b8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/password-delete-space.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Backspace with trailing white space in password field</title>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1400844">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#password-state-%28type=password%29">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<input id="target" type="password" value=" ">
+
+<script>
+promise_test(async () => {
+ target.focus();
+ target.selectionStart = 2;
+ await test_driver.send_keys(target, '\uE003');
+ assert_equals(target.value, " ");
+}, "Backspace with trailing white space in password field");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/password.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/password.html
new file mode 100644
index 0000000000..aac54aa1c7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/password.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Password input element</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#password-state-%28type=password%29">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<div style="display: none">
+<input id="password" type="password" />
+<input id=password2 type=password value="password">
+<input id="password_with_value" type="password" value="foobar" />
+</div>
+<script type="text/javascript">
+ setup(function() {
+ window.password = document.getElementById("password");
+ });
+
+ test(function() {
+ assert_equals(password.value, "");
+ assert_equals(document.getElementById("password_with_value").value, "foobar");
+ }, "Value returns the current value for password");
+
+ test(function() {
+ password.value = "A";
+ assert_equals(password.value, "A");
+ assert_equals(password.getAttribute("value"), null);
+ password.value = "B";
+ assert_equals(password.value, "B");
+ assert_equals(password.getAttribute("value"), null);
+ }, "Setting value changes the current value for password, but not the value content attribute");
+
+ test(function() {
+ // Any LF (\n) must be stripped.
+ password.value = "\nAB";
+ assert_equals(password.value, "AB");
+ password.value = "A\nB";
+ assert_equals(password.value, "AB");
+ password.value = "AB\n";
+ assert_equals(password.value, "AB");
+
+ // Any CR (\r) must be stripped.
+ password.value = "\rAB";
+ assert_equals(password.value, "AB");
+ password.value = "A\rB";
+ assert_equals(password.value, "AB");
+ password.value = "AB\r";
+ assert_equals(password.value, "AB");
+
+ // Any combinations of LF CR must be stripped.
+ password.value = "\r\nAB";
+ assert_equals(password.value, "AB");
+ password.value = "A\r\nB";
+ assert_equals(password.value, "AB");
+ password.value = "AB\r\n";
+ assert_equals(password.value, "AB");
+ password.value = "\r\nA\n\rB\r\n";
+ assert_equals(password.value, "AB");
+ }, "Value sanitization algorithm should strip line breaks for password");
+
+ var pass = document.getElementById('password2');
+
+ test(function(){
+ assert_equals(pass.value, "password");
+ pass.value = " pass word ";
+ assert_equals(pass.value, " pass word ");
+ }, "sanitization algorithm doesn't strip leading and trailing whitespaces");
+
+ test(function(){
+ pass.value = "pass\u000Aword";
+ assert_equals(pass.value, "password");
+ pass.value = "\u000Apassword\u000A";
+ assert_equals(pass.value, "password");
+ pass.value = "pass\u000Dword";
+ assert_equals(pass.value, "password");
+ pass.value = "\u000Dpassword\u000D";
+ assert_equals(pass.value, "password");
+ }, "sanitization algorithm strips line breaks");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/pattern_attribute.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/pattern_attribute.html
new file mode 100644
index 0000000000..93cbd2caec
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/pattern_attribute.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>pattern attribute</title>
+<meta name=viewport content="width=device-width">
+<link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+<link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+<link rel="author" title="Mathias Bynens" href="https://mathiasbynens.be/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#attr-input-pattern">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<h1><code>pattern</code> attribute</h1>
+<div style="display: none">
+ <input pattern="[a-z]{3}" value="abcd" id="basic">
+
+ <input pattern="a.b" value="a&#x1D306;b" id="unicode-code-points">
+ <input pattern="\p{ASCII_Hex_Digit}+" value="c0ff33" id="unicode-property">
+
+ <input pattern="\p{RGI_Emoji}+" value="&#x1F618;&#x1F48B;" id="unicode-property-of-strings">
+ <input pattern="[\p{ASCII_Hex_Digit}--[Ff]]" value="0123456789abcdefABCDEF" id="set-difference">
+ <input pattern="[_\q{a|bc|def}]" value="q" id="string-literal">
+
+ <div class="breaking-changes-from-u-to-v">
+ <!-- Unescaped special characters in character classes. -->
+ <input pattern="[(]" value="foo">
+ <input pattern="[)]" value="foo">
+ <input pattern="[[]" value="foo">
+ <input pattern="[{]" value="foo">
+ <input pattern="[}]" value="foo">
+ <input pattern="[/]" value="foo">
+ <input pattern="[-]" value="foo">
+ <input pattern="[|]" value="foo">
+ <!-- Double punctuators in character classes. -->
+ <input pattern="[&&]" value="foo">
+ <input pattern="[!!]" value="foo">
+ <input pattern="[##]" value="foo">
+ <input pattern="[$$]" value="foo">
+ <input pattern="[%%]" value="foo">
+ <input pattern="[**]" value="foo">
+ <input pattern="[++]" value="foo">
+ <input pattern="[,,]" value="foo">
+ <input pattern="[..]" value="foo">
+ <input pattern="[::]" value="foo">
+ <input pattern="[;;]" value="foo">
+ <input pattern="[<<]" value="foo">
+ <input pattern="[==]" value="foo">
+ <input pattern="[>>]" value="foo">
+ <input pattern="[??]" value="foo">
+ <input pattern="[@@]" value="foo">
+ <input pattern="[``]" value="foo">
+ <input pattern="[~~]" value="foo">
+ <input pattern="[_^^]" value="foo">
+ </div>
+</div>
+<div id="log"></div>
+<script>
+ test(() => {
+ const input = document.querySelector("#basic");
+
+ assert_idl_attribute(input, "pattern");
+ assert_equals(input.pattern, "[a-z]{3}");
+
+ assert_inherits(input, "validity");
+ assert_false(input.validity.valid);
+ assert_true(input.validity.patternMismatch);
+
+ assert_true(input.matches(":invalid"));
+ }, "basic <input pattern> support");
+
+ test(() => {
+ const input = document.querySelector("#unicode-code-points");
+ assert_true(input.validity.valid);
+ assert_true(input.matches(":valid"));
+ assert_false(input.validity.patternMismatch);
+ }, "<input pattern> is Unicode code point-aware");
+
+ test(() => {
+ const input = document.querySelector("#unicode-property");
+ assert_true(input.validity.valid);
+ assert_true(input.matches(":valid"));
+ assert_false(input.validity.patternMismatch);
+ }, "<input pattern> supports Unicode property escape syntax");
+
+ test(() => {
+ const input = document.querySelector("#unicode-property-of-strings");
+ assert_true(input.validity.valid);
+ assert_true(input.matches(":valid"));
+ assert_false(input.validity.patternMismatch);
+ }, "<input pattern> supports Unicode property escape syntax for properties of strings");
+
+ test(() => {
+ const input = document.querySelector("#set-difference");
+ assert_false(input.validity.valid);
+ assert_false(input.matches(":valid"));
+ assert_true(input.validity.patternMismatch);
+ }, "<input pattern> supports set difference syntax");
+
+ test(() => {
+ const input = document.querySelector("#string-literal");
+ assert_false(input.validity.valid);
+ assert_true(input.validity.patternMismatch);
+ assert_true(input.matches(":invalid"));
+ }, "<input pattern> supports string literal syntax");
+
+ test(() => {
+ const inputs = document.querySelectorAll(".breaking-changes-from-u-to-v input");
+ // These examples are all written such that they’re all `:invalid`
+ // when using `u`, but would become `:valid` when using `v` because
+ // the pattern would error, in turn resulting in
+ // `validity.valid === true`.
+ for (const input of inputs) {
+ const html = input.outerHTML;
+ assert_true(input.validity.valid, `${html} should be valid`);
+ assert_true(input.matches(":valid"), `${html} should match \`:valid\``);
+ assert_false(input.validity.patternMismatch, `${html} should not trigger a pattern mismatch`);
+ }
+ }, "<input pattern> enables the RegExp v flag");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update-ref.html
new file mode 100644
index 0000000000..38da019539
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<input value="content">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update.html
new file mode 100644
index 0000000000..af0c0793ee
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/placeholder-update.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<link rel="match" href="placeholder-update-ref.html">
+<body>
+<div id="app"></div>
+<script>
+const rootElement = document.getElementById("app");
+const input = document.createElement("input");
+input.placeholder = "placeholder";
+input.value = "content";
+rootElement.appendChild(input);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-disconnected-group-owner.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-disconnected-group-owner.html
new file mode 100644
index 0000000000..60feb2b0ba
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-disconnected-group-owner.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <meta charset="utf-8">
+ <title>Test for validity of disconnected radio buttons</title>
+</head>
+
+<body>
+ <input type="radio" name="group" id="radio1" required />
+ <input type="radio" name="group" id="radio2" checked />
+ <form>
+ <input type="radio" name="group" id="radio3" required />
+ <input type="radio" name="group" id="radio4" checked />
+ </form>
+
+ <script>
+ test(() => {
+ const radio1 = document.getElementById("radio1");
+ const radio2 = document.getElementById("radio2");
+ assert_false(radio1.validity.valueMissing, "Element should not suffer from value missing");
+
+ radio2.remove();
+ assert_true(radio1.validity.valueMissing, "Element should suffer from value missing");
+
+ radio1.checked = true;
+ radio2.required = true;
+ assert_false(radio2.validity.valueMissing, "Element should not suffer from value missing");
+
+ const radio3 = document.getElementById("radio3");
+ const radio4 = document.getElementById("radio4");
+ assert_false(radio3.validity.valueMissing, "Element should not suffer from value missing");
+
+ radio4.remove();
+ assert_true(radio3.validity.valueMissing, "Element should suffer from value missing");
+
+ radio3.checked = true;
+ assert_true(radio4.checked, "Element should remain checked");
+ assert_false(radio3.validity.valueMissing, "Element should not suffer from value missing");
+
+ document.querySelector("form").appendChild(radio2);
+ assert_false(radio3.checked, "Element should be unchecked");
+ assert_false(radio1.validity.valueMissing, "Element should not suffer from value missing");
+ }, "Removed elements are moved into separate radio groups.");
+
+ test(() => {
+ const container = document.createElement("div");
+ const radio = document.createElement("input");
+ radio.type = "radio";
+ radio.name = "group";
+ radio.id = "radio5";
+ radio.required = true;
+ container.appendChild(radio);
+ assert_true(radio.validity.valueMissing, "Element should suffer from value missing");
+
+ const outerContainer = document.createElement("div");
+ const outerRadio = document.createElement("input");
+ outerRadio.type = "radio";
+ outerRadio.name = "group";
+ outerRadio.id = "radio6";
+ outerRadio.checked = true;
+ outerContainer.appendChild(outerRadio);
+ outerContainer.appendChild(container);
+ assert_false(radio.validity.valueMissing, "Element should not suffer from value missing");
+
+ container.remove();
+ assert_true(radio.validity.valueMissing, "Element should suffer from value missing");
+ }, "Disconnected radio buttons should be contained by their tree root.");
+
+ test(() => {
+ const radioParent = document.createElement("input");
+ radioParent.type = "radio";
+ radioParent.name = "group";
+ radioParent.id = "radio-parent";
+ radioParent.required = true;
+ assert_true(radioParent.validity.valueMissing, "Element should suffer from value missing");
+
+ const radioChild = document.createElement("input");
+ radioChild.type = "radio";
+ radioChild.name = "group";
+ radioChild.id = "radio-child";
+ radioChild.checked = true;
+ assert_false(radioChild.validity.valueMissing, "Element should not suffer from value missing");
+
+ radioParent.appendChild(radioChild);
+ assert_false(radioChild.validity.valueMissing, "Element should not suffer from value missing");
+ assert_false(radioParent.validity.valueMissing, "Element should not suffer from value missing");
+
+ radioParent.checked = true;
+ assert_false(radioChild.checked, "Element should no longer be checked");
+ }, "Disconnected radio buttons can serve as radio group containers.");
+
+ test(() => {
+ const shadowHost = document.createElement("div");
+ const root = shadowHost.attachShadow({mode: "open"});
+ const container = document.createElement("div");
+ container.appendChild(shadowHost);
+
+ const radio1 = document.createElement("input");
+ radio1.type = "radio";
+ radio1.name = "group";
+ radio1.required = true;
+ const radio2 = document.createElement("input");
+ radio2.type = "radio";
+ radio2.name = "group";
+ radio2.checked = true;
+ const radio3 = document.createElement("input");
+ radio3.type = "radio";
+ radio3.name = "group";
+ radio3.required = true;
+
+ root.appendChild(radio1);
+ container.appendChild(radio3);
+ assert_true(radio1.validity.valueMissing, "Element should suffer from value missing");
+ assert_true(radio3.validity.valueMissing, "Element should suffer from value missing");
+
+ root.appendChild(radio2);
+ assert_false(radio1.validity.valueMissing, "Element should not suffer from value missing");
+ assert_true(radio3.validity.valueMissing, "Element should suffer from value missing");
+ }, "Shadow roots in disconnected trees can serve as radio group containers.");
+
+ test(() => {
+ const svgRoot = document.createElementNS("http://www.w3.org/2000/svg", "g")
+ const htmlContainer = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
+ svgRoot.appendChild(htmlContainer);
+
+ const radio1 = document.createElement("input");
+ radio1.type = "radio";
+ radio1.name = "group";
+ radio1.required = true;
+ const radio2 = document.createElement("input");
+ radio2.type = "radio";
+ radio2.name = "group";
+ radio2.checked = true;
+
+ htmlContainer.appendChild(radio1);
+ assert_true(radio1.validity.valueMissing, "Element should suffer from value missing");
+ htmlContainer.appendChild(radio2);
+ assert_false(radio1.validity.valueMissing, "Element should not suffer from value missing");
+ radio1.checked = true;
+ assert_false(radio2.checked, "Element should no longer be checked");
+ }, "Non-HTML elements in disconnected trees can serve as radio group containers.");
+
+ test(() => {
+ const fragment = document.createDocumentFragment();
+
+ const radio1 = document.createElement("input");
+ radio1.type = "radio";
+ radio1.name = "group";
+ radio1.required = true;
+ const radio2 = document.createElement("input");
+ radio2.type = "radio";
+ radio2.name = "group";
+ radio2.checked = true;
+
+ fragment.appendChild(radio1);
+ assert_true(radio1.validity.valueMissing, "Element should suffer from value missing");
+ fragment.appendChild(radio2);
+ assert_false(radio1.validity.valueMissing, "Element should not suffer from value missing");
+ radio1.checked = true;
+ assert_false(radio2.checked, "Element should no longer be checked");
+ }, "Disconnected document fragments can serve as radio group containers.");
+ </script>
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-double-activate-pseudo.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-double-activate-pseudo.html
new file mode 100644
index 0000000000..287dc7d58e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-double-activate-pseudo.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<!-- This behavior is not explicitly specified. -->
+
+<input type=radio id=radioinput>
+
+<script>
+ promise_test(async () => {
+ await test_driver.send_keys(radioinput, ' ');
+ await test_driver.send_keys(radioinput, ' ');
+ assert_equals(document.querySelector(':active'), null,
+ `If the radio doesn't have the :active pseudo selector, nothing else should either.`);
+ }, `<input type=radio> shouldn't have the :active pseudo element after pressing the spacebar twice.`);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-groupname-case.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-groupname-case.html
new file mode 100644
index 0000000000..3c54aca3e7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-groupname-case.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>radio group name case-sensitive</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#radio-button-group">
+<!-- See also: https://github.com/whatwg/html/issues/1666 -->
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+
+<input id=r1 type="radio" name="sImPlE">
+<input id=r2 type="radio" name="simple">
+<input id=r3 type="radio" name="SIMPLE">
+
+<input id=r4 type="radio" name="paSSfield-killroyß">
+<input id=r5 type="radio" name="passfield-killroyß">
+<input id=r6 type="radio" name="PASSFIELD-KILLROYß">
+<input id=r7 type="radio" name="paſſfield-killroyß">
+<input id=r8 type="radio" name="passfield-&#x212a;illroyß">
+<input id=r9 type="radio" name="paßfield-killroyß">
+<input id=r10 type="radio" name="paẞfield-killroyß">
+<input id=r11 type="radio" name="passfield-killroyẞ">
+<input id=r12 type="radio" name="passfield-killroyß">
+<input id=r13 type="radio" name="passfıeld-killroyß">
+<input id=r14 type="radio" name="passfİeld-killroyß">
+
+<input id=r15 type="radio" name="глупый">
+<input id=r16 type="radio" name="глупы&#x438;&#x306;">
+<input id=r17 type="radio" name="ГЛУПЫЙ">
+<input id=r18 type="radio" name="ГЛУПЫ&#x418;&#x306;">
+
+<input id=r19 type="radio" name="åωk">
+<input id=r20 type="radio" name="ÅΩK">
+<input id=r21 type="radio" name="&#x212b;ωk">
+<input id=r22 type="radio" name="å&#x2126;k">
+<input id=r23 type="radio" name="åω&#x212a;">
+
+<input id=r24 type="radio" name="blah1">
+<input id=r25 type="radio" name="blah&#x2460;">
+<input id=r26 type="radio" name="bl&#x24b6;h1">
+<input id=r27 type="radio" name="bl&#x24d0;h1">
+
+<input id=r28 type="radio" name="t&Eacute;dz5アパートFi">
+<input id=r29 type="radio" name="T&Eacute;DZ5アパートFi">
+<input id=r30 type="radio" name="T&eacute;&#x01F1;&#x2075;アパートFi">
+<input id=r31 type="radio" name="t&Eacute;dz5&#x3300;Fi">
+<input id=r32 type="radio" name="t&Eacute;dz5&#x30A2;&#x30CF;&#x309A;&#x30FC;&#x30C8;Fi">
+<input id=r34 type="radio" name="T&Eacute;DZ⁵アパートFi">
+<input id=r35 type="radio" name="T&Eacute;DZ5アパートfi">
+
+<input id=r36 type="radio" name="ΣΣ">
+<input id=r37 type="radio" name="σς">
+
+<script>
+"use strict";
+const notGroups = {
+ "sImPlE": ["r1" ,"r2", "r3"],
+ "paSSfield-killroyß": ["r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14"],
+ "глупый": ["r15", "r16", "r17", "r18"],
+ "åωk": ["r19", "r20", "r21", "r22", "r23"],
+ "blah1": ["r24", "r25", "r26", "r27"],
+ "tÉdz5アパートFi": ["r28", "r29", "r30", "r31", "r32", "r34", "r35"],
+ "ΣΣ": ["r36", "r37"]
+};
+
+for (let notGroupLabel of Object.keys(notGroups)) {
+ test(() => {
+ const ids = notGroups[notGroupLabel];
+ const radios = ids.map(id => document.getElementById(id));
+
+ for (let radio of radios) {
+ radio.checked = true;
+ }
+
+ for (let radio of radios) {
+ assert_true(radio.checked, `${radio.name} must be checked`);
+ }
+ }, `Among names like ${notGroupLabel}, everything must be checkable at the same time`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-input-cancel.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-input-cancel.html
new file mode 100644
index 0000000000..fc2796b041
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-input-cancel.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<title>Radio input cancel behavior reverts state</title>
+<link rel="author" title="jeffcarp" href="mailto:gcarpenterv@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/#radio-button-state-(type=radio)">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+"use strict";
+
+test(() => {
+ const input = document.createElement("input");
+ input.type = "radio";
+ document.body.appendChild(input);
+ const events = [];
+
+ input.addEventListener("change", () => {
+ events.push("change");
+ });
+ input.addEventListener("click", e => {
+ // cancel click event
+ e.preventDefault();
+ events.push("click");
+ });
+ input.addEventListener("input", () => {
+ events.push("input");
+ });
+
+ assert_false(input.checked);
+
+ input.click();
+
+ assert_false(input.checked);
+
+ // only click event called
+ assert_array_equals(events, ["click"]);
+
+}, "radio input cancel behavior reverts state");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-keyboard-navigation-order.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-keyboard-navigation-order.html
new file mode 100644
index 0000000000..d019ca982c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-keyboard-navigation-order.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Radio button group keyboard navigation order</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+<form id="inside">
+ <input type="radio" name="inside" id="inside1"/>
+ <input type="radio" name="inside" id="inside2"/>
+ <input type="radio" name="inside" id="inside3"/>
+</form>
+<form id="before"></form>
+<input type="radio" form="before" name="before" id="before1"/>
+<input type="radio" form="before" name="before" id="before2"/>
+<input type="radio" form="before" name="before" id="before3"/>
+<input type="radio" form="after" name="after" id="after1"/>
+<input type="radio" form="after" name="after" id="after2"/>
+<input type="radio" form="after" name="after" id="after3"/>
+<form id="after"></form>
+<input type="radio" name="mix" id="mix1"/>
+<form id="mix"><input type="radio" name="mix" id="mix2"/></form>
+<input type="radio" name="mix" id="mix3"/>
+<input type="radio" name="doc" id="doc1"/>
+<input type="radio" name="doc" id="doc2"/>
+<input type="radio" name="doc" id="doc3"/>
+<script>
+async function pressRight() {
+ return new test_driver.Actions()
+ .keyDown("\uE014")
+ .keyUp("\uE014")
+ .send();
+}
+
+promise_test(async () => {
+ for (const groupName of ["inside", "before", "after", "mix", "doc"]) {
+ const firstInGroup = document.querySelector(`input[name="${groupName}"]`);
+ const newInput = document.createElement("input");
+ newInput.id = groupName + "New";
+ newInput.type = "radio";
+ if (groupName != "doc") {
+ newInput.setAttribute("form", groupName);
+ }
+ newInput.name = groupName;
+ firstInGroup.after(newInput);
+ }
+
+ for (const formId of ["inside", "before", "after", "mix"]) {
+ document.forms[formId].elements[0].focus();
+ for (const radio of document.forms[formId].elements) {
+ assert_equals(radio, document.activeElement, `Navigated to next radio button in form '${formId}'`);
+ await pressRight();
+ }
+ }
+
+ const radios = document.querySelectorAll("input[name='doc']");
+ radios[0].focus();
+ for (const radio of radios) {
+ assert_equals(radio, document.activeElement, `Navigated to next radio button on document`);
+ await pressRight();
+ }
+}, "Radio button keyboard navigation should proceed in tree-order.");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-morphed.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-morphed.html
new file mode 100644
index 0000000000..b7b8658948
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-morphed.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Morphed radio input</title>
+<link rel="author" title="Kagami Sascha Rosylight" href="mailto:krosylight@mozilla.com">
+<link rel="help" href="https://html.spec.whatwg.org/#radio-button-state-(type=radio)">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input id="radio" type="radio" name="name_7" checked>
+<input id="text" name="name_7" checked>
+<script>
+ "use strict";
+
+ test(() => {
+ text.type = 'radio';
+ assert_false(radio.checked);
+ }, "Setting type attribute must unset checkedness of other elements");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-multiple-selected.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-multiple-selected.html
new file mode 100644
index 0000000000..83d42032a5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio-multiple-selected.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Multiple required input radio elements</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<form id='testForm'>
+ <input type=radio name=foo required checked>
+ <input type=radio name=foo required>
+ <input type=submit>
+</form>
+<script>
+ test(function() {
+ assert_true(document.getElementById('testForm').reportValidity());
+ }, "Form should be valid since one of the radio elements is checked");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/radio.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio.html
new file mode 100644
index 0000000000..7f183f8367
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/radio.html
@@ -0,0 +1,351 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type radio</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<input type=radio name=group1 id=radio1>
+<input type=radio name=group1 id=radio2>
+
+<input type=radio name=groüp2 id=radio3>
+<input type=radio name=groüp2 id=radio4>
+
+<input type=radio id=radio5>
+<input type=radio id=radio6 disabled>
+
+<input type=radio name="group5" id=radio71 checked>
+<input type=radio name="group5" id=radio72>
+
+<input type=radio name=group3 id=radio8 checked>
+<input type=radio name=group3 id=radio9>
+<input type=radio name=group4 id=radio10>
+<input type=radio name=group4 id=radio11 checked>
+
+<form id="testform"></form>
+<input type=radio form=testform name=group6 id=radio12 checked>
+<input type=radio form=testform name=group6 id=radio13>
+<input type=radio form=testform name=group6 id=radio14>
+
+<script>
+ var radio1 = document.getElementById('radio1'),
+ radio2 = document.getElementById('radio2'),
+ radio3 = document.getElementById('radio3'),
+ radio4 = document.getElementById('radio4'),
+ radio5 = document.getElementById('radio5'),
+ radio6 = document.getElementById('radio6'),
+ radio71 = document.getElementById('radio71'),
+ radio72 = document.getElementById('radio72'),
+ radio8 = document.getElementById('radio8'),
+ radio9 = document.getElementById('radio9'),
+ radio10 = document.getElementById('radio10'),
+ radio11 = document.getElementById('radio11'),
+ radio12 = document.getElementById('radio12'),
+ radio13 = document.getElementById('radio13'),
+ radio14 = document.getElementById('radio14'),
+ testform = document.getElementById('testform'),
+ t1 = async_test("click on mutable radio fires click event, then input event, then change event"),
+ t3 = async_test("click on non-mutable radio doesn't fire the input event"),
+ t4 = async_test("click on non-mutable radio doesn't fire the change event"),
+ t5 = async_test("canceled activation steps on unchecked radio"),
+ input_fired = false,
+ change_fired = false;
+
+ test(function(){
+ assert_false(radio1.checked);
+ assert_false(radio2.checked);
+ radio1.checked = true;
+ assert_true(radio1.checked);
+ assert_false(radio2.checked);
+ radio2.checked = true;
+ assert_false(radio1.checked);
+ assert_true(radio2.checked);
+ }, "only one control of a radio button group can have its checkedness set to true");
+
+ test(function(){
+ assert_false(radio3.checked);
+ assert_false(radio4.checked);
+ radio3.checked = true;
+ assert_true(radio3.checked);
+ assert_false(radio4.checked);
+ radio4.checked = true;
+ assert_false(radio3.checked);
+ assert_true(radio4.checked);
+ }, "radio inputs with non-ASCII name attributes belong to the same radio button group");
+
+ test(function(){
+ assert_true(radio8.checked);
+ assert_false(radio9.checked);
+ assert_false(radio10.checked);
+ assert_true(radio11.checked);
+ radio9.name="group4";
+ radio9.checked = true;
+ assert_true(radio8.checked);
+ assert_true(radio9.checked);
+ assert_false(radio10.checked);
+ assert_false(radio11.checked);
+ }, "changing the name of a radio input element and setting its checkedness to true makes all the other elements' checkedness in the same radio button group be set to false");
+
+ test(function(){
+ radio12.remove();
+ assert_true(radio12.checked);
+ assert_false(radio13.checked);
+ assert_false(radio14.checked);
+ radio13.checked = true;
+ assert_true(radio13.checked);
+ assert_false(radio14.checked);
+ radio13.removeAttribute("form");
+ radio14.removeAttribute("form");
+ assert_true(radio13.checked);
+ assert_false(radio14.checked);
+ radio14.checked = true;
+ assert_false(radio13.checked);
+ assert_true(radio14.checked);
+ radio13.setAttribute("form", "testform");
+ radio14.setAttribute("form", "testform");
+ radio13.checked = true;
+ assert_true(radio13.checked);
+ assert_false(radio14.checked);
+ testform.remove();
+ assert_true(radio13.checked);
+ assert_false(radio14.checked);
+ }, "moving radio input element out of or into a form should still work as expected");
+
+ radio5.onclick = t1.step_func(function(e) {
+ click_fired = true;
+ assert_false(input_fired, "click event should fire before input event");
+ assert_false(change_fired, "click event should fire before change event");
+ assert_false(e.isTrusted, "click()-initiated click event shouldn't be trusted");
+ });
+
+ radio5.oninput = t1.step_func(function(e) {
+ input_fired = true;
+ assert_true(click_fired, "input event should fire after click event");
+ assert_false(change_fired, "input event should fire before change event");
+ assert_true(e.bubbles, "input event should bubble")
+ assert_true(e.isTrusted, "input event should be trusted");
+ assert_false(e.cancelable, "input event should not be cancelable");
+ });
+
+ radio5.onchange = t1.step_func(function(e) {
+ change_fired = true;
+ assert_true(click_fired, "change event should fire after click event");
+ assert_true(input_fired, "change event should fire after input event");
+ assert_true(e.bubbles, "change event should bubble")
+ assert_true(e.isTrusted, "change event should be trusted");
+ assert_false(e.cancelable, "change event should not be cancelable");
+ });
+
+ radio6.oninput= t3.step_func_done(function(e) {
+ assert_unreached("event input fired");
+ });
+
+ radio6.onchange = t4.step_func_done(function(e) {
+ assert_unreached("event change fired");
+ });
+
+ t1.step(function() {
+ radio5.click();
+ assert_true(input_fired);
+ t1.done();
+ });
+
+ t3.step(function(){
+ radio6.click();
+ t3.done();
+ t4.done();
+ });
+
+ radio72.onclick = t5.step_func_done(function(e){
+ assert_false(radio71.checked, "click on radio should uncheck other radio in same group");
+ assert_true(radio72.checked, "click on radio should check that radio");
+ e.preventDefault();
+ // The cancelation of the click doesn't have an effect until after all the click event handlers have been run.
+ assert_false(radio71.checked, "radio remains unchecked immediately after click event on other radio in same group is canceled");
+ assert_true(radio72.checked, "clicked radio remains checked immediately after click event is canceled");
+ });
+
+ t5.step(function(){
+ assert_true(radio71.checked, "initially checked radio should be checked");
+ assert_false(radio72.checked, "other radios in same group as initially-checked radio should be unchecked");
+ radio72.click();
+ // Now that the click event has been fully dispatched, its cancelation has taken effect.
+ assert_true(radio71.checked, "canceled click event on radio should leave the previously-checked radio checked");
+ assert_false(radio72.checked, "canceled click event on previously-unchecked radio should leave that radio unchecked");
+ });
+
+ test(() => {
+ const container = document.createElement('div');
+ container.innerHTML =
+ '<input type=radio name=n1><span><input type=radio name=n1 checked></span>' +
+ '<form><input type=radio name=n1 checked></form>';
+ const radios = container.querySelectorAll('input');
+ assert_false(radios[0].checked, 'Sanity check: The first radio should be unchecked');
+ assert_true(radios[1].checked, 'Sanity check: The second radio should be checked');
+ assert_true(radios[2].checked, 'Sanity check: The third radio should be checked');
+
+ radios[0].checked = true;
+ assert_true(radios[0].checked, 'The first radio should be checked after setting checked');
+ assert_false(radios[1].checked, 'The second radio should be unchecked after setting checked');
+ assert_true(radios[2].checked, 'The third radio should be checked after setting checked');
+
+ radios[1].required = true;
+ assert_false(radios[0].validity.valueMissing, 'The first radio should be valid');
+ assert_false(radios[1].validity.valueMissing, 'The second radio should be valid');
+ assert_false(radios[2].validity.valueMissing, 'The third radio should be valid');
+
+ radios[0].remove();
+ assert_false(radios[0].validity.valueMissing, 'The first radio should be valid because of no required');
+ assert_true(radios[1].validity.valueMissing, 'The second radio should be invalid***');
+ assert_false(radios[2].validity.valueMissing, 'The third radio should be valid');
+
+ radios[0].required = true;
+ radios[0].checked = false;
+ assert_true(radios[0].validity.valueMissing, 'The first radio should be invalid because of required');
+ }, 'Radio buttons in an orphan tree should make a group');
+
+ test(() => {
+ const container = document.createElement('div');
+ container.innerHTML =
+ '<form>' +
+ '<input type=radio name=group1 id=radio1 checked>' +
+ '<input type=radio name=group1 id=radio2>' +
+ '</form>' +
+ '<form>' +
+ '<input type=radio name=group1 id=radio3 checked>' +
+ '<input type=radio name=group1 id=radio4>' +
+ '</form>' +
+ '<input type=radio name=group1 id=radio5 checked>' +
+ '<input type=radio name=group1 id=radio6>';
+ const radio1 = container.querySelector('#radio1');
+ const radio2 = container.querySelector('#radio2');
+ const radio3 = container.querySelector('#radio3');
+ const radio4 = container.querySelector('#radio4');
+ const radio5 = container.querySelector('#radio5');
+ const radio6 = container.querySelector('#radio6');
+
+ // initial conditions
+ assert_true(radio1.checked, 'radio1 should be checked');
+ assert_false(radio2.checked, 'radio2 should be unchecked');
+ assert_true(radio3.checked, 'radio3 should be checked');
+ assert_false(radio4.checked, 'radio4 should be unchecked');
+ assert_true(radio5.checked, 'radio5 should be checked');
+ assert_false(radio6.checked, 'radio6 should be unchecked');
+
+ radio2.checked = true;
+ assert_false(radio1.checked, 'radio1 should be unchecked');
+ assert_true(radio2.checked, 'radio2 should be checked');
+ assert_true(radio3.checked, 'radio3 should remain checked');
+ assert_true(radio5.checked, 'radio5 should remain checked');
+
+ radio4.checked = true;
+ assert_false(radio1.checked, 'radio1 should remain unchecked');
+ assert_true(radio2.checked, 'radio2 should remain checked');
+ assert_false(radio3.checked, 'radio3 should be unchecked');
+ assert_true(radio4.checked, 'radio4 should be checked');
+ assert_true(radio5.checked, 'radio5 should remain checked');
+
+ radio6.checked = true;
+ assert_false(radio1.checked, 'radio1 should remain unchecked');
+ assert_true(radio2.checked, 'radio2 should remain checked');
+ assert_false(radio3.checked, 'radio3 should remain unchecked');
+ assert_true(radio4.checked, 'radio4 should remain checked');
+ assert_false(radio5.checked, 'radio5 should be unchecked');
+ assert_true(radio6.checked, 'radio6 should be checked');
+ }, "Radio buttons in different groups (because they have different form owners or no form owner) do not affect each other's checkedness");
+
+ test(() => {
+ const container = document.createElement('div');
+ container.innerHTML =
+ '<form>' +
+ '<input type=radio name=group1 id=radio1 checked>' +
+ '<input type=radio name=group1 id=radio2>' +
+ '<input type=radio name=group1 id=radio3>' +
+ '<input type=radio name=group1 id=radio4>' +
+ '</form>';
+ const radio1 = container.querySelector('#radio1');
+ const radio2 = container.querySelector('#radio2');
+ const radio3 = container.querySelector('#radio3');
+ const radio4 = container.querySelector('#radio4');
+
+ // initial conditions
+ assert_true(radio1.checked, 'radio1 should be checked');
+ assert_false(radio2.checked, 'radio2 should be unchecked');
+ assert_false(radio3.checked, 'radio3 should be unchecked');
+ assert_false(radio4.checked, 'radio4 should be unchecked');
+
+ radio3.remove();
+ radio4.remove();
+ radio3.checked = true;
+ radio4.checked = true;
+ assert_true(radio1.checked, 'radio1 should remain checked');
+ assert_false(radio2.checked, 'radio2 should remain unchecked');
+ assert_true(radio3.checked, 'radio3 should be checked');
+ assert_true(radio4.checked, 'radio4 should be checked');
+ }, "Radio buttons in different groups (because they are not in the same tree) do not affect each other's checkedness");
+
+ test(() => {
+ const container = document.createElement('div');
+ container.innerHTML =
+ '<form>' +
+ '<input type=radio name=group1 id=radio1 checked>' +
+ '<input type=radio name=group1 id=radio2>' +
+ '<input type=radio name=group2 id=radio3 checked>' +
+ '<input type=radio name=group2 id=radio4>' +
+ '<input type=radio name="" id=radio5 checked>' +
+ '<input type=radio name="" id=radio6>' +
+ '<input type=radio id=radio7 checked>' +
+ '<input type=radio id=radio8>' +
+ '</form>';
+ const radio1 = container.querySelector('#radio1');
+ const radio2 = container.querySelector('#radio2');
+ const radio3 = container.querySelector('#radio3');
+ const radio4 = container.querySelector('#radio4');
+ const radio5 = container.querySelector('#radio5');
+ const radio6 = container.querySelector('#radio6');
+ const radio7 = container.querySelector('#radio7');
+ const radio8 = container.querySelector('#radio8');
+
+ // initial conditions
+ assert_true(radio1.checked, 'radio1 should be checked');
+ assert_false(radio2.checked, 'radio2 should be unchecked');
+ assert_true(radio3.checked, 'radio3 should be checked');
+ assert_false(radio4.checked, 'radio4 should be unchecked');
+ assert_true(radio5.checked, 'radio5 should be checked');
+ assert_false(radio6.checked, 'radio6 should be unchecked');
+ assert_true(radio7.checked, 'radio7 should be checked');
+ assert_false(radio8.checked, 'radio8 should be unchecked');
+
+ radio2.checked = true;
+ assert_false(radio1.checked, 'radio1 should be unchecked');
+ assert_true(radio2.checked, 'radio2 should be checked');
+ assert_true(radio3.checked, 'radio3 should remain checked');
+ assert_false(radio4.checked, 'radio4 should remain unchecked');
+ assert_true(radio5.checked, 'radio5 should remain checked');
+ assert_false(radio6.checked, 'radio6 should remain unchecked');
+ assert_true(radio7.checked, 'radio7 should remain checked');
+ assert_false(radio8.checked, 'radio8 should remain unchecked');
+
+ radio6.checked = true;
+ assert_false(radio1.checked, 'radio1 should remain unchecked');
+ assert_true(radio2.checked, 'radio2 should remain checked');
+ assert_true(radio3.checked, 'radio3 should remain checked');
+ assert_false(radio4.checked, 'radio4 should remain unchecked');
+ assert_true(radio5.checked, 'radio5 should remain checked');
+ assert_true(radio6.checked, 'radio6 should be checked');
+ assert_true(radio7.checked, 'radio7 should remain checked');
+
+ radio8.checked = true;
+ assert_false(radio1.checked, 'radio1 should remain unchecked');
+ assert_true(radio2.checked, 'radio2 should remain checked');
+ assert_true(radio3.checked, 'radio3 should remain checked');
+ assert_false(radio4.checked, 'radio4 should remain unchecked');
+ assert_true(radio5.checked, 'radio5 should remain checked');
+ assert_true(radio6.checked, 'radio6 should remain checked');
+ assert_true(radio7.checked, 'radio7 should remain checked');
+ assert_true(radio8.checked, 'radio8 should be checked');
+
+ }, "Radio buttons in different groups (because they have different name attribute values, or no name attribute) do not affect each other's checkedness");
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-2.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-2.html
new file mode 100644
index 0000000000..3277dfc07f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-2.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>range input Tests</title>
+<link rel="author" title="Microsoft" href="http://www.microsoft.com" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<input type="range" id="r00" min="0" max="100" step="20" value="40" style="display:none">
+<input type="range" id="r01" min="0" max="1" step=".1" value=".2" style="display:none">
+<input type="range" id="r02" style="display:none">
+<input type="range" id="r03" style="display:none">
+<input type="range" id="r04" style="display:none">
+
+<script>
+test(function rangeElementTest0() {
+ document.getElementById('r00').value = "";
+ assert_equals(document.getElementById('r00').type, "range");
+ assert_equals(document.getElementById('r00').value, "60");
+}, "range input value set to ''");
+
+test(function rangeElementTest1() {
+ document.getElementById('r01').value = .6;
+ assert_equals(document.getElementById('r01').type, "range");
+ assert_equals(document.getElementById('r01').value, "0.6");
+}, "range input value set to an integer");
+
+test(function rangeElementTest2() {
+ assert_equals(document.getElementById('r02').type, "range");
+ assert_equals(document.getElementById('r02').value, "50");
+}, "range input value equals 50");
+
+test(function rangeElementTest3() {
+ document.getElementById('r03').value = 200;
+ assert_equals(document.getElementById('r03').type, "range");
+ assert_equals(document.getElementById('r03').value, "100");
+}, "range input value equals 100");
+
+test(function rangeElementTest4() {
+ document.getElementById('r04').value = 2.1;
+ assert_equals(document.getElementById('r04').type, "range");
+ assert_equals(document.getElementById('r04').value, "2");
+}, "range input value equals 2");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size-ref.html
new file mode 100644
index 0000000000..48beaea3f6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size-ref.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+ <meta charset="utf-8">
+ <title>Reference: type=range intrinsic size</title>
+ <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1512066">
+ <style>
+html,body {
+ color:black; background-color:white; font:16px/1 monospace;
+}
+
+.flex {
+ display: inline-flex;
+ width: 0;
+ border: 1px solid;
+ justify-items:start;
+}
+.flex2 {
+ display: inline-flex;
+ border: 1px solid;
+ justify-items:start;
+}
+.grid {
+ display: inline-grid;
+ grid: auto / 0;
+ border: 1px solid;
+ justify-items:start;
+}
+.grid2 {
+ display: inline-grid;
+ border: 1px solid;
+ justify-items:start;
+}
+.ib {
+ display: inline-block;
+ width: 0;
+ border: 1px solid;
+ justify-items:start;
+}
+
+input {
+ width: max-content;
+ min-width: 0;
+}
+input.min {
+ min-width: min-content;
+}
+input.mbp0 {
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0;
+ border: 0;
+}
+ </style>
+</head>
+<body>
+
+<div class="flex"><input type="range" class="min"></div><br>
+<div class="flex"><input type="range" style="width:0"></div><br>
+<div class="flex"><input type="range" class="min"></div><br>
+<div class="flex"><input type="range" class="min"></div><br>
+<div class="flex"><input type="range" class="min"></div><br>
+<br>
+
+<div class="flex2"><input type="range"></div>
+<div class="flex2" style="width:3px"><input type="range" style="width:3px" class="mbp0"></div>
+<div class="flex2" style="width:30px"><input type="range" class="mbp0"></div>
+<div class="flex2"><input type="range"></div>
+<div class="flex2"><input type="range"></div>
+<div class="flex2"><input type="range"></div>
+<div class="flex2"><input type="range"></div>
+<br>
+
+<div class="grid"><input type="range" style="width:0"></div><br>
+<div class="grid"><input type="range" style="width:0"></div><br>
+<div class="grid" style="justify-items:start"><input type="range"></div><br>
+
+<div class="grid2"><input type="range"></div>
+<div class="grid2"><input type="range" style="min-width:0"></div>
+<div class="grid2" style="width:3px"><input type="range" style="width:3px" class="mbp0"></div>
+<div class="flex2" style="width:30px"><input type="range" class="mbp0"></div>
+<div class="flex2" style="width:30px"><input type="range" class="mbp0"></div>
+<div class="grid2" style="justify-items:start"><input type="range"></div>
+
+<br>
+
+<div class="ib"><input type="range"></div><br>
+<div class="ib"><input type="range"></div><br>
+
+<input type="range">
+<input type="range"
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size.html
new file mode 100644
index 0000000000..ce37faf89b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-intrinsic-size.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+ <meta charset="utf-8">
+ <title>Test: type=range intrinsic size</title>
+ <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1512066">
+ <link rel="match" href="range-intrinsic-size-ref.html">
+ <style>
+html,body {
+ color:black; background-color:white; font:16px/1 monospace;
+}
+
+.flex {
+ display: inline-flex;
+ width: 0;
+ border: 1px solid;
+}
+.flex2 {
+ display: inline-flex;
+ border: 1px solid;
+}
+.grid {
+ display: inline-grid;
+ grid: auto / 0;
+ border: 1px solid;
+}
+.grid2 {
+ display: inline-grid;
+ border: 1px solid;
+}
+.ib {
+ display: inline-block;
+ width: 0;
+ border: 1px solid;
+}
+input.mbp0 {
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0;
+ border: 0;
+}
+ </style>
+</head>
+<body>
+
+<div class="flex"><input type="range"></div><br>
+<div class="flex"><input type="range" style="min-width:0"></div><br>
+<div class="flex" style="justify-items:start"><input type="range"></div><br>
+<div class="flex" style="-webkit-box-pack: start"><input type="range"></div><br>
+<div class="flex" style="-webkit-box-pack: start; justify-content: flex-start;"><input type="range"></div><br>
+<br>
+
+<div class="flex2"><input type="range"></div>
+<div class="flex2" style="width:3px"><input type="range" style="min-width:0" class="mbp0"></div>
+<div class="flex2" style="width:30px"><input type="range" style="min-width:0" class="mbp0"></div>
+<div class="flex2"><input type="range" style="min-width:0"></div>
+<div class="flex2" style="justify-items:start"><input type="range"></div>
+<div class="flex2" style="-webkit-box-pack: start"><input type="range"></div>
+<div class="flex2" style="-webkit-box-pack: start; justify-content: flex-start;"><input type="range"></div>
+<br>
+
+<div class="grid"><input type="range"></div><br>
+<div class="grid"><input type="range" style="min-width:0"></div><br>
+<div class="grid" style="justify-items:start"><input type="range"></div><br>
+
+<div class="grid2"><input type="range"></div>
+<div class="grid2"><input type="range" style="min-width:0"></div>
+<div class="grid2" style="width:3px"><input type="range" style="min-width:0" class="mbp0"></div>
+<div class="grid2" style="width:30px"><input type="range" style="min-width:0" class="mbp0"></div>
+<div class="grid2" style="grid:auto/30px"><input type="range" class="mbp0"></div>
+<div class="grid2" style="justify-items:start"><input type="range"></div>
+
+<br>
+
+<div class="ib"><input type="range"></div><br>
+<div class="ib"><input type="range" style="min-width:0"></div><br>
+
+<input type="range" style="width:min-content;">
+<input type="range" style="width:max-content;">
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-added-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-added-repaint.html
new file mode 100644
index 0000000000..344f36527b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-added-repaint.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if a list ID is added</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5>
+<datalist id=tickmarks>
+ <option value=4>
+ <option value=-2>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ document.querySelector("input[type=range]").setAttribute("list", "tickmarks");
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-change-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-change-repaint.html
new file mode 100644
index 0000000000..b5bee03b3b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-change-repaint.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if its list attribute changes</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=firstlist>
+<datalist id=firstlist>
+ <option value=1></option>
+ <option value=-5></option>
+</datalist>
+<datalist id=secondlist>
+ <option value=-2>
+ <option value=4>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ const range = document.querySelector("input[type=range]");
+ range.setAttribute("list", "secondlist");
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-duplicate-id-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-duplicate-id-repaint.html
new file mode 100644
index 0000000000..0a2a90b500
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-duplicate-id-repaint.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if the ID identifies a different list</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=firstlist>
+<datalist id=firstlist>
+ <option value=1></option>
+ <option value=-5></option>
+</datalist>
+<datalist id=secondlist>
+ <option value=4>
+ <option value=-2>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ const firstList = document.querySelector("datalist#firstlist");
+ const secondList = document.querySelector("datalist#secondlist");
+ secondList.id = "firstlist";
+ firstList.parentNode.insertBefore(secondList, firstList);
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-nonexistent.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-nonexistent.html
new file mode 100644
index 0000000000..72fb19b9c8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-list-nonexistent.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if the ID first identifies no list, then a list takes on that ID</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=nonexistentlist>
+<datalist>
+ <option value=4>
+ <option value=-2>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ const dataListWithIDOfNonExistentList = document.querySelector("datalist");
+ dataListWithIDOfNonExistentList.id = "nonexistentlist";
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-add-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-add-repaint.html
new file mode 100644
index 0000000000..31631b0c59
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-add-repaint.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if an option is added to the range's list</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=tickmarks>
+<datalist id=tickmarks>
+ <option value=4></option>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ const dataList = document.querySelector("datalist");
+ const toAdd = document.createElement("option");
+ toAdd.value = -2;
+ dataList.appendChild(toAdd);
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-remove-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-remove-repaint.html
new file mode 100644
index 0000000000..672e371bfb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-remove-repaint.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if an option is removed from the range's list</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=tickmarks>
+<datalist id=tickmarks>
+ <option value=-2></option>
+ <option value=1 id=to-remove></option>
+ <option value=4></option>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ document.querySelector("option#to-remove").remove();
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-value-change-repaint.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-value-change-repaint.html
new file mode 100644
index 0000000000..7dcace4e47
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-option-value-change-repaint.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html class=reftest-wait>
+<title>The range is repainted if the value of an option in the range's list changes</title>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1805105">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<script src=/common/reftest-wait.js></script>
+<input type=range step=3 value=1 min=-5 max=5 list=tickmarks>
+<datalist id=tickmarks>
+ <option value=-2></option>
+ <option value=1 id=to-change></option>
+</datalist>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ const toChange = document.querySelector("option#to-change");
+ toChange.value = 4;
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html
new file mode 100644
index 0000000000..f73c5e6f63
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-restore-oninput-onchange-event.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/pull/7283">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1266468">
+
+<link rel=author href="mailto:gulukesh@gmail.com">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1131234">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+function runTest(type, testValue) {
+ promise_test(async () => {
+ const w = window.open(`resources/${type}-restore-events.html`);
+ // Unfortunately, navigating |w| doesn't fire load events in this parent
+ // window, so we have to make the child window manually tell this parent
+ // window when it has loaded.
+ await new Promise(resolve => window.loadResolver = resolve);
+ // We can't navigate the child window until after a setTimeout.
+ await new Promise(resolve => step_timeout(resolve, 0));
+
+ assert_not_equals(
+ w.document.querySelector('input').value,
+ testValue,
+ `Test shouldn't start with the new value already in the input.`);
+ w.document.querySelector('input').value = testValue;
+
+ w.location.href = 'resources/loadresolver.html';
+ await new Promise(resolve => window.loadResolver = resolve);
+
+ w.history.back();
+ await new Promise(resolve => window.loadResolver = resolve);
+ // The value doesn't get restored until after a setTimeout.
+ await new Promise(resolve => step_timeout(resolve, 0));
+
+ assert_equals(w.document.querySelector('input').value, testValue,
+ 'The input should have its value restored.');
+
+ assert_false(w.seeninput || false,
+ 'The input event should not have been fired after restoration.');
+ assert_false(w.seenchange || false,
+ 'The change event should not have been fired after restoration.');
+
+ w.close();
+ }, `Verifies that form restoration does not fire input or change events for <input type=${type}>.`);
+}
+
+runTest('range', '8');
+runTest('text', 'foo');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value-ref.html
new file mode 100644
index 0000000000..71a44cdf2f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>range input element setAttribute value appearance</title>
+
+<p>Test passes if the range element below visually has its slider at 2/10 from the left</p>
+
+<input type=range min=0 max=10 value=2></input>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value.html
new file mode 100644
index 0000000000..3a03a5b6fe
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-setattribute-value.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#the-input-element">
+<link rel="match" href="range-setattribute-value-ref.html">
+<title>range input element setAttribute value appearance</title>
+
+<p>Test passes if the range element below visually has its slider at 2/10 from the left</p>
+
+<script>
+window.onload = () => {
+
+ const input = document.createElement('input');
+ input.type = 'range';
+ input.min = 0;
+ input.max = 10;
+ document.body.appendChild(input);
+
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ input.setAttribute('value', 2);
+ document.documentElement.classList.remove('reftest-wait');
+ });
+ });
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01-notref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01-notref.html
new file mode 100644
index 0000000000..58192bec8e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01-notref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<title>LTR range input with datalist reference</title>
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01.html
new file mode 100644
index 0000000000..225422dc4d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-01.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>LTR range input with datalist</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841942">
+<link rel="author" href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel="mismatch" href="range-tick-marks-01-notref.html">
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="0">
+ <option value="-30">
+ <option value="30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02-ref.html
new file mode 100644
index 0000000000..3d5b323470
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02-ref.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>RTL range input with datalist reference</title>
+<style>
+ input[type=range] {
+ transform: scaleX(-1);
+ }
+</style>
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="0">
+ <option value="-30">
+ <option value="30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02.html
new file mode 100644
index 0000000000..453e650b2f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-02.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>RTL range input with datalist</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#attr-dir-rtl">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841942">
+<link rel="author" href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel="match" href="range-tick-marks-02-ref.html">
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers" dir="rtl">
+<datalist id="powers">
+ <option value="0">
+ <option value="-30">
+ <option value="30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03-notref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03-notref.html
new file mode 100644
index 0000000000..5c15233a31
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03-notref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>max and min attributes applied to range input with datalist reference</title>
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="0">
+ <option value="-30">
+ <option value="30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03.html
new file mode 100644
index 0000000000..e067013bdd
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-03.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>max and min attributes applied to range input with datalist</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841942">
+<link rel="author" href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel="mismatch" href="range-tick-marks-03-notref.html">
+<input type="range" min="-40" max="40" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="0">
+ <option value="-30">
+ <option value="30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04-ref.html
new file mode 100644
index 0000000000..a6afaff7ee
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>no range tick marks for disabled datalist elements reference</title>
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="-30">
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04.html
new file mode 100644
index 0000000000..6fb0e930a1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-04.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>no range tick marks for disabled datalist elements</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-elements.html#htmldatalistelement">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-disabled">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841942">
+<link rel="author" href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel="match" href="range-tick-marks-04-ref.html">
+<input type="range" min="-100" max="100" value="0" step="10" name="power" list="powers">
+<datalist id="powers">
+ <option value="0" disabled>
+ <option value="-30">
+ <option value="30" disabled>
+ <option value="50">
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05-ref.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05-ref.html
new file mode 100644
index 0000000000..f144af3880
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>no range tick marks for range tick marks that are step mismatches reference</title>
+<input type=range step=3 value=1 min=-5 max=5 list=degrees>
+<datalist id=degrees>
+ <option value=-2>
+ <option value=4>
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05.html
new file mode 100644
index 0000000000..a65c7b7946
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range-tick-marks-05.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>no range tick marks for range tick marks that are step mismatches</title>
+<link rel=help href="https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range)">
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1803303">
+<link rel=author href="mailto:zach@zrhoffman.net" title="Zach Hoffman">
+<link rel=match href=range-tick-marks-05-ref.html>
+<input type=range step=3 value=1 min=-5 max=5 list=degrees>
+<datalist id=degrees>
+ <option value=-4>
+ <option value=-2>
+ <option value=0>
+ <option value=2>
+ <option value=4>
+</datalist>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/range.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/range.html
new file mode 100644
index 0000000000..27cc6abe9c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/range.html
@@ -0,0 +1,245 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <title>Input Range</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+ <link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+ <link rel="author" title="Tomoyuki SHIMIZU" href="mailto:tomoyuki.labs@gmail.com">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-type">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-min">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-max">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#range-state-(type=range)">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepup">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-stepdown">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+
+
+ <h1>Input Range</h1>
+ <div style="display:none">
+ <input type="range" id="range_basic" min=0 max=5 />
+ <input type="range" id="value_smaller_than_min" min=0 max=5 value=-10 />
+ <input type="range" id="value_larger_than_max" min=0 max=5 value=7 />
+ <input type="range" id="empty_attributes" />
+ <input type="range" id="value_not_specified" min=2 max=6 />
+ <input type="range" id="control_step_mismatch" min=0 max=7 step=2 />
+ <input type="range" id="max_smaller_than_min" min=2 max=-3 />
+ <input type="range" id="default_step_scale_factor_1" min=5 max=12.6 value=6.7 />
+ <input type="range" id="default_step_scale_factor_2" min=5.3 max=12 value=6.7 />
+ <input type="range" id="float_step_scale_factor" min=5.3 max=12 step=0.5 value=6.7 />
+ <input type="range" id="stepup" min=3 max=14 value=6 step=3 />
+ <input type="range" id="stepdown" min=3 max=11 value=9 step=3 />
+ <input type="range" id="stepup_beyond_max" min=3 max=14 value=9 step=3 />
+ <input type="range" id="stepdown_beyond_min" min=3 max=11 value=6 step=3 />
+ <input type="range" id="illegal_min_and_max" min="ab" max="f" />
+ <input type="range" id="illegal_value_and_step" min=0 max=5 value="ppp" step="xyz" />
+ <input type="range" id="should_skip_whitespace" value=" 123"/>
+ <input type="range" id="exponent_value1" value=""/>
+ <input type="range" id="exponent_value2" value=""/>
+ </div>
+
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+
+ test(
+ function() {
+ assert_equals(document.getElementById('range_basic').type, "range");
+ },
+ "range type support on input element"
+ );
+
+ test(function() {
+ assert_equals(getComputedStyle(document.getElementById('range_basic')).overflow, "visible");
+ }, "range overflow styles");
+
+ test(
+ function() {
+ assert_equals(document.getElementById('range_basic').min, "0")
+ },
+ "min attribute support on input element"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('range_basic').max, "5")
+ },
+ "max attribute support on input element"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('illegal_min_and_max').min, "ab")
+ },
+ "Illegal value of min attribute"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('illegal_min_and_max').max, "f")
+ },
+ "Illegal value of max attribute"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('illegal_value_and_step').value, "3")
+ },
+ "Converting an illegal string to the default value"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('illegal_value_and_step').step, "xyz")
+ },
+ "Illegal value of step attribute"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('value_smaller_than_min').value, "0")
+ },
+ "the value is set to min when a smaller value than min attribute is given"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('value_larger_than_max').value, "5")
+ },
+ "the value is set to max when a larger value than max attribute is given"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('empty_attributes').min, "")
+ },
+ "default value of min attribute in input type=range"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('empty_attributes').max, "")
+ },
+ "default value of max attribute in input type=range"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('value_not_specified').value, "4")
+ },
+ "default value when min and max attributes are given (= min plus half the difference between min and max)"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('control_step_mismatch').value, "4")
+ },
+ "default value with step control when both min and max attributes are given"
+ );
+
+ // Chrome would result in different value out of the range between min and max. Why?
+ test(
+ function() {
+ assert_equals(document.getElementById('max_smaller_than_min').value, "2")
+ },
+ "default value when both min and max attributes are given, while min > max"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('default_step_scale_factor_1').value, "7")
+ },
+ "The default step scale factor is 1, unless min attribute has non-integer value"
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('default_step_scale_factor_2').value, "6.3")
+ },
+ "Step scale factor behavior when min attribute has integer value but max attribute is non-integer "
+ );
+
+ test(
+ function() {
+ assert_equals(document.getElementById('float_step_scale_factor').value, "6.8")
+ },
+ "Solving the step mismatch"
+ );
+
+ // Firefox Nightly (24.0a1) would result in the possible maximum value in this range... (i.e. 12)
+ test(
+ function() {
+ var e = document.getElementById('stepup');
+ e.stepUp();
+ assert_equals(e.value, "9")
+ },
+ "Performing stepUp()"
+ );
+
+ // Firefox Nightly (24.0a1) would result in the possible minimum value in this range... (i.e. 3)
+ test(
+ function() {
+ var e = document.getElementById('stepdown');
+ e.stepDown();
+ assert_equals(e.value, "6")
+ },
+ "Performing stepDown()"
+ );
+
+ // Chrome and Opera would throw DOM Exception 11 (InvalidStateError)
+ // Firefox Nightly gives the correct result
+ test(
+ function() {
+ var e = document.getElementById('stepup_beyond_max');
+ e.stepUp(2);
+ assert_equals(e.value, "12")
+ },
+ "Performing stepUp() beyond the value of the max attribute"
+ );
+
+ // Chrome and Opera would throw DOM Exception 11 (InvalidStateError)
+ // Firefox Nightly gives the correct result
+ test(
+ function() {
+ var e = document.getElementById('stepdown_beyond_min');
+ e.stepDown(2);
+ assert_equals(e.value, "3")
+ }, "Performing stepDown() beyond the value of the min attribute"
+ );
+
+ test(
+ function() {
+ var e = document.getElementById('should_skip_whitespace');
+ assert_equals(e.value, "50")
+ }, "Input should be reset to the default value when value attribute has whitespace"
+ );
+
+ test(
+ function() {
+ var e = document.getElementById('exponent_value1');
+ e.value = 1e2;
+ assert_equals(e.value, "100")
+ }, "Multiply value by ten raised to the exponentth power with `e`"
+ );
+
+ test(
+ function() {
+ var e = document.getElementById('exponent_value2');
+ e.value = 1E2;
+ assert_equals(e.value, "100")
+ }, "Multiply value by ten raised to the exponentth power with `E`"
+ );
+
+ </script>
+
+ </body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/required_attribute.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/required_attribute.html
new file mode 100644
index 0000000000..63488e9f4c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/required_attribute.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <title>Required Attribute</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+ <link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#attr-input-required">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+
+
+ <h1>Required Attribute</h1>
+ <div style="display: none">
+ <input type="text" required="required" />
+ </div>
+
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+
+
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].getAttribute("required"), "required")}, "required attribute support on input element");
+
+ </script>
+
+ </body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/reset.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/reset.html
new file mode 100644
index 0000000000..9a97995426
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/reset.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>input type reset</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#reset-button-state-(type=reset)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<form>
+ <input type=text id=input1 value="foobar">
+ <input type=text id=input2>
+ <input type=reset id=r1>
+</form>
+
+<input type=text id=input3 value="barfoo">
+
+<table>
+ <form>
+ <tr>
+ <td>
+ <input type=text id=input4 value="foobar">
+ <input type=reset id=r2>
+ </td>
+ </tr>
+ </form>
+</table>
+
+<div>
+ <form>
+ <input type=text id=input5 value="foobar">
+ </div>
+ <input type=reset id=r3>
+</form>
+
+<div>
+ <form>
+ <input type=reset id=r4>
+ </div>
+ <input type=text id=input6 value="foobar">
+</form>
+
+<form id=form5>
+ <input type=reset id=r5>
+</form>
+<input form=form5 type=text id=input7 value="foobar">
+
+<form id=form6>
+ <input type=text id=input8 value="foobar">
+</form>
+<input type=reset form=form6 id=r6>
+
+<script>
+ var input1 = document.getElementById('input1'),
+ input2 = document.getElementById('input2'),
+ input3 = document.getElementById('input3'),
+ input7 = document.getElementById('input7'),
+ input8 = document.getElementById('input8'),
+ r1 = document.getElementById('r1');
+
+ test(function(){
+ assert_equals(input1.value, "foobar");
+ assert_equals(input2.value, "");
+ assert_equals(input3.value, "barfoo");
+ input1.value = "foobar1";
+ input2.value = "notempty";
+ input3.value = "barfoo1";
+ assert_equals(input1.value, "foobar1");
+ assert_equals(input2.value, "notempty");
+ assert_equals(input3.value, "barfoo1");
+ r1.click();
+ assert_equals(input1.value, "foobar");
+ assert_equals(input2.value, "");
+ assert_equals(input3.value, "barfoo1");
+ }, "reset button only resets the form owner");
+
+ test(function(){
+ assert_false(r1.willValidate);
+ }, "the element is barred from constraint validation");
+
+ test(function(){
+ assert_equals(input1.value, "foobar");
+ assert_equals(input2.value, "");
+ assert_equals(input3.value, "barfoo1");
+ r1.disabled = true;
+ r1.click();
+ assert_equals(input1.value, "foobar");
+ assert_equals(input2.value, "");
+ assert_equals(input3.value, "barfoo1");
+ }, "clicking on a disabled reset does nothing");
+
+ function testReset(inputId, buttonId) {
+ var inp = document.getElementById(inputId);
+ assert_equals(inp.value, "foobar");
+ inp.value = "barfoo";
+ assert_equals(inp.value, "barfoo");
+ document.getElementById(buttonId).click();
+ assert_equals(inp.value, "foobar");
+ }
+
+ test(function(){
+ testReset("input4", "r2");
+ testReset("input5", "r3");
+ testReset("input6", "r4");
+ }, "reset button resets controls associated with their form using the form element pointer");
+
+ test(function(){
+ testReset("input7", "r5");
+ }, "reset button resets controls associated with a form using the form attribute");
+
+ test(function(){
+ testReset("input8", "r6");
+ }, "reset button associated with a form using the form attribute resets all the form's controls");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/image-submit-click.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/image-submit-click.html
new file mode 100644
index 0000000000..8461a03d7a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/image-submit-click.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<form>
+ <input type="image" name="name" value="value">
+</form>
+
+<script>
+"use strict";
+if (window.location.search.startsWith("?name.x")) {
+ // The action pointed to ourself, so the form submitted something
+ window.parent.success(window.location.href);
+} else {
+ const input = document.querySelector("input");
+ input.click();
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/loadresolver.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/loadresolver.html
new file mode 100644
index 0000000000..14379dd922
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/loadresolver.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+ window.onload = () => {
+ window.opener.loadResolver();
+ };
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html
new file mode 100644
index 0000000000..27044c3537
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+ window.onload = () => {
+ const loadResolver = window.opener.loadResolver;
+ if (loadResolver)
+ loadResolver();
+ };
+</script>
+<input type=range min=0 max=10 value=5>
+<script>
+ const input = document.querySelector('input');
+ input.onchange = () => window.seenchange = true;
+ input.oninput = () => window.seeninput = true;
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers
new file mode 100644
index 0000000000..4030ea1d3d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/range-restore-events.html.headers
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/show-picker-child-iframe.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/show-picker-child-iframe.html
new file mode 100644
index 0000000000..07b72f02cb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/show-picker-child-iframe.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Test showPicker() in an iframe</title>
+<script type=module>
+import inputTypes from "./../input-types.js";
+
+const urlParams = new URLSearchParams(location.search);
+const documentDomain = urlParams.get('documentDomain');
+if (documentDomain) {
+ document.domain = documentDomain;
+}
+
+let securityErrors = [];
+for (const inputType of inputTypes) {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+
+ try {
+ input.showPicker();
+ } catch (error) {
+ if (error instanceof DOMException && error.name == 'SecurityError') {
+ securityErrors.push(inputType);
+ }
+ }
+}
+parent.postMessage(securityErrors.join(','), "*");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html
new file mode 100644
index 0000000000..aa57bdebcc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+ window.onload = () => {
+ const loadResolver = window.opener.loadResolver;
+ if (loadResolver)
+ loadResolver();
+ };
+</script>
+<input type=text value=initialValue>
+<script>
+ const input = document.querySelector('input');
+ input.onchange = () => window.seenchange = true;
+ input.oninput = () => window.seeninput = true;
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers
new file mode 100644
index 0000000000..4030ea1d3d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/resources/text-restore-events.html.headers
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/search_input.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/search_input.html
new file mode 100644
index 0000000000..7b63cd43e1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/search_input.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <title>Search Input</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="author" title="Fabrice Clari" href="mailto:f.clari@inno-group.com">
+ <link rel="author" title="Dimitri Bocquet" href="mailto:Dimitri.Bocquet@mosquito-fp7.eu">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-type">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-input-placeholder">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+
+
+ <h1>Search Input</h1>
+ <input type="search" style="display:none" placeholder="Search..." />
+
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+
+
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].type, "search")}, "search type support on input element");
+ test(function() {assert_equals(document.getElementsByTagName("input")[0].placeholder, "Search...")}, "placeholder attribute support on input element");
+
+ </script>
+
+ </body>
+
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-pointer.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-pointer.html
new file mode 100644
index 0000000000..7f06ae24a2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-pointer.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Selecting texts across input element</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<link rel="stylesheet" href="/fonts/ahem.css" />
+
+<style>
+ .test {
+ font: 16px/1 Ahem;
+ padding-bottom: 16px;
+ }
+</style>
+<div class="test">
+ <span id="foo">foo</span><br>
+ <input id="input"><br>
+ <span id="bar">bar</span>
+</div>
+<script type="module">
+import inputTypes from "./input-types.js";
+
+const selection = getSelection();
+const inputVisibleTypes = inputTypes.filter(t => t !== "hidden");
+
+for (const inputType of inputVisibleTypes) {
+ promise_test(async () => {
+ input.type = inputType;
+ selection.collapse(foo);
+ await new test_driver.Actions()
+ .pointerMove(0, 0, {origin: foo})
+ .pointerDown()
+ .pointerMove(0, 0, {origin: input})
+ .pointerMove(0, 0, {origin: bar})
+ .pointerUp()
+ .send();
+ const nRanges = selection.rangeCount;
+ assert_true(nRanges > 0);
+ const expectedStart = foo.childNodes[0];
+ const expectedEnd = bar.childNodes[0];
+ if (nRanges === 1) {
+ assert_equals(selection.anchorNode, expectedStart, "anchorNode");
+ assert_equals(selection.focusNode, expectedEnd, "focusNode");
+ } else {
+ // In case multiple ranges are supported, make sure the set of ranges
+ // spans the full selection, across the input.
+ const ranges = [...Array(nRanges).keys()].map(n => selection.getRangeAt(n));
+ assert_true(ranges.some(r => r.startContainer === expectedStart),"startContainer");
+ assert_true(ranges.some(r => r.endContainer === expectedEnd),"endContainer");
+ }
+ }, `Selecting texts across <input type=${inputType}> should not cancel selection`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-weekmonth.html
new file mode 100644
index 0000000000..c0d36dded9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection-weekmonth.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<title>Input element programmatic selection support</title>
+<link rel="author" title="yaycmyk" href="mailto:evan@yaycmyk.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-textarea/input-select">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+/* all textual, non-hidden inputs support .select() */
+test(function() {
+ var valid = [
+ "month",
+ "week",
+ ];
+
+ valid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+ var a;
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ input.select();
+
+ }, "input type " + type + " should support the select() method");
+ });
+});
+
+/* only certain input types are allowed to have a variable-length selection */
+test(function() {
+ var invalid = [
+ "month",
+ "week",
+ ];
+
+ invalid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ assert_equals(input.selectionStart, null, 'getting input.selectionStart');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionStart = 0; });
+ assert_equals(input.selectionEnd, null, 'getting input.selectionEnd');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionEnd = 0; });
+ assert_equals(input.selectionDirection, null, 'getting input.selectionDirection');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionDirection = "none"; });
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.setSelectionRange(0, 0); });
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.setRangeText('', 0, 0); });
+
+ }, "input type " + type + " should not support variable-length selections");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/selection.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection.html
new file mode 100644
index 0000000000..1f5c8378ff
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/selection.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML>
+<title>Input element programmatic selection support</title>
+<link rel="author" title="yaycmyk" href="mailto:evan@yaycmyk.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-textarea/input-select">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+/* all textual, non-hidden inputs support .select() */
+test(function() {
+ var valid = [
+ "text",
+ "search",
+ "url",
+ "tel",
+ "email",
+ "password",
+ "date",
+ "time",
+ "datetime-local",
+ "number",
+ "color",
+ "file",
+ ];
+
+ var invalid = [
+ "hidden",
+ "range",
+ "checkbox",
+ "radio",
+ "submit",
+ "image",
+ "reset",
+ "button"
+ ];
+
+ valid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+ var a;
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ input.select();
+
+ }, "input type " + type + " should support the select() method");
+ });
+
+ invalid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ var selectionStartBefore = input.selectionStart;
+ var selectionEndBefore = input.selectionEnd;
+ var selectionDirectionBefore = input.selectionDirection;
+
+ // Does not throw; see https://github.com/whatwg/html/issues/2275
+ input.select();
+
+ assert_equals(input.selectionStart, selectionStartBefore, "selectionStart must not change");
+ assert_equals(input.selectionEnd, selectionEndBefore, "selectionEnd must not change");
+ assert_equals(input.selectionDirection, selectionDirectionBefore, "selectionDirection must not change");
+
+ }, "input type " + type + " should do nothing when the select() method is called (but, not throw)");
+ });
+});
+
+/* only certain input types are allowed to have a variable-length selection */
+test(function() {
+ var valid = [
+ "text",
+ "search",
+ "url",
+ "tel",
+ "password"
+ ];
+
+ var invalid = [
+ "hidden",
+ "email",
+ "date",
+ "time",
+ "datetime-local",
+ "number",
+ "range",
+ "color",
+ "checkbox",
+ "radio",
+ "file",
+ "submit",
+ "image",
+ "reset",
+ "button"
+ ];
+
+ valid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+ var a;
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ a = input.selectionStart;
+ input.selectionStart = 0;
+ a = input.selectionEnd;
+ input.selectionEnd = 0;
+ a = input.selectionDirection;
+ input.selectionDirection = "none";
+ input.setSelectionRange(0, 0);
+ input.setRangeText('', 0, 0);
+
+ }, "input type " + type + " should support all selection attributes and methods");
+ });
+
+ invalid.forEach(function(type) {
+ test(function() {
+ var input = document.createElement("input");
+
+ input.type = type;
+ assert_equals(input.type, type, "the given input type is not supported");
+
+ assert_equals(input.selectionStart, null, 'getting input.selectionStart');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionStart = 0; });
+ assert_equals(input.selectionEnd, null, 'getting input.selectionEnd');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionEnd = 0; });
+ assert_equals(input.selectionDirection, null, 'getting input.selectionDirection');
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.selectionDirection = "none"; });
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.setSelectionRange(0, 0); });
+ assert_throws_dom("INVALID_STATE_ERR", function() { input.setRangeText('', 0, 0); });
+
+ }, "input type " + type + " should not support variable-length selections");
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-cross-origin-iframe.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-cross-origin-iframe.html
new file mode 100644
index 0000000000..c8197cc180
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-cross-origin-iframe.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<title>Test showPicker() called from cross-origin iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<iframe id="iframe1"></iframe>
+<iframe id="iframe2"></iframe>
+<iframe id="iframe3"></iframe>
+<iframe id="iframe4"></iframe>
+</body>
+<script>
+function waitForSecurityErrors() {
+ return new Promise((resolve) => {
+ window.addEventListener("message", (event) => resolve(event.data), {
+ once: true,
+ });
+ });
+}
+
+promise_test(async (t) => {
+ iframe1.src =
+ new URL("resources/", self.location).pathname +
+ "show-picker-child-iframe.html";
+
+ // Wait for the iframe to report security errors when calling showPicker().
+ const securityErrors = await waitForSecurityErrors();
+ assert_equals(
+ securityErrors,
+ "",
+ "In same-origin iframes, showPicker() does not throw a SecurityError."
+ );
+});
+
+promise_test(async (t) => {
+ iframe2.src =
+ get_host_info().HTTP_NOTSAMESITE_ORIGIN +
+ new URL("resources/", self.location).pathname +
+ "show-picker-child-iframe.html";
+
+ // Wait for the iframe to report security errors when calling showPicker().
+ const securityErrors = await waitForSecurityErrors();
+ assert_equals(
+ securityErrors,
+ "button,checkbox,date,datetime-local,email,hidden,image,month,number,password,radio,range,reset,search,submit,tel,text,time,url,week",
+ "In cross-origin iframes, showPicker() throws a SecurityError except on file and color."
+ );
+});
+
+promise_test(async (t) => {
+ iframe3.src =
+ new URL("resources/", self.location).pathname +
+ "show-picker-child-iframe.html?documentDomain=" + get_host_info().ORIGINAL_HOST;
+
+ // Wait for the iframe to report security errors when calling showPicker().
+ const securityErrors = await waitForSecurityErrors();
+ assert_equals(
+ securityErrors,
+ "",
+ "In same-origin but cross-origin-domain iframes, showPicker() does not throw a SecurityError."
+ );
+});
+
+promise_test(async (t) => {
+ document.domain = get_host_info().ORIGINAL_HOST;
+ iframe4.src =
+ get_host_info().HTTP_REMOTE_ORIGIN +
+ new URL("resources/", self.location).pathname +
+ "show-picker-child-iframe.html?documentDomain=" + get_host_info().ORIGINAL_HOST;
+
+ // Wait for the iframe to report security errors when calling showPicker().
+ const securityErrors = await waitForSecurityErrors();
+ assert_equals(
+ securityErrors,
+ "button,checkbox,date,datetime-local,email,hidden,image,month,number,password,radio,range,reset,search,submit,tel,text,time,url,week",
+ "In cross-origin but same-origin-domain iframes, showPicker() throws a SecurityError except on file and color."
+ );
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-disabled-readonly.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-disabled-readonly.html
new file mode 100644
index 0000000000..8fdffc158f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-disabled-readonly.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Test showPicker() disabled/readonly requirement</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body></body>
+<script type=module>
+import inputTypes from "./input-types.js";
+
+for (const inputType of inputTypes) {
+ test(() => {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.setAttribute("disabled", "");
+
+ assert_throws_dom('InvalidStateError', () => { input.showPicker(); });
+ }, `input[type=${inputType}] showPicker() throws when disabled`);
+}
+
+const noReadonlySupport = ['button', 'checkbox', 'color', 'file',
+'hidden', 'image', 'radio', 'range', 'reset', 'submit'];
+for (const inputType of inputTypes) {
+ if (!noReadonlySupport.includes(inputType)) {
+ test(() => {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.setAttribute("readonly", "");
+
+ assert_throws_dom('InvalidStateError', () => { input.showPicker(); });
+ }, `input[type=${inputType}] showPicker() throws when readonly`);
+ } else {
+ test(() => {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+ input.setAttribute("readonly", "");
+
+ // Missing user gesture activation throws.
+ assert_throws_dom('NotAllowedError', () => { input.showPicker(); });
+ }, `input[type=${inputType}] showPicker() doesn't throw when readonly`);
+ }
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-user-gesture.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-user-gesture.html
new file mode 100644
index 0000000000..6b94b4f0f0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/show-picker-user-gesture.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Test showPicker() user gesture requirement</title>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body></body>
+<script type=module>
+import inputTypes from "./input-types.js";
+
+for (const inputType of inputTypes) {
+ test(() => {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+
+ assert_throws_dom('NotAllowedError', () => { input.showPicker(); });
+ }, `input[type=${inputType}] showPicker() requires a user gesture`);
+}
+
+for (const inputType of inputTypes) {
+ promise_test(async t => {
+ const input = document.createElement("input");
+ input.setAttribute("type", inputType);
+
+ await test_driver.bless('show picker');
+ input.showPicker();
+ input.blur();
+ }, `input[type=${inputType}] showPicker() does not throw when user activation is active`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/telephone.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/telephone.html
new file mode 100644
index 0000000000..974cbaf88b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/telephone.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Input tel</title>
+ <link rel="author" title="Kazuki Kanamori" href="mailto:yogurito@gmail.com">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#telephone-state-(type=tel)">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <h1>Input tel</h1>
+ <input type="tel" id="novalue" />
+ <input type="tel" id="value_with_LF" value="0&#x000A;1" />
+ <input type="tel" id="value_with_CR" value="0&#x000D;1" />
+ <input type="tel" id="value_with_CRLF" value="0&#x000A;&#x000D;1" />
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+ var element = document.getElementById('novalue');
+ test(function(){
+ assert_equals(element.type, 'tel');
+ }, 'tel type supported on input element');
+ test(function(){
+ element.value = '0\u000A1';
+ assert_equals(element.value, '01');
+ }, 'User agents must not allow users to insert "LF" (U+000A)');
+ test(function(){
+ element.value = '0\u000D1';
+ assert_equals(element.value, '01');
+ }, 'User agents must not allow users to insert "CR" (U+000D)');
+
+ element = document.getElementById('value_with_LF');
+ test(function(){
+ assert_equals(element.value, '01');
+ }, 'The value attribute, if specified, must have a value that contains no "LF" (U+000A)');
+
+ element = document.getElementById('value_with_CR');
+ test(function(){
+ assert_equals(element.value, '01');
+ }, 'The value attribute, if specified, must have a value that contains no "CR" (U+000D)');
+
+ test(function(){
+ element = document.getElementById('novalue');
+ element.value = '0\u000D\u000A1';
+ assert_equals(element.value, '01');
+
+ element = document.getElementById('value_with_CRLF');
+ assert_equals(element.value, '01');
+ }, 'The value sanitization algorithm is as follows: Strip line breaks from the value');
+
+ element = document.getElementById('novalue');
+ test(function(){
+ element.value = '+811234';
+ assert_equals(element.value, '+811234');
+ }, 'Element can accept the phone number with plus sign(country code)');
+ test(function(){
+ element.value = '1234#5678';
+ assert_equals(element.value, '1234#5678');
+ }, 'Element can accept the phone number with hash mark(extension number)');
+ test(function(){
+ element.value = '123-456-789';
+ assert_equals(element.value, '123-456-789');
+ }, 'Element can accept the phone number with hyphen');
+ test(function(){
+ element.value = '123.456.789';
+ assert_equals(element.value, '123.456.789');
+ }, 'Element can accept the phone number with dots');
+ test(function(){
+ element.value = '1 23 4';
+ assert_equals(element.value, '1 23 4');
+ }, 'Element can accept the phone number with whitespace');
+ test(function(){
+ element.value = ' 1234 ';
+ assert_equals(element.value, ' 1234 ');
+ }, 'Element can accept the phone number with leading & following whitespaces');
+ test(function(){
+ element.value = '(03)12345678';
+ assert_equals(element.value, '(03)12345678');
+ }, 'Element can accept the phone number with parentheses(area code)');
+ </script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/text.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/text.html
new file mode 100644
index 0000000000..f30f9d39fc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/text.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Text input element</title>
+ <link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#text-(type=text)-state-and-search-state-(type=search)">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Text input element</h1>
+ <div style="display: none">
+
+ <input id="text" type="text" />
+ <input id="text_with_value" type="text" value="foo" />
+
+ <input id="search" type="search" />
+ <input id="search_with_value" type="search" value="foo" />
+
+ </div>
+ <div id="log"></div>
+ <script type="text/javascript">
+ var types = [ 'text', 'search' ];
+
+ for (var i = 0; i < types.length; ++i) {
+ test(
+ function() {
+ assert_equals(document.getElementById(types[i]).value, "");
+ assert_equals(document.getElementById(types[i] + "_with_value").value, "foo");
+ }, "Value returns the current value for " + types[i]);
+
+ test(
+ function() {
+ document.getElementById(types[i]).value = "A";
+ assert_equals(document.getElementById(types[i]).value, "A");
+ document.getElementById(types[i]).value = "B";
+ }, "Setting value changes the current value for " + types[i]);
+
+ test(
+ function() {
+ // Any LF (\n) must be stripped.
+ document.getElementById(types[i]).value = "\nAB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "A\nB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "AB\n";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+
+ // Any CR (\r) must be stripped.
+ document.getElementById(types[i]).value = "\rAB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "A\rB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "AB\r";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+
+ // Any combinations of LF CR must be stripped.
+ document.getElementById(types[i]).value = "\r\nAB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "A\r\nB";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "AB\r\n";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ document.getElementById(types[i]).value = "\r\nA\n\rB\r\n";
+ assert_equals(document.getElementById(types[i]).value, "AB");
+ }, "Value sanitization algorithm should strip line breaks for " + types[i]);
+
+ test(
+ function() {
+ assert_equals(document.getElementById(types[i]).files, null);
+ }, "files attribute must return null for " + types[i]);
+
+ test(
+ function() {
+ assert_equals(document.getElementById(types[i]).valueAsDate, null);
+ }, "valueAsDate attribute must return null for " + types[i]);
+
+ test(
+ function() {
+ assert_equals(document.getElementById(types[i]).valueAsNumber, NaN);
+ }, "valueAsNumber attribute must return NaN for " + types[i]);
+
+ test(
+ function() {
+ assert_equals(document.getElementById("text").list, null);
+ }, "list attribute must return null for " + types[i]);
+
+ test(
+ function() {
+ var el = document.getElementById(types[i]);
+ assert_throws_dom("InvalidStateError", function() { el.stepDown(); }, "");
+ }, "stepDown does not apply for " + types[i]);
+
+ test(
+ function() {
+ var el = document.getElementById(types[i]);
+ assert_throws_dom("InvalidStateError", function() { el.stepUp(); }, "");
+ }, "stepUp does not apply for " + types[i]);
+ }
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/time-2.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-2.html
new file mode 100644
index 0000000000..0ffec33bf5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-2.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Form input type=time</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#times">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#time-state-(type=time)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ var times = [
+ {value: "", expected: "", testname: "empty value"},
+ {value: "00:00", expected: "00:00", testname: "Valid value: value should be 00:00"},
+ {value: "00:00:00", expected: "00:00:00", testname: "Valid value: value should be 00:00:00"},
+ {value: "00:00:00.0", expected: "00:00:00.0", testname: "Valid value: value should be 00:00:00.0"},
+ {value: "00:00:00.00", expected: "00:00:00.00", testname: "Valid value: value should be 00:00:00.00"},
+ {value: "00:00:00.000", expected: "00:00:00.000", testname: "Valid value: value should be 00:00:00.000"},
+ {value: "00:00:00.0000", expected: "", testname: "Invalid value: fraction should have one, two or three ASCII digits. Value should be empty"},
+ {value: "0:00:00.000", expected: "", testname: "Invalid value: hour should have two ASCII digits. Value should be empty"},
+ {value: "00:0:00.000", expected: "", testname: "Invalid value: minutes should have two ASCII digits. Value should be empty"},
+ {value: "00:00:0.000", expected: "", testname: "Invalid value: seconds should have two ASCII digits. Value should be empty"},
+ {value: "24:00:00.000", expected: "", testname: "Invalid value: hour > 23. Value should be empty"},
+ {value: "00:60:00.000", expected: "", testname: "Invalid value: minute > 59. Value should be empty"},
+ {value: "00:00:60.000", expected: "", testname: "Invalid value: second > 59. Value should be empty"},
+ {value: "12:00:00.001", attributes: { min: "12:00:00.000" }, expected: "12:00:00.001", testname: "Value >= min attribute"},
+ {value: "12:00:00.000", attributes: { min: "12:00:00.001" }, expected: "12:00:00.000", testname: "Value < min attribute"},
+ {value: "12:00:00.000", attributes: { max: "12:00:00.001" }, expected: "12:00:00.000", testname: "Value <= max attribute"},
+ {value: "12:00:00.001", attributes: { max: "12:00:00.000" }, expected: "12:00:00.001", testname: "Value > max attribute"}
+ ];
+ for (var i = 0; i < times.length; i++) {
+ var w = times[i];
+ test(function() {
+ var input = document.createElement("input");
+ input.type = "time";
+ input.value = w.value;
+ for(var attr in w.attributes) {
+ input[attr] = w.attributes[attr];
+ }
+ assert_equals(input.value, w.expected);
+ }, w.testname);
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/time-datalist-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-datalist-crash.html
new file mode 100644
index 0000000000..2964032e35
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-datalist-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="newParent"></div>
+<datalist id="suggestions">
+ <option>12:00</option>
+ <input type="time" list="suggestions">
+</datalist>
+<script>
+ test(() => {
+ document.body.offsetTop;
+ newParent.appendChild(suggestions);
+ }, "Moving a datalist enclosing an input type=time using that list should not crash.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/time-focus-dynamic-value-change.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-focus-dynamic-value-change.html
new file mode 100644
index 0000000000..95ccb1ff69
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/time-focus-dynamic-value-change.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>input type=date and input type=datetime handle focus state correctly</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time)">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1450219">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input type="time">
+<input type="text">
+<script>
+let t = async_test("Time input handles focus correctly when value changes");
+window.onload = t.step_func_done(function() {
+ let time = document.querySelector("input[type=time]");
+ let text = document.querySelector("input[type=text]");
+ time.focus();
+ assert_true(time.matches(":focus"));
+ assert_equals(document.activeElement, time);
+ time.value = "08:10:10";
+ assert_true(time.matches(":focus"));
+ assert_equals(document.activeElement, time);
+ time.value = "08:10";
+ assert_true(time.matches(":focus"));
+ assert_equals(document.activeElement, time);
+ text.focus();
+ assert_true(text.matches(":focus"));
+ assert_false(time.matches(":focus"));
+ assert_equals(document.activeElement, text);
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/time.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/time.html
new file mode 100644
index 0000000000..ec815d4cb3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/time.html
@@ -0,0 +1,357 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <title>Input Time</title>
+ <meta name=viewport content="width=device-width, maximum-scale=1.0, user-scalable=no" />
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-input-element">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+
+ <body>
+ <h1>Input Time</h1>
+ <div style="display:none;">
+ <input type="time "id="chkDefaultValue" />
+ <input type="time" id="chkStep" />
+ <input type="time" id="chkSetValueTest" />
+ <input type="time" id="chkSupportAttribute" min="01:01:01.001" max="12:12:12.012" step="600" />
+ </div>
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+
+/* check default value */
+test(function(){ assert_equals(document.getElementById("chkDefaultValue").value, "");
+}, "time element of default time value");
+test(function(){assert_equals(document.getElementById('chkStep').step, "");
+}, "step attribute on default value check");
+test(function(){assert_equals(document.getElementById('chkDefaultValue').max, "");
+}, "max attribute on default value check")
+test(function(){assert_equals(document.getElementById('chkDefaultValue').max, "");
+}, "min attribute on default value check")
+
+/* simple attribute test*/
+test(function(){assert_equals(document.getElementById("chkSupportAttribute").type,"time");}
+ , "type attribute support on input element");
+test(function(){assert_equals(document.getElementById('chkSupportAttribute').min, "01:01:01.001")}
+ , "max attribute support on input element");
+test(function(){assert_equals(document.getElementById('chkSupportAttribute').max, "12:12:12.012")}
+ , "min attribute support on input element");
+test(function(){assert_equals(document.getElementById("chkSupportAttribute").step, "600")}
+ , "step attribute support on input element");
+
+/* check step up and down */
+var _StepTest = document.getElementById("chkStep");
+test(function(){ assert_true(typeof(_StepTest.stepUp) ==="function" ) } , "stepUp function support on input Element");
+test(function(){ assert_true(typeof(_StepTest.stepDown) ==="function" ) } , "stepDown function support on input Element");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:01",
+ "12:01:00",
+ "12:01:00.0",
+ "12:01:00.00",
+ "12:01:00.000"],
+ "a valid time string representing 1 minute after noon");
+} , "stepUp step value empty on default step value ");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "11:59",
+ "11:59:00",
+ "11:59:00.0",
+ "11:59:00.00",
+ "11:59:00.000"],
+ "a valid time string representing 1 minute before noon");
+}, "stepDown step value empty default step value");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "-600";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:01",
+ "12:01:00",
+ "12:01:00.0",
+ "12:01:00.00",
+ "12:01:00.000"],
+ "a valid time string representing 1 minute after noon");
+},"stepUp on step value minus");
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "-600";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "11:59",
+ "11:59:00",
+ "11:59:00.0",
+ "11:59:00.00",
+ "11:59:00.000"],
+ "a valid time string representing 1 minute before noon");
+},"stepDown on step value minus");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "0";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:01",
+ "12:01:00",
+ "12:01:00.0",
+ "12:01:00.00",
+ "12:01:00.000"],
+ "a valid time string representing 1 minute after noon");
+} , "stepUp on step value zero ");
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "0";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "11:59",
+ "11:59:00",
+ "11:59:00.0",
+ "11:59:00.00",
+ "11:59:00.000"],
+ "a valid time string representing 1 minute before noon");
+} , "stepDown on step value zero ");
+
+test(function(){
+ _StepTest.value = "00:00";
+ _StepTest.step = "86399";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "23:59:59",
+ "23:59:59.0",
+ "23:59:59.00",
+ "23:59:59.000"],
+ "a valid time string representing 1 second before midnight");
+} , "stepUp on step value 24 hour");
+test(function(){
+ _StepTest.value = "23:59:59";
+ _StepTest.step = "86399";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "00:00",
+ "00:00:00",
+ "00:00:00.0",
+ "00:00:00.00",
+ "00:00:00.000"],
+ "a valid time string representing midnight");
+} , "stepDown on step value 24 hour ");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "3600";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "13:00",
+ "13:00:00",
+ "13:00:00.0",
+ "13:00:00.00",
+ "13:00:00.000"],
+ "a valid time string representing 1pm");
+} , "stepUp on step value hour ");
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "3600";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "11:00",
+ "11:00:00",
+ "11:00:00.0",
+ "11:00:00.00",
+ "11:00:00.000"],
+ "a valid time string representing 11am");
+} , "stepDown on step value hour ");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "1";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:00:01",
+ "12:00:01.0",
+ "12:00:01.00",
+ "12:00:01.000"],
+ "a valid time string representing 1 second after noon");
+} , "stepUp on step value second ");
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "1";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "11:59:59",
+ "11:59:59.0",
+ "11:59:59.00",
+ "11:59:59.000"],
+ "a valid time string representing 1 second before noon");
+} , "stepDown on step value second ");
+
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "0.001";
+ _StepTest.stepUp();
+ assert_equals(_StepTest.value, "12:00:00.001");
+} , "stepUp on step value with fractional seconds");
+test(function(){
+ _StepTest.value = "12:00";
+ _StepTest.step = "0.001";
+ _StepTest.stepDown();
+ assert_equals(_StepTest.value, "11:59:59.999");
+} , "stepDown on step value with fractional seconds");
+
+test(function(){
+ _StepTest.value = "13:00:00";
+ _StepTest.step = "1";
+ _StepTest.stepUp(2);
+ assert_in_array(
+ _StepTest.value,
+ [
+ "13:00:02",
+ "13:00:02.0",
+ "13:00:02.00",
+ "13:00:02.000"],
+ "a valid time string representing 2 seconds after 1pm");
+}, "stepUp argument 2 times");
+test(function(){
+ _StepTest.value = "13:00:00";
+ _StepTest.step = "1";
+ _StepTest.stepDown(2);
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:59:58",
+ "12:59:58.0",
+ "12:59:58.00",
+ "12:59:58.000"],
+ "a valid time string representing 2 seconds before 1pm");
+}, "stepDown argument 2 times");
+
+test(function(){
+ _StepTest.max = "15:00";
+ this.add_cleanup(function() { _StepTest.max = ""; });
+ _StepTest.value = "15:00";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "15:00",
+ "15:00:00",
+ "15:00:00.0",
+ "15:00:00.00",
+ "15:00:00.000"],
+ "a valid time string representing 3pm");
+} , "stepUp stop because it exceeds the maximum value");
+test(function(){
+ _StepTest.min = "13:00";
+ this.add_cleanup(function() { _StepTest.min = ""; });
+ _StepTest.value = "13:00";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "13:00",
+ "13:00:00",
+ "13:00:00.0",
+ "13:00:00.00",
+ "13:00:00.000"],
+ "a valid time string representing 1pm");
+} , "stepDown stop so lower than the minimum value");
+
+test(function(){
+ // Set min value to ensure that 15:01 - base is a multiple of 2 min (i.e., a
+ // valid value).
+ _StepTest.min = "14:01";
+ _StepTest.max = "15:01";
+ this.add_cleanup(function() { _StepTest.min = _StepTest.max = ""; });
+ _StepTest.value = "15:00";
+ _StepTest.step = "120";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "15:01",
+ "15:01:00",
+ "15:01:00.0",
+ "15:01:00.00",
+ "15:01:00.000"],
+ "a valid time string representing 1 minute after 3pm");
+} , "stop at border on stepUp");
+test(function(){
+ _StepTest.min = "12:59";
+ this.add_cleanup(function() { _StepTest.min = ""; });
+ _StepTest.value = "13:00";
+ _StepTest.step = "120";
+ _StepTest.stepDown();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "12:59",
+ "12:59:00",
+ "12:59:00.0",
+ "12:59:00.00",
+ "12:59:00.000"],
+ "a valid time string representing 1 minute before 2pm");
+} , "stop at border on stepDown");
+
+test(function(){
+ _StepTest.value = "";
+ _StepTest.step = "60";
+ _StepTest.stepUp();
+ assert_in_array(
+ _StepTest.value,
+ [
+ "00:01",
+ "00:01:00",
+ "00:01:00.0",
+ "00:01:00.00",
+ "00:01:00.000"],
+ "a valid time string representing 1 minute after midnight");
+} , " empty value of stepUp");
+
+
+/* set value test */
+test(function(){
+ var _time = document.getElementById("chkSetValueTest");
+ _time.value = "12:00:00.000";
+ assert_equals(_time.value, "12:00:00.000");
+ _time.value = "hh:mi:ss.sss";
+ assert_equals(_time.value, "");
+}, "set value on not time format value");
+
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html
new file mode 100644
index 0000000000..5fb5000a26
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#input-type-change">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input id="myInput" type="file">
+<script>
+ test(() => {
+ myInput.offsetTop;
+ myInput.type = "text";
+ }, "Changing type from file to text should not crash.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state-weekmonth.html
new file mode 100644
index 0000000000..cab8e3a625
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state-weekmonth.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Input element's type attribute changes state</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#the-input-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+ const INITIAL_VALUE = " foo\rbar ";
+
+ // Sanitize algorithm implementations only for values used in this test.
+ function sanitizeText(value) {
+ switch (value) {
+ case INITIAL_VALUE: return " foobar ";
+ case " foobar ": return value;
+ case "foobar": return value;
+ case "50": return value;
+ case "#000000": return value;
+ case "": return value;
+ default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
+ }
+ }
+ function sanitizeEmailOrUrl(value) {
+ switch (value) {
+ case INITIAL_VALUE: return "foobar";
+ case " foobar ": return "foobar";
+ case "foobar": return value;
+ case "50": return value;
+ case "#000000": return value;
+ case "": return value;
+ default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
+ }
+ }
+ function sanitizeTemporal(value) {
+ // We have no test cases using valid temporal values.
+ return "";
+ }
+ function sanitizeNumber(value) {
+ switch (value) {
+ case "50": return value;
+ default:
+ // We have no test cases using valid numbers other than "50".
+ return "";
+ }
+ }
+ function sanitizeRange(value) {
+ // We have no test cases using valid numbers other than "50".
+ return "50";
+ }
+ function sanitizeColor(value) {
+ // We have no test cases using valid colors other than "#000000".
+ return "#000000";
+ }
+ function browserSupportsInputTypeOf(inputType) {
+ var inputTest = document.createElement("input");
+ inputTest.type = inputType;
+ return (inputTest.type === inputType);
+ }
+
+
+ var types = [
+ { type: "hidden" },
+ { type: "text", sanitizer: sanitizeText },
+ { type: "search", sanitizer: sanitizeText },
+ { type: "tel", sanitizer: sanitizeText },
+ { type: "url", sanitizer: sanitizeEmailOrUrl },
+ { type: "email", sanitizer: sanitizeEmailOrUrl },
+ { type: "password", sanitizer: sanitizeText },
+ { type: "datetime-local", sanitizer: sanitizeTemporal },
+ { type: "date", sanitizer: sanitizeTemporal },
+ { type: "month", sanitizer: sanitizeTemporal },
+ { type: "week", sanitizer: sanitizeTemporal },
+ { type: "time", sanitizer: sanitizeTemporal },
+ { type: "number", sanitizer: sanitizeNumber },
+ { type: "range", sanitizer: sanitizeRange },
+ { type: "color", sanitizer: sanitizeColor },
+ { type: "checkbox", defaultValue: "on" },
+ { type: "radio", defaultValue: "on" },
+ { type: "file" },
+ { type: "submit" },
+ { type: "image" },
+ { type: "reset" },
+ { type: "button" }
+ ];
+
+ const selectionStart = 2;
+ const selectionEnd = 5;
+ const selectionDirection = "backward";
+
+ // Obtain selectionDirection after setting it to "none".
+ // Some platforms don't support "none" direction, and "forward" is returned
+ // in such platforms.
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#set-the-selection-direction
+ function testNoneDirection() {
+ const input = document.createElement("input");
+ input.selectionDirection = "none";
+ return input.selectionDirection;
+ }
+ const noneDirectionResult = testNoneDirection();
+
+ for (var i = 0; i < types.length; i++) {
+ for (var j = 0; j < types.length; j++) {
+ const monthOrWeek = types[i].type === 'month' || types[i].type === 'week' || types[j].type === 'month' || types[j].type === 'week';
+ if ((types[i] != types[j]) && monthOrWeek) {
+ test(function() {
+ assert_implements(browserSupportsInputTypeOf(types[i].type), "Support for input type " + types[i].type + " is required for this test.");
+ assert_implements(browserSupportsInputTypeOf(types[j].type), "Support for input type " + types[j].type + " is required for this test.");
+ var input = document.createElement("input");
+ var expected = INITIAL_VALUE;
+ input.type = types[i].type;
+ if (types[i].type === "file") {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ input.value = expected;
+ });
+ assert_equals(input.value, "");
+ } else if (types[j].type === "file") {
+ input.value = expected;
+ input.type = types[j].type; // change state
+ assert_equals(input.value, "");
+ } else {
+ input.value = expected;
+ expected = input.value;
+
+ const previouslySelectable = (input.selectionStart !== null);
+
+ if (previouslySelectable) {
+ input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
+ }
+
+ input.type = types[j].type; // change state
+
+ var preSanitizeValue = expected;
+ // type[j] sanitization
+ if (types[j].sanitizer) {
+ expected = types[j].sanitizer(expected);
+ }
+
+ // type[j] defaultValue
+ if (expected === "" && types[j].defaultValue) {
+ expected = types[j].defaultValue;
+ }
+
+ assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
+
+ const nowSelectable = (input.selectionStart !== null);
+
+ if (nowSelectable) {
+ if (previouslySelectable) {
+ // Value might change after sanitization. The following checks are only valid when the value stays the same.
+ if (preSanitizeValue === expected) {
+ assert_equals(input.selectionStart, selectionStart, "selectionStart should be unchanged");
+ assert_equals(input.selectionEnd, selectionEnd, "selectionEnd should be unchanged");
+ assert_equals(input.selectionDirection, selectionDirection, "selectionDirection should be unchanged");
+ }
+ } else {
+ assert_equals(input.selectionStart, 0, "selectionStart should be 0");
+ assert_equals(input.selectionEnd, 0, "selectionEnd should be 0");
+ assert_equals(input.selectionDirection, noneDirectionResult,
+ `selectionDirection should be '{noneDirectionResult}'`);
+ }
+ }
+ }
+ }, "change state from " + types[i].type + " to " + types[j].type);
+ }
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state.html
new file mode 100644
index 0000000000..5fb4cc9b56
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/type-change-state.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Input element's type attribute changes state</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#the-input-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+ const INITIAL_VALUE = " foo\rbar ";
+
+ // Sanitize algorithm implementations only for values used in this test.
+ function sanitizeText(value) {
+ switch (value) {
+ case INITIAL_VALUE: return " foobar ";
+ case " foobar ": return value;
+ case "foobar": return value;
+ case "50": return value;
+ case "#000000": return value;
+ case "": return value;
+ default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
+ }
+ }
+ function sanitizeEmailOrUrl(value) {
+ switch (value) {
+ case INITIAL_VALUE: return "foobar";
+ case " foobar ": return "foobar";
+ case "foobar": return value;
+ case "50": return value;
+ case "#000000": return value;
+ case "": return value;
+ default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
+ }
+ }
+ function sanitizeTemporal(value) {
+ // We have no test cases using valid temporal values.
+ return "";
+ }
+ function sanitizeNumber(value) {
+ switch (value) {
+ case "50": return value;
+ default:
+ // We have no test cases using valid numbers other than "50".
+ return "";
+ }
+ }
+ function sanitizeRange(value) {
+ // We have no test cases using valid numbers other than "50".
+ return "50";
+ }
+ function sanitizeColor(value) {
+ // We have no test cases using valid colors other than "#000000".
+ return "#000000";
+ }
+ function browserSupportsInputTypeOf(inputType) {
+ var inputTest = document.createElement("input");
+ inputTest.type = inputType;
+ return (inputTest.type === inputType);
+ }
+
+
+ var types = [
+ { type: "hidden" },
+ { type: "text", sanitizer: sanitizeText },
+ { type: "search", sanitizer: sanitizeText },
+ { type: "tel", sanitizer: sanitizeText },
+ { type: "url", sanitizer: sanitizeEmailOrUrl },
+ { type: "email", sanitizer: sanitizeEmailOrUrl },
+ { type: "password", sanitizer: sanitizeText },
+ { type: "datetime-local", sanitizer: sanitizeTemporal },
+ { type: "date", sanitizer: sanitizeTemporal },
+ { type: "time", sanitizer: sanitizeTemporal },
+ { type: "number", sanitizer: sanitizeNumber },
+ { type: "range", sanitizer: sanitizeRange },
+ { type: "color", sanitizer: sanitizeColor },
+ { type: "checkbox", defaultValue: "on" },
+ { type: "radio", defaultValue: "on" },
+ { type: "file" },
+ { type: "submit" },
+ { type: "image" },
+ { type: "reset" },
+ { type: "button" }
+ ];
+
+ const selectionStart = 2;
+ const selectionEnd = 5;
+ const selectionDirection = "backward";
+
+ // Obtain selectionDirection after setting it to "none".
+ // Some platforms don't support "none" direction, and "forward" is returned
+ // in such platforms.
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#set-the-selection-direction
+ function testNoneDirection() {
+ const input = document.createElement("input");
+ input.selectionDirection = "none";
+ return input.selectionDirection;
+ }
+ const noneDirectionResult = testNoneDirection();
+
+ for (var i = 0; i < types.length; i++) {
+ for (var j = 0; j < types.length; j++) {
+ if (types[i] != types[j]) {
+ test(function() {
+ assert_implements(browserSupportsInputTypeOf(types[i].type), "Support for input type " + types[i].type + " is required for this test.");
+ assert_implements(browserSupportsInputTypeOf(types[j].type), "Support for input type " + types[j].type + " is required for this test.");
+ var input = document.createElement("input");
+ var expected = INITIAL_VALUE;
+ input.type = types[i].type;
+ if (types[i].type === "file") {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ input.value = expected;
+ });
+ assert_equals(input.value, "");
+ } else if (types[j].type === "file") {
+ input.value = expected;
+ input.type = types[j].type; // change state
+ assert_equals(input.value, "");
+ } else {
+ input.value = expected;
+ expected = input.value;
+
+ const previouslySelectable = (input.selectionStart !== null);
+
+ if (previouslySelectable) {
+ input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
+ }
+
+ input.type = types[j].type; // change state
+
+ var preSanitizeValue = expected;
+ // type[j] sanitization
+ if (types[j].sanitizer) {
+ expected = types[j].sanitizer(expected);
+ }
+
+ // type[j] defaultValue
+ if (expected === "" && types[j].defaultValue) {
+ expected = types[j].defaultValue;
+ }
+
+ assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
+
+ const nowSelectable = (input.selectionStart !== null);
+
+ if (nowSelectable) {
+ if (previouslySelectable) {
+ // Value might change after sanitization. The following checks are only valid when the value stays the same.
+ if (preSanitizeValue === expected) {
+ assert_equals(input.selectionStart, selectionStart, "selectionStart should be unchanged");
+ assert_equals(input.selectionEnd, selectionEnd, "selectionEnd should be unchanged");
+ assert_equals(input.selectionDirection, selectionDirection, "selectionDirection should be unchanged");
+ }
+ } else {
+ assert_equals(input.selectionStart, 0, "selectionStart should be 0");
+ assert_equals(input.selectionEnd, 0, "selectionEnd should be 0");
+ assert_equals(input.selectionDirection, noneDirectionResult,
+ `selectionDirection should be '{noneDirectionResult}'`);
+ }
+ }
+ }
+ }, "change state from " + types[i].type + " to " + types[j].type);
+ }
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/url.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/url.html
new file mode 100644
index 0000000000..aafa0ced9d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/url.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Input url</title>
+ <link rel="author" title="Hyeonseok Shin" href="mailto:hyeonseok@gmail.com">
+ <link rel="help" href="https://html.spec.whatwg.org/multipage/#url-state-%28type=url%29">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <h1>Input url</h1>
+ <div style="display: none">
+ <input type="url" id="type_support" />
+ <input type="url" id="set_value_LF" />
+ <input type="url" id="set_value_CR" />
+ <input type="url" id="set_value_CRLF" />
+ <input type="url" id="value_with_CRLF" value="a&#x000D;&#x000A;a" />
+ <input type="url" id="value_with_leading_trailing_white_space" value=" aa " />
+ <input type="url" id="value_with_leading_trailing_inner_white_space" value=" a a " />
+ </div>
+ <div id="log">
+ </div>
+
+ <script type="text/javascript">
+ test(function(){
+ var element = document.getElementById('type_support');
+ assert_equals(element.type, 'url');
+ }, 'url type supported on input element');
+
+ test(function(){
+ var element = document.getElementById('set_value_LF');
+ element.value = 'a\u000Aa';
+ assert_equals(element.value, 'aa');
+
+ element = document.getElementById('set_value_CR');
+ element.value = 'a\u000Da';
+ assert_equals(element.value, 'aa');
+
+ element = document.getElementById('set_value_CRLF');
+ element.value = 'a\u000D\u000Aa';
+ assert_equals(element.value, 'aa');
+ }, 'The value must not be set with "LF" (U+000A) or "CR" (U+000D)');
+
+ test(function(){
+ var element = document.getElementById('value_with_CRLF');
+ assert_equals(element.value, 'aa');
+ }, 'The value sanitization algorithm is as follows: Strip line breaks from the value');
+
+ test(function(){
+ var element = document.getElementById('value_with_leading_trailing_white_space');
+ assert_equals(element.value, 'aa');
+
+ element = document.getElementById('value_with_leading_trailing_inner_white_space');
+ assert_equals(element.value, 'a a');
+ }, 'The value sanitization algorithm is as follows: Strip leading and trailing whitespace from the value.');
+ </script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode-weekmonth.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode-weekmonth.html
new file mode 100644
index 0000000000..c4a241016b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode-weekmonth.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Input element value mode</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+// MODE DEFAULT
+test(function () {
+ var input = document.createElement("input");
+ input.type = "month";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type month without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "month";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type month with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "week";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type week without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "week";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type week with value attribute");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode.html
new file mode 100644
index 0000000000..37f3a7bce9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/valueMode.html
@@ -0,0 +1,304 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Input element value mode</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+// MODE DEFAULT
+test(function () {
+ var input = document.createElement("input");
+ input.type = "hidden";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type hidden without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "hidden";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type hidden with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "submit";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type submit without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "submit";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type submit with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "image";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type image without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "image";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type image with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "reset";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type reset without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "reset";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type reset with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "button";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type button without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "button";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type button with value attribute");
+
+// MODE DEFAULT/ON
+test(function () {
+ var input = document.createElement("input");
+ input.type = "checkbox";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type checkbox without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "checkbox";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type checkbox with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "radio";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type radio without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "radio";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\r\r\n\n\0");
+}, "value IDL attribute of input type radio with value attribute");
+
+// MODE VALUE
+test(function () {
+ var input = document.createElement("input");
+ input.type = "text";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type text without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "text";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type text with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "search";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type search without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "search";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type search with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "tel";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type tel without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "tel";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type tel with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "url";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type url without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "url";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type url with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "email";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type email without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "email";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type email with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "password";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type password without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "password";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "foo\0");
+}, "value IDL attribute of input type password with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "datetime-local";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type datetime-local without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "datetime-local";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type datetime-local with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "date";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type date without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "date";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type date with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "time";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type time without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "time";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type time with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "number";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type number without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "number";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "");
+}, "value IDL attribute of input type number with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "range";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "50");
+}, "value IDL attribute of input type range without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "range";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "50");
+}, "value IDL attribute of input type range with value attribute");
+
+test(function () {
+ var input = document.createElement("input");
+ input.type = "color";
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "#000000");
+}, "value IDL attribute of input type color without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "color";
+ input.setAttribute("value", "bar");
+ input.value = "foo\r\r\n\n\0";
+ assert_equals(input.value, "#000000");
+}, "value IDL attribute of input type color with value attribute");
+
+// MODE FILENAME
+test(function () {
+ var input = document.createElement("input");
+ input.type = "file";
+
+ for (const emptyValue of ["", null]) {
+ input.value = emptyValue;
+ assert_equals(input.value, "", `input.value is empty after assigning ${emptyValue}`);
+ }
+
+ for (const invalidValue of ["foo", 10, undefined]) {
+ assert_throws_dom("InvalidStateError", () => {
+ input.value = invalidValue;
+ });
+ assert_equals(input.value, "", `input.value is empty after assigning ${invalidValue}`);
+ }
+}, "value IDL attribute of input type file without value attribute");
+test(function() {
+ var input = document.createElement("input");
+ input.type = "file";
+ input.setAttribute("value", "bar");
+ assert_equals(input.value, "", "input.value is empty even with a value attribute");
+
+ input.value = "";
+ assert_equals(input.getAttribute("value"), "bar", "Setting input.value does not change the value attribute");
+}, "value IDL attribute of input type file with value attribute");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-input-element/week.html b/testing/web-platform/tests/html/semantics/forms/the-input-element/week.html
new file mode 100644
index 0000000000..925acfdaf8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-input-element/week.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Form input type=week</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#weeks">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#week-state-(type=week)">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ var weeks = [
+ {value: "", expected: "", testname: "empty value"},
+ {value: "2014-W52", expected: "2014-W52", testname: "Valid value: Value should be 2014-W52"},
+ {value: "2014-W53", expected: "", testname: "2014 has 52 weeks: Value should be empty"},
+ {value: "2015-W53", expected: "2015-W53", testname: "2015 has 53 weeks: Value should be 2015-W53"},
+ {value: "2014", expected: "", testname: "Invalid value: year only"},
+ {value: "2014W", expected: "", testname: "Invalid value: no week number"},
+ {value: "2014W52", expected: "", testname: "Invalid value: no '-' (U+002D)"},
+ {value: "-W52", expected: "", testname: "Invalid value: yearless week"},
+ {value: "2017-w52", expected: "", testname: "Invalid value: should be capital letter 'W'"},
+ {value: "2017-W52-", expected: "", testname: "Invalid value: incorrect with '-' at the end"},
+ {value: "2017-W52-12", expected: "", testname: "Invalid value: value should be two parts"},
+ {value: "W52", expected: "", testname: "Invalid value: yearless week and no '-' (U+002D)"},
+ {value: "2014-W03", attributes: { min: "2014-W02" }, expected: "2014-W03", testname: "Value >= min attribute"},
+ {value: "2014-W01", attributes: { min: "2014-W02" }, expected: "2014-W01", testname: "Value < min attribute"},
+ {value: "2014-W10", attributes: { max: "2014-W11" }, expected: "2014-W10", testname: "Value <= max attribute"},
+ {value: "2014-W12", attributes: { max: "2014-W11" }, expected: "2014-W12", testname: "Value > max attribute"}
+ ];
+ for (var i = 0; i < weeks.length; i++) {
+ var w = weeks[i];
+ test(function() {
+ var input = document.createElement("input");
+ input.type = "week";
+ input.value = w.value;
+ for(var attr in w.attributes) {
+ input[attr] = w.attributes[attr];
+ }
+ assert_equals(input.value, w.expected);
+ }, w.testname);
+ }
+</script>