diff options
Diffstat (limited to 'testing/web-platform/tests/html/semantics/forms/the-input-element')
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
a multiline

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
a multiline

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
a multiline

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𝌆b" id="unicode-code-points"> + <input pattern="\p{ASCII_Hex_Digit}+" value="c0ff33" id="unicode-property"> + + <input pattern="\p{RGI_Emoji}+" value="😘💋" 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-Killroyß"> +<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="глупый"> +<input id=r17 type="radio" name="ГЛУПЫЙ"> +<input id=r18 type="radio" name="ГЛУПЫЙ"> + +<input id=r19 type="radio" name="åωk"> +<input id=r20 type="radio" name="ÅΩK"> +<input id=r21 type="radio" name="Åωk"> +<input id=r22 type="radio" name="åΩk"> +<input id=r23 type="radio" name="åωK"> + +<input id=r24 type="radio" name="blah1"> +<input id=r25 type="radio" name="blah①"> +<input id=r26 type="radio" name="blⒶh1"> +<input id=r27 type="radio" name="blⓐh1"> + +<input id=r28 type="radio" name="tÉdz5アパートFi"> +<input id=r29 type="radio" name="TÉDZ5アパートFi"> +<input id=r30 type="radio" name="TéDZ⁵アパートFi"> +<input id=r31 type="radio" name="tÉdz5㌀Fi"> +<input id=r32 type="radio" name="tÉdz5アパートFi"> +<input id=r34 type="radio" name="TÉDZ⁵アパートFi"> +<input id=r35 type="radio" name="TÉ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
1" /> + <input type="tel" id="value_with_CR" value="0
1" /> + <input type="tel" id="value_with_CRLF" value="0

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
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> |