summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/forms/the-select-element
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/html/semantics/forms/the-select-element
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/forms/the-select-element')
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-add.html89
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-namedItem.html54
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection.html117
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html103
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html21
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html39
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/resources/show-picker-child-iframe.html20
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css18
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-optgroup.html29
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-option-crash.html13
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-add.html36
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-ask-for-reset.html97
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html12
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html18
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-in-table-crash.html4
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-multiple.html48
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-named-getter.html46
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html112
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-remove.html64
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-selectedOptions.html143
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-setcustomvalidity.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-validity.html124
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-value.html56
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/select-willvalidate-readonly-attribute.html24
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/selected-index.html143
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-cv-hidden.html23
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-rendered.html21
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-cross-origin-iframe.tentative.html79
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-disabled.tentative.html14
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-multiple.tentative.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-size.tentative.html17
-rw-r--r--testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-user-gesture.tentative.html24
32 files changed, 1642 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-add.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-add.html
new file mode 100644
index 0000000000..cf4306e271
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-add.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title id='title'>HTMLOptionsCollection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<select id="selly">
+ <option id="id1" name="name1">1</option>
+ <option id="id2" name="name2">2</option>
+ <option id="id3" name="name3">3</option>
+ <option id="id4" name="name4">4</option>
+ <optgroup id="og1">
+ <option name="nameonly">n1</option>
+ <option id="id5">5</option>
+ </optgroup>
+ <optgroup id="og2">
+ <option name="nameonly">n2</option>
+ <option id="id6">6</option>
+ </optgroup>
+
+</select>
+
+<script>
+var selly;
+setup(function() {
+ selly = document.getElementById('selly');
+});
+
+test(function () {
+ var option = document.getElementById('id1');
+ var optgroup = document.getElementById('og1');
+ selly.options.add(option, option);
+ selly.options.add(optgroup, optgroup);
+ assert_equals(selly.children.length, 6);
+ assert_equals(selly.length, 8);
+}, "if before and node are the same element nothing should be done");
+
+test(function () {
+ var o1 = document.createElement("option");
+ o1.value = "a";
+ var o2 = document.createElement("option");
+ o2.value = "b";
+ var o3 = document.createElement("option");
+ o3.value = "c";
+ var optgroup = document.getElementById('og1');
+ selly.options.add(o1, null);
+ selly.options.add(o2, optgroup);
+ selly.options.add(o3, 0);
+
+ var elarray = [];
+ for (var i = 0; i < selly.length; i++) {
+ elarray.push(selly[i].value);
+ }
+ assert_array_equals(elarray, ["c", "1", "2", "3", "4", "b", "n1", "5", "n2", "6", "a"]);
+}, "add method should add option elements correctly");
+
+test(function () {
+ var og1 = document.createElement("optgroup");
+ var o1 = document.createElement("option");
+ o1.value = "a";
+ o1.appendChild(og1);
+ var og2 = document.createElement("optgroup");
+ var o2 = document.createElement("option");
+ o2.value = "b";
+ o2.appendChild(og2);
+ var og3 = document.createElement("optgroup");
+ var o3 = document.createElement("option");
+ o3.value = "c";
+ o3.appendChild(og3);
+
+ var optgroup = document.getElementById('og1');
+ selly.options.add(og1, null);
+ selly.options.add(og2, optgroup);
+ selly.options.add(og3, 0);
+
+ var elarray = [];
+ for (var i = 0; i < selly.length; i++) {
+ elarray.push(selly[i].value);
+ }
+ assert_array_equals(elarray, ["c", "1", "2", "3", "4", "b", "n1", "5", "n2", "6", "a"]);
+}, "add method should add option groups correctly");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-namedItem.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-namedItem.html
new file mode 100644
index 0000000000..c5c8510a47
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection-namedItem.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title id='title'>HTMLOptionsCollection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<select id="selly">
+ <option id="id1" name="name1">1</option>
+ <option id="id2" name="name2">2</option>
+ <option id="id3" name="name3">3</option>
+ <option id="id4" name="name4">4</option>
+ <option name="nameonly">nameonly</option>
+ <option id="id3">duplicate ID</option>
+ <option name="name4">duplicate name</option>
+ <option id="mixed1">mixed ID</option>
+ <option name="mixed1">mixed name</option>
+</select>
+
+<script>
+var selly;
+setup(function() {
+ selly = document.getElementById('selly');
+});
+
+test(function () {
+ assert_equals(selly.namedItem('nameonly')["value"], "nameonly");
+}, "if only one item has a *name* or id value matching the parameter, return that object and stop");
+
+test(function () {
+ assert_equals(selly.namedItem('id2')["value"], "2");
+}, "if only one item has a name or *id* value matching the parameter, return that object and stop");
+
+test(function () {
+ assert_equals(selly.namedItem('thisdoesnotexist'), null);
+}, "if no item has a name or id value matching the parameter, return null and stop");
+
+test(function () {
+ assert_equals(selly.namedItem('id3')["value"], "3");
+}, "if multiple items have a name or *id* value matching the parameter, return the first object and stop");
+
+test(function () {
+ assert_equals(selly.namedItem('name4')["value"], "4");
+}, "if multiple items have a *name* or id value matching the parameter, return the first object and stop");
+
+test(function () {
+ assert_equals(selly.namedItem('mixed1')["value"], "mixed ID");
+}, "if multiple items have a *name* or *id* value matching the parameter, return the first object and stop");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection.html
new file mode 100644
index 0000000000..737e9be876
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/common-HTMLOptionsCollection.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title id='title'>HTMLOptionsCollection</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<select id="selly">
+ <option>1</option>
+ <option>2</option>
+ <option>3</option>
+ <option>4</option>
+</select>
+
+<script>
+var selly;
+setup(function() {
+ selly = document.getElementById('selly');
+});
+
+test(function () {
+ assert_equals(selly.length, 4);
+}, "On getting, the length attribute must return the number of nodes represented by the collection.");
+
+test(function () {
+ selly.length = 7;
+ assert_equals(selly.length, 7,
+ "Number of nodes in collection should have changed");
+ assert_equals(selly.children.length, 7,
+ "Number of children should have changed");
+ for (var i = 4; i < 7; ++i) {
+ var child = selly.children[i];
+ assert_equals(child.localName, "option",
+ "new child should be an option");
+ assert_equals(child.namespaceURI, "http://www.w3.org/1999/xhtml",
+ "new child should be an HTML element");
+ assert_equals(child.attributes.length, 0,
+ "new child should not have attributes");
+ assert_equals(child.childNodes.length, 0,
+ "new child should not have child nodes");
+ }
+}, "Changing the length adds new nodes; The number of new nodes = new length minus old length");
+
+test(function () {
+ var elarray = [];
+ for (var i = 0; i < selly.length; i++) {
+ elarray.push(selly[i].value);
+ }
+ assert_array_equals(elarray, ["1", "2", "3", "4", "", "", ""]);
+}, "New nodes have no value");
+
+test(function () {
+ selly.length = 7;
+ assert_equals(selly.length, 7,
+ "Number of nodes in collection should not have changed");
+ assert_equals(selly.children.length, 7,
+ "Number of children should not have changed");
+}, "Setting a length equal to existing length changes nothing");
+
+test(function () {
+ selly.length = 4;
+ assert_equals(selly[6], undefined,
+ "previously set node is now undefined");
+ assert_equals(selly.length, 4,
+ "Number of nodes in collection is correctly changed");
+ assert_equals(selly.children.length, 4,
+ "Number of children should have changed");
+}, "Setting a length lower than the old length trims nodes from the end");
+
+test(function () {
+ var opts = selly.options;
+ opts[3] = null;
+ assert_equals(selly[3], undefined,
+ "previously set node is now undefined");
+ assert_equals(selly.length, 3,
+ "Number of nodes in collection is correctly changed");
+ assert_equals(selly.children.length, 3,
+ "Number of children should have changed");
+}, "Setting element to null by index removed the element");
+
+test(function () {
+ var opts = selly.options;
+ var new_option = document.createElement("option");
+ var replace_option = new_option.cloneNode(true);
+ new_option.value = "-1";
+ replace_option.value = "a";
+ opts[5] = new_option;
+ opts[0] = replace_option;
+
+ var elarray = [];
+ for (var i = 0; i < selly.length; i++) {
+ elarray.push(selly[i].value);
+ }
+ assert_array_equals(elarray, ["a", "2", "3", "", "", "-1"]);
+
+}, "Setting element by index should correctly append and replace elements");
+
+test(function () {
+ var selection = document.createElementNS("http://www.w3.org/1999/xhtml", "foo:select");
+
+ selection.length = 5;
+ assert_equals(selection.length, 5,
+ "Number of nodes in collection should have changed");
+ for (var i = 0; i < 5; ++i) {
+ var child = selection.children[i];
+ assert_equals(child.localName, "option",
+ "new child should be an option");
+ assert_equals(child.namespaceURI, "http://www.w3.org/1999/xhtml",
+ "new child should be an HTML element");
+ assert_equals(child.prefix, null,
+ "new child should not copy select's prefix");
+ }
+
+}, "Changing the length adds new nodes; The new nodes will not copy select's prefix");
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html
new file mode 100644
index 0000000000..0db2bf0e77
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<link rel="help" href="https://html.spec.whatwg.org/C/#the-select-element:nodes-are-inserted">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<select id="by-parser">
+<option selected>First</option>
+<option selected>Second</option>
+</select>
+
+<select id="by-parser-optgroup">
+<optgroup>
+<option selected>First</option>
+<option selected>Second</option>
+</optgroup>
+</select>
+
+<select id="by-dom"></select>
+
+<select id="by-innerHTML"></select>
+
+<script>
+test(() => {
+ const target = document.querySelector("#by-parser");
+ assert_equals(target.selectedOptions[0].textContent, 'Second');
+
+ const target2 = document.querySelector("#by-parser-optgroup");
+ assert_equals(target2.selectedOptions[0].textContent, 'Second');
+}, 'The last selected OPTION should win; Inserted by parser');
+
+test(() => {
+ const target = document.querySelector("#by-dom");
+ const option1 = document.createElement('option');
+ option1.defaultSelected = true;
+ option1.textContent = 'First';
+ const option2 = document.createElement('option');
+ option2.defaultSelected = true;
+ option2.textContent = 'Second';
+ target.appendChild(option1);
+ target.appendChild(option2);
+ assert_equals(target.selectedOptions[0].textContent, 'Second');
+
+ target.innerHTML = '';
+ const optgroup = document.createElement('optgroup');
+ const option3 = document.createElement('option');
+ option3.defaultSelected = true;
+ option3.textContent = 'First';
+ const option4 = document.createElement('option');
+ option4.defaultSelected = true;
+ option4.textContent = 'Second';
+ optgroup.appendChild(option3);
+ optgroup.appendChild(option4);
+ target.appendChild(optgroup);
+ assert_equals(target.selectedOptions[0].textContent, 'Second');
+}, 'The last selected OPTION should win; Inserted by DOM API');
+
+test(() => {
+ const target = document.querySelector("#by-dom");
+ target.innerHTML = '';
+ const inner = `<option value="one" selected>First</option>
+ <option value="two" selected>Second</option>`;
+
+ // Emulate what jQuery 1.x/2.x does in append(inner).
+ const fragment = document.createDocumentFragment();
+ const div = document.createElement('div');
+ div.innerHTML = '<select multiple>' + inner + '</select>';
+ while (div.firstChild.firstChild)
+ fragment.appendChild(div.firstChild.firstChild);
+ target.appendChild(fragment);
+ assert_equals(target.selectedOptions[0].textContent, 'Second');
+}, 'The last selected OPTION should win; Inserted by jQuery append()');
+
+test(() => {
+ const target = document.querySelector("#by-innerHTML");
+ target.innerHTML = '<option selected>First</option>' +
+ '<option selected>Second</option>';
+ assert_equals(target.selectedOptions[0].textContent, 'Second');
+
+ target.innerHTML = '<option selected>First</option>' +
+ '<optgroup><option selected>Second</option>' +
+ '<option selected>Third</option></optgroup>' +
+ '<option selected>Fourth</option>';
+ assert_equals(target.selectedOptions[0].textContent, 'Fourth');
+}, 'The last selected OPTION should win; Inserted by innerHTML');
+
+test (() => {
+ for (let insert_location = 0; insert_location < 3; ++insert_location) {
+ const target = document.querySelector('#by-innerHTML');
+ target.innerHTML = '<option>A</option>' +
+ '<option selected>C</option>' +
+ '<option>D</option>';
+ const refNode = target.querySelectorAll('option')[insert_location];
+
+ const opt = document.createElement('option');
+ opt.selected = true;
+ opt.textContent = 'B';
+ target.insertBefore(opt, refNode);
+ assert_equals(target.selectedOptions[0].textContent, 'B');
+ }
+}, 'If an OPTION says it is selected, it should be selected after it is inserted.');
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html
new file mode 100644
index 0000000000..acf192d1d5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<body>
+
+<form>
+<select>
+<option>Default</option>
+<option>Another</option>
+</select>
+
+<select>
+<option>Another</option>
+<option selected>Default</option>
+</select>
+
+<select multiple>
+<option>option 1</option>
+<option>option 2</option>
+</select>
+</form>
+
+</body>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html
new file mode 100644
index 0000000000..67da173ff2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Invalidation test on resetting &lt;select></title>
+<link rel="help" href="https://html.spec.whatwg.org/C/#the-select-element:concept-form-reset-control">
+<link rel="help" href="http://crbug.com/1087031">
+<link rel="match" href="reset-algorithm-rendering-ref.html">
+<body>
+
+<form>
+<select>
+<option>Default</option>
+<option>Another</option>
+</select>
+
+<select>
+<option>Another</option>
+<option selected>Default</option>
+</select>
+
+<select multiple>
+<option>option 1</option>
+<option>option 2</option>
+</select>
+</form>
+
+<script>
+const selects = document.querySelectorAll('select');
+selects[0].selectedIndex = 1;
+selects[1].selectedIndex = 0;
+selects[2].options[1].selected = true;
+
+document.documentElement.addEventListener('TestRendered', e => {
+ document.querySelector('form').reset();
+ e.target.removeAttribute('class');
+});
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/show-picker-child-iframe.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/show-picker-child-iframe.html
new file mode 100644
index 0000000000..bba3989824
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/show-picker-child-iframe.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Test showPicker() in an iframe</title>
+<script type=module>
+ const urlParams = new URLSearchParams(location.search);
+ const documentDomain = urlParams.get('documentDomain');
+ if (documentDomain) {
+ document.domain = documentDomain;
+ }
+
+ let securityErrors = [];
+ const select = document.createElement("select");
+ try {
+ select.showPicker();
+ } catch (error) {
+ if (error instanceof DOMException && error.name == 'SecurityError') {
+ securityErrors.push("select");
+ }
+ }
+ parent.postMessage(securityErrors.join(','), "*");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css b/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css
new file mode 100644
index 0000000000..a7e9a87cdf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/resources/stylable-select-styles.css
@@ -0,0 +1,18 @@
+.stylable-select-datalist {
+ box-shadow: 0px 12.8px 28.8px rgba(0, 0, 0, 0.13), 0px 0px 9.2px rgba(0, 0, 0, 0.11);
+ box-sizing: border-box;
+ overflow: auto;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 0.25em;
+ padding: 0.25em 0;
+ background-color: Field;
+ margin: 0;
+ inset: auto;
+ min-inline-size: anchor-size(self-inline);
+ min-block-size: 1lh;
+ inset-block-start: anchor(self-end);
+ inset-inline-start: anchor(self-start);
+
+ font-family: Arial;
+ font-size: 13.3333px;
+}
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-optgroup.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-optgroup.html
new file mode 100644
index 0000000000..fab5332f26
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-optgroup.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1477785">
+<link rel=help href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<select>
+ <option id=opt1>opt1</option>
+ <optgroup label=group1>
+ <option id=opt2>opt2</option>
+ </optgroup>
+</select>
+
+<script>
+test(() => {
+ const select = document.querySelector('select');
+ const optgroup = document.querySelector('optgroup');
+ const newOption = document.createElement('option');
+ newOption.textContent = 'new option';
+
+ select.options.add(newOption, 1);
+ assert_equals(select.options.length, 3);
+ assert_equals(select.options[0], opt1, 'First item should be opt1.');
+ assert_equals(select.options[1], newOption, 'Second item should be newOption.');
+ assert_equals(select.options[2], opt2, 'Third item should be opt2.');
+ assert_equals(newOption.parentNode, optgroup, 'The new option should be inside the optgroup.');
+}, 'select.add() with an index should work when the target is inside an optgroup.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-option-crash.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-option-crash.html
new file mode 100644
index 0000000000..78e9e7de53
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add-option-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1178128">
+
+<script>
+function iframeloadhandler() {
+ selectid[5] = optionid;
+}
+</script>
+<option id="optionid" selected>
+ <select id="selectid">
+ <select>
+ <iframe onload="iframeloadhandler()">
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add.html
new file mode 100644
index 0000000000..910be348ae
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-add.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTMLSelectElement Test: add()</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-add-dev">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<form style="display:none">
+ <option id="testoption">
+ <select id="testselect1">
+ </select>
+ <select id="testselect2">
+ <option>TEST</option>
+ </select>
+ </option>
+</form>
+
+<script>
+
+test(() => {
+ let testselect1 = document.getElementById("testselect1");
+ let opt1 = new Option("Marry","1");
+ testselect1.add(opt1);
+ assert_equals(testselect1.options[0].value, "1");
+}, "test that HTMLSelectElement.add method can add option element");
+
+test(() => {
+ let testselect2 = document.getElementById("testselect2");
+ let opt2 = document.getElementById("testoption");
+ assert_throws_dom("HierarchyRequestError", () => {
+ testselect2.add(opt2);
+ });
+}, "test that HierarchyRequestError exception must be thrown when element is an ancestor of the element into which it is to be inserted");
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-ask-for-reset.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-ask-for-reset.html
new file mode 100644
index 0000000000..822114fb26
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-ask-for-reset.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLSelectElement ask for reset</title>
+<link rel="author" title="Dongie Agnir" href="dongie.agnir@gmail.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ var select = makeSelect(5);
+
+ select.children[4].selected = true;
+ unselectedExcept(select, 4);
+
+ select.children[4].remove();
+ unselectedExcept(select, 0); // remove selected node, should default to first
+
+ select.children[3].selected = true;
+
+ select.children[0].remove();
+ unselectedExcept(select, 2); // last node still selected
+
+ select.size = 2;
+ select.children[2].remove();
+
+ unselectedExcept(select, null);
+}, "ask for reset on node remove, non multiple.");
+
+test(function() {
+ var select = makeSelect(3);
+ select.children[1].selected = true;
+
+ // insert selected option, should remain selected
+ var opt4 = document.createElement("option");
+ opt4.selected = true;
+ select.appendChild(opt4);
+ unselectedExcept(select, 3);
+
+ // insert unselected, 3 should remain selected
+ var opt5 = document.createElement("option");
+ select.appendChild(opt5);
+ unselectedExcept(select, 3);
+}, "ask for reset on node insert, non multiple.");
+
+test(function() {
+ var select = makeSelect(3);
+
+ var options = select.children;
+
+ // select options from first to last
+ for (var i = 0; i < options.length; ++i) {
+ options[i].selected = true;
+ unselectedExcept(select, i);
+ }
+
+ // select options from last to first
+ for (var i = options.length - 1; i >= 0; --i) {
+ options[i].selected = true;
+ unselectedExcept(select, i);
+ }
+
+ options[2].selected = true;
+ options[2].selected = false; // none selected
+ unselectedExcept(select, 0);
+
+ // disable first so option at index 1 is first eligible
+ options[0].disabled = true;
+ options[2].selected = true;
+ options[2].selected = false; // none selected
+ unselectedExcept(select, 1);
+
+ select.size = 2;
+ options[1].selected = false;
+ unselectedExcept(select, null); // size > 1 so should not default to any
+}, "change selectedness of option, non multiple.");
+
+
+function unselectedExcept(sel, opt) {
+ for (var i = 0; i < sel.children.length; ++i) {
+ if (i != opt) {
+ assert_false(sel.children[i].selected, "option should not be selected.");
+ }
+ if (opt != null) {
+ assert_true(sel.children[opt].selected, "option should be selected.");
+ }
+ }
+}
+
+function makeSelect(n) {
+ var sel = document.createElement("select");
+ for (var i = 0; i < n; ++i) {
+ opt = document.createElement("option");
+ sel.appendChild(opt);
+ }
+ return sel;
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html
new file mode 100644
index 0000000000..46bbd0ccd0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel=stylesheet href="resources/stylable-select-styles.css">
+
+<button popovertarget=popover id=button>button</button>
+<div id=popover popover=auto anchor=button class=stylable-select-datalist>
+ <option>one</option>
+ <option>two</option>
+</div>
+
+<script>
+document.getElementById('popover').showPopover();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html
new file mode 100644
index 0000000000..b74957feed
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-child-button-and-datalist.tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<link rel=match href="select-child-button-and-datalist-ref.html">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<select>
+ <button type=popover>button</button>
+ <datalist>
+ <option>one</option>
+ <option>two</option>
+ </datalist>
+</select>
+
+<script>
+document.querySelector('button').click();
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-in-table-crash.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-in-table-crash.html
new file mode 100644
index 0000000000..d1f1cee217
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-in-table-crash.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1519397">
+<table><select>A0A0AA<<datalist><title></title><table><table><td>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-multiple.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-multiple.html
new file mode 100644
index 0000000000..e348064151
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-multiple.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLSelectElement ask for reset</title>
+<link rel="author" title="Sebastian Mayr" href="wpt@smayr.name">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<select multiple id="initial-selected">
+ <option selected>Test 1</option>
+ <option selected>Test 2</option>
+</select>
+<select multiple id="scripted-select">
+ <option selected>Test 1</option>
+ <option>Test 2</option>
+</select>
+<div id=log></div>
+<script>
+"use strict";
+
+test(() => {
+
+ const select = document.getElementById("initial-selected");
+ assert_true(select.options[0].selected, "first option should be selected.");
+ assert_true(select.options[1].selected, "second option should be selected.");
+
+}, "multiple selected options exist, both set from markup");
+
+test(() => {
+
+ const select = document.getElementById("initial-selected");
+ select.options[1].selected = true;
+
+ assert_true(select.options[0].selected, "first option should be selected.");
+ assert_true(select.options[1].selected, "second option should be selected.");
+
+}, "multiple selected options exist, one set from script");
+
+// crbug.com/1245443
+test(() => {
+ let select = document.createElement("select");
+ select.length = 4;
+ let o1 = select.options.item(1);
+ select.multiple = true;
+ select.selectedIndex = 2;
+ o1.selected = true;
+ select.multiple = false;
+ assert_equals(select.selectedOptions.length, 1);
+}, "Removing multiple attribute reduces the number of selected OPTIONs to 1");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-named-getter.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-named-getter.html
new file mode 100644
index 0000000000..da43da9d92
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-named-getter.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Absence of a named getter on HTMLSelectElement</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<select id=select>
+ <option id=op1>A</option>
+ <option name=op2>B</option>
+ <option id=op3 name=op4>C</option>
+ <option id=>D</option>
+ <option name=>D</option>
+</select>
+<script>
+test(function() {
+ var select = document.getElementById("select");
+ assert_equals(select.op1, undefined);
+ assert_false("op1" in select);
+ assert_equals(select.namedItem("op1"), select.children[0]);
+}, "Option with id")
+
+test(function() {
+ var select = document.getElementById("select");
+ assert_equals(select.op2, undefined);
+ assert_false("op2" in select);
+ assert_equals(select.namedItem("op2"), select.children[1]);
+}, "Option with name")
+
+test(function() {
+ var select = document.getElementById("select");
+ assert_equals(select.op3, undefined);
+ assert_false("op3" in select);
+ assert_equals(select.namedItem("op3"), select.children[2]);
+
+ assert_equals(select.op4, undefined);
+ assert_false("op4" in select);
+ assert_equals(select.namedItem("op4"), select.children[2]);
+}, "Option with name and id")
+
+test(function() {
+ var select = document.getElementById("select");
+ assert_equals(select[""], undefined);
+ assert_false("" in select);
+ assert_equals(select.namedItem(""), null);
+}, "Empty string name");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html
new file mode 100644
index 0000000000..31133446d4
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-parsing.tentative.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9799">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+
+<select id=s1>
+ <div>div 1</div>
+ <button>button</button>
+ <div>div 2</div>
+ <datalist>
+ <option>option</option>
+ </datalist>
+ <div>div 3</div>
+</select>
+
+<select id=s2>
+ <button>button
+</select>
+
+<select id=s3>
+ <datalist>datalist
+</select>
+
+<select id=s4>
+ <button>
+ <select></select>
+ </button>
+</select>
+
+<select id=s5>
+ <button>
+ <div>
+ <select>
+</select>
+
+<select id=s6>
+<button>
+<button></button>
+</button>
+<datalist>
+<datalist></datalist>
+</datalist>
+</select>
+
+<div id=afterlast>
+ keep this div after the last test case
+</div>
+
+<script>
+test(() => {
+ // The document.body check here and in the other tests is to make sure that a
+ // previous test case didn't leave the HTML parser open on another element.
+ assert_equals(document.getElementById('s1').parentNode, document.body);
+ assert_equals(document.getElementById('s1').innerHTML, `
+ div 1
+ <button>button</button>
+ div 2
+ <datalist>
+ <option>option</option>
+ </datalist>
+ div 3
+`);
+}, '<button>s and <datalist>s should be allowed in <select>.');
+
+test(() => {
+ assert_equals(document.getElementById('s2').parentNode, document.body);
+ assert_equals(document.getElementById('s2').innerHTML, `
+ <button>button
+</button>`);
+}, '</select> should close <button>.');
+
+test(() => {
+ assert_equals(document.getElementById('s3').parentNode, document.body);
+ assert_equals(document.getElementById('s3').innerHTML, `
+ <datalist>datalist
+</datalist>`);
+}, '</select> should close <datalist>.');
+
+test(() => {
+ assert_equals(document.getElementById('s4').parentNode, document.body);
+ assert_equals(document.getElementById('s4').innerHTML, `
+ <button>
+ </button>`);
+}, '<select> in <button> in <select> should remove inner <select>.');
+
+test(() => {
+ assert_equals(document.getElementById('s5').parentNode, document.body);
+ assert_equals(document.getElementById('s5').innerHTML, `
+ <button>
+ <div>
+ </div></button>`);
+}, '<select> in <select><button><div> should remove inner <select>.');
+
+test(() => {
+ assert_equals(document.getElementById('s6').parentNode, document.body);
+ assert_equals(document.getElementById('s6').innerHTML, `
+<button>
+</button>
+
+<datalist>
+</datalist>
+
+`);
+}, 'Nested <button>s or <datalist>s in <select> should be dropped.');
+
+test(() => {
+ assert_equals(document.getElementById('afterlast').parentNode, document.body);
+}, 'The last test should not leave any tags open after parsing.');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-remove.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-remove.html
new file mode 100644
index 0000000000..cf2128bd15
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-remove.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLSelectElement.remove</title>
+<link rel="author" title="Ms2ger" href="Ms2ger@gmail.com">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-childnode-remove">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-select-remove">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-htmloptionscollection-remove">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+function testRemove(getter, desc) {
+ test(function() {
+ var div = document.createElement("div");
+ var select = document.createElement("select");
+ div.appendChild(select);
+ assert_equals(select.parentNode, div);
+
+ var options = [];
+ for (var i = 0; i < 3; ++i) {
+ var option = document.createElement("option");
+ option.textContent = String(i);
+ select.appendChild(option);
+ options.push(option);
+ }
+
+ getter(select).remove(-1);
+ assert_array_equals(select.options, options, "After remove(-1)");
+ assert_equals(select.parentNode, div);
+
+ getter(select).remove(3);
+ assert_array_equals(select.options, options, "After remove(3)");
+ assert_equals(select.parentNode, div);
+
+ getter(select).remove(0);
+ assert_array_equals(select.options, [options[1], options[2]], "After remove(0)");
+ assert_equals(select.parentNode, div);
+ }, desc)
+}
+testRemove(function(select) { return select; }, "select.remove(n) should work");
+testRemove(function(select) { return select.options; }, "select.options.remove(n) should work");
+test(function() {
+ var div = document.createElement("div");
+ var select = document.createElement("select");
+ div.appendChild(select);
+ assert_equals(select.parentNode, div);
+ assert_equals(div.firstChild, select);
+
+ select.remove();
+ assert_equals(select.parentNode, null);
+ assert_equals(div.firstChild, null);
+}, "remove() should work on select elements.")
+test(function() {
+ var div = document.createElement("div");
+ var select = document.createElement("select");
+ div.appendChild(select);
+ assert_equals(select.parentNode, div);
+ assert_equals(div.firstChild, select);
+
+ Element.prototype.remove.call(select);
+ assert_equals(select.parentNode, null);
+ assert_equals(div.firstChild, null);
+}, "Element#remove() should work on select elements.")
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-selectedOptions.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-selectedOptions.html
new file mode 100644
index 0000000000..bd5984a6b2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-selectedOptions.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>HTMLSelectElement.selectedOptions</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-select-selectedoptions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+
+<select id="select-none-selected">
+ <option>One</option>
+ <option>Two</option>
+ <option>Three</option>
+</select>
+
+<select id="select-one-selected">
+ <option>One</option>
+ <option selected>Two</option>
+ <option>Three</option>
+</select>
+
+<select multiple id="multiple-select-none-selected">
+ <option>One</option>
+ <option>Two</option>
+ <option>Three</option>
+</select>
+
+<select multiple id="multiple-select-two-selected">
+ <option>One</option>
+ <option selected>Two</option>
+ <option selected>Three</option>
+</select>
+
+<select id="select-named-selected">
+ <option>One</option>
+ <option>Two</option>
+ <option id="named-option" selected>Three</option>
+</select>
+
+<select id="invalid-select">
+ <option selected>One</option>
+ <option selected>Two</option>
+ <option>Three</option>
+</select>
+
+<select id="select-same-object">
+ <option>One</option>
+ <option selected>Two</option>
+ <option>Three</option>
+</select>
+
+<select multiple id="select-same-object-change">
+ <option selected>One</option>
+ <option selected>Two</option>
+ <option selected>Three</option>
+</select>
+
+<script>
+"use strict";
+
+test(() => {
+ const select = document.getElementById("select-none-selected");
+
+ assert_array_equals(select.selectedOptions, [select.children[0]]);
+ assert_equals(select.selectedOptions.length, 1);
+
+}, ".selectedOptions with no selected option");
+
+test(() => {
+ const select = document.getElementById("select-one-selected");
+
+ assert_array_equals(select.selectedOptions, [select.children[1]]);
+ assert_equals(select.selectedOptions.length, 1);
+}, ".selectedOptions with one selected option");
+
+test(() => {
+ const select = document.getElementById("multiple-select-none-selected");
+
+ assert_equals(select.selectedOptions.item(0), null);
+ assert_equals(select.selectedOptions.length, 0);
+}, ".selectedOptions using the 'multiple' attribute with no selected options");
+
+test(() => {
+ const select = document.getElementById("multiple-select-two-selected");
+
+ assert_equals(select.selectedOptions.item(0), select.children[1]);
+ assert_equals(select.selectedOptions.item(1), select.children[2]);
+ assert_equals(select.selectedOptions.length, 2);
+}, ".selectedOptions using the 'multiple' attribute with two selected options");
+
+// "A select element whose multiple attribute is not specified must not have
+// more than one descendant option element with its selected attribute set."
+// - https://html.spec.whatwg.org/multipage/forms.html#the-option-element:the-select-element-6
+
+// "If two or more option elements in the select element's list of options
+// have their selectedness set to true, set the selectedness of all but
+// the last option element with its selectedness set to true in the list of
+// options in tree order to false."
+// - https://html.spec.whatwg.org/multipage/forms.html#the-select-element:the-option-element-21
+test(() => {
+ const select = document.getElementById("invalid-select");
+
+ assert_array_equals(select.selectedOptions, [select.children[1]]);
+ assert_equals(select.selectedOptions.length, 1);
+
+}, ".selectedOptions without the 'multiple' attribute but " +
+ "more than one selected option should return the last one");
+
+test(() => {
+ const select = document.getElementById("select-named-selected");
+
+ assert_equals(select.selectedOptions.constructor, HTMLCollection);
+ assert_equals(select.selectedOptions.namedItem("named-option"), select.children[2]);
+}, ".selectedOptions should return `HTMLCollection` instance");
+
+test(() => {
+ const select = document.getElementById("select-same-object");
+ const selectAgain = document.getElementById("select-same-object");
+
+ assert_equals(select.selectedOptions, selectAgain.selectedOptions);
+
+}, ".selectedOptions should always return the same value - [SameObject]");
+
+test(() => {
+ const select = document.getElementById("select-same-object-change");
+ const before = select.selectedOptions;
+ assert_equals(before.length, 3);
+
+ select.selectedOptions[1].selected = false;
+
+ const after = select.selectedOptions;
+
+ assert_equals(before, after);
+ assert_equals(before.length, 2);
+ assert_equals(after.length, 2);
+
+}, ".selectedOptions should return the same object after selection changes - [SameObject]");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-setcustomvalidity.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-setcustomvalidity.html
new file mode 100644
index 0000000000..15308c1a8f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-setcustomvalidity.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<title>select setCustomValidity</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<select id='select_test'></select>
+
+<script>
+
+test(() => {
+ let elem = document.getElementById("select_test");
+ assert_false(elem.validity.customError);
+ elem.setCustomValidity("custom error");
+ assert_true(elem.validity.customError);
+}, "select setCustomValidity is correct")
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-validity.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-validity.html
new file mode 100644
index 0000000000..9f044879d9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-validity.html
@@ -0,0 +1,124 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLSelectElement.checkValidity</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#the-select-element:attr-select-required-4">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+
+test(function() {
+ var select = document.createElement('select');
+ assert_true(select.willValidate, "A select element is a submittable element that is a candidate for constraint validation.");
+ var placeholder = document.createElement('option');
+ select.appendChild(placeholder);
+ assert_true(select.checkValidity(), "Always valid when the select isn't a required value.");
+ select.required = true;
+ assert_true(placeholder.selected, "If display size is 1, multiple is absent and no options have selectedness true, the first option is selected.");
+ assert_equals(select.value, "", "The placeholder's value should be the select's value right now");
+ assert_false(select.checkValidity(), "A selected placeholder option should invalidate the select.");
+ var emptyOption = document.createElement('option');
+ select.appendChild(emptyOption);
+ emptyOption.selected = true;
+ assert_equals(select.value, "", "The empty value should be set.");
+ assert_true(select.checkValidity(), "An empty non-placeholder option should be a valid choice.");
+ var filledOption = document.createElement('option');
+ filledOption.value = "test";
+ select.appendChild(filledOption);
+ filledOption.selected = true;
+ assert_equals(select.value, "test", "The non-empty value should be set.");
+ assert_true(select.checkValidity(), "A non-empty non-placeholder option should be a valid choice.");
+ select.removeChild(placeholder);
+ select.appendChild(emptyOption); // move emptyOption to second place
+ emptyOption.selected = true;
+ assert_equals(select.value, "", "The empty value should be set.");
+ assert_true(select.checkValidity(), "Only the first option can be seen as a placeholder.");
+ placeholder.disabled = true;
+ select.insertBefore(placeholder, filledOption);
+ placeholder.selected = true;
+ assert_equals(select.value, "", "A disabled first placeholder option should result in an empty value.");
+ assert_false(select.checkValidity(), "A disabled first placeholder option should invalidate the select.");
+}, "Placeholder label options within a select");
+
+test(function() {
+ var select = document.createElement('select');
+ select.required = true;
+ var optgroup = document.createElement('optgroup');
+ var emptyOption = document.createElement('option');
+ optgroup.appendChild(emptyOption);
+ select.appendChild(optgroup);
+ emptyOption.selected = true;
+ assert_equals(select.value, "", "The empty value should be set.");
+ assert_true(select.checkValidity(), "The first option is not considered a placeholder if it is located within an optgroup.");
+ var otherEmptyOption = document.createElement('option');
+ otherEmptyOption.value = "";
+ select.appendChild(otherEmptyOption);
+ otherEmptyOption.selected = true;
+ assert_equals(select.value, "", "The empty value should be set.");
+ assert_true(select.checkValidity(), "The empty option should be accepted as it is not the first option in the tree ordered list.");
+}, "Placeholder label-like options within optgroup");
+
+test(function() {
+ var select = document.createElement('select');
+ select.required = true;
+ select.size = 2;
+ var emptyOption = document.createElement('option');
+ select.appendChild(emptyOption);
+ assert_false(emptyOption.selected, "Display size is not 1, so the first option should not be selected.");
+ assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid.");
+ emptyOption.selected = true;
+ assert_true(select.checkValidity(), "If one option is selected, the select should be considered valid.");
+ var otherEmptyOption = document.createElement('option');
+ otherEmptyOption.value = "";
+ select.appendChild(otherEmptyOption);
+ otherEmptyOption.selected = true;
+ assert_false(emptyOption.selected, "Whenever an option has its selectiveness set to true, the other options must be set to false.");
+ otherEmptyOption.selected = false;
+ assert_false(otherEmptyOption.selected, "It should be possible to set the selectiveness to false with a display size more than one.");
+ assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid.");
+}, "Validation on selects with display size set as more than one");
+
+test(function() {
+ var select = document.createElement('select');
+ select.required = true;
+ select.multiple = true;
+ var emptyOption = document.createElement('option');
+ select.appendChild(emptyOption);
+ assert_false(select.checkValidity(), "If no options are selected the select must be seen as invalid.");
+ emptyOption.selected = true;
+ assert_true(select.checkValidity(), "If one option is selected, the select should be considered valid.");
+ var optgroup = document.createElement('optgroup');
+ optgroup.appendChild(emptyOption); // Move option to optgroup
+ select.appendChild(optgroup);
+ assert_true(select.checkValidity(), "If one option within an optgroup or not is selected, the select should be considered valid.");
+}, "Validation on selects with multiple set");
+
+test(function() {
+ var select = document.createElement('select');
+ select.required = true;
+ var option = document.createElement('option');
+ option.value = 'test';
+ option.disabled = true;
+ option.selected = true;
+ select.appendChild(option);
+ assert_true(select.checkValidity(), "When a required select has an option that is selected and disabled, the select should be considered valid.");
+}, "Validation on selects with non-empty disabled option");
+
+test(function() {
+ var select = document.createElement('select');
+ select.required = true;
+ var placeholder = document.createElement('option');
+ select.appendChild(placeholder);
+ var nonPlaceholder = document.createElement('option');
+ nonPlaceholder.textContent = "non-placeholder-option";
+ select.appendChild(nonPlaceholder);
+
+ assert_false(select.checkValidity(), "If the placeholder label option is selected, required select element shouldn't be valid.");
+ placeholder.remove();
+ assert_true(select.checkValidity(), "If the placeholder label option is removed, required select element should become valid.");
+ select.prepend(placeholder);
+ assert_false(select.checkValidity(), "If the placeholder label option is selected, required select element shouldn't be valid.");
+
+}, "Remove and add back the placeholder label option");
+
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-value.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-value.html
new file mode 100644
index 0000000000..d8d5263e3e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-value.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>HTMLSelectElement.value</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#dom-select-value">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<select id=sel1>
+ <option value=0></option>
+ <option selected value=1></option>
+</select>
+
+<select id=sel2>
+ <optgroup>
+ <option value=0></option>
+ </optgroup>
+ <optgroup></optgroup>
+ <optgroup>
+ <option></option>
+ <option value=1></option>
+ <option selected value=2></option>
+ </optgroup>
+</select>
+
+<select id=sel3>
+ <option selected value=1></option>
+</select>
+
+<select id=sel4></select>
+
+<script>
+test(function() {
+ var select = document.getElementById('sel1');
+ assert_equals(select.value, '1');
+}, 'options');
+
+test(function() {
+ var select = document.getElementById('sel2');
+ assert_equals(select.value, '2');
+}, 'optgroups');
+
+test(function() {
+ var select = document.getElementById('sel3');
+ var option = select.options[0];
+ var div = document.createElement('div');
+ select.appendChild(div);
+ div.appendChild(option);
+ assert_equals(select.value, '');
+}, 'option is child of div');
+
+test(function() {
+ var select = document.getElementById('sel4');
+ assert_equals(select.value, '');
+}, 'no options');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/select-willvalidate-readonly-attribute.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-willvalidate-readonly-attribute.html
new file mode 100644
index 0000000000..d3f4ce43cf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/select-willvalidate-readonly-attribute.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Select element with "readonly" attribute shouldn't be barred from constraint validation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<select id="singleSelect" readonly>
+ <option>1
+ <option>2
+</select>
+
+<select id="multiSelect" readonly multiple>
+ <option>a
+ <option>b
+ <option>c
+ <option>d
+</select>
+
+<script>
+ test(() => {
+ assert_true(singleSelect.willValidate);
+ assert_true(multiSelect.willValidate);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/selected-index.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/selected-index.html
new file mode 100644
index 0000000000..7f7fd9a1a2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/selected-index.html
@@ -0,0 +1,143 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLSelectElement selectedIndex</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<form id=form>
+ <select id=empty></select>
+
+ <select id=default>
+ <option></option>
+ <option></option>
+ <option></option>
+ <option></option>
+ <option></option>
+ </select>
+
+ <select id=disabled>
+ <option disabled></option>
+ <option></option>
+ </select>
+
+ <select id=selected>
+ <option></option>
+ <option selected></option>
+ </select>
+
+ <select id=display-none>
+ <option style="display:none"></option>
+ <option></option>
+ </select>
+
+ <select id=minus-one>
+ <option value=1>1</option>
+ <option value=2>2</option>
+ </select>
+</form>
+
+<script>
+function assertSelectedIndex(select, value) {
+ assert_equals(select.selectedIndex, value);
+ assert_equals(select.options.selectedIndex, value);
+}
+
+function assertSelectValue(select, value) {
+ assert_equals(select.value, value);
+}
+
+test(function () {
+ var select = document.getElementById('empty');
+ assertSelectedIndex(select, -1);
+}, "get empty");
+
+test(function () {
+ var select = document.getElementById('default');
+ assertSelectedIndex(select, 0);
+}, "get default");
+
+test(function () {
+ var select = document.getElementById('disabled');
+ assertSelectedIndex(select, 1);
+}, "get disabled");
+
+test(function () {
+ var select = document.getElementById('selected');
+ assertSelectedIndex(select, 1);
+}, "get unselected");
+
+test(function () {
+ var select = document.getElementById('empty');
+ select.selectedIndex = 1;
+ assertSelectedIndex(select, -1);
+}, "set empty (HTMLSelectElement)");
+
+test(function () {
+ var select = document.getElementById('empty');
+ select.options.selectedIndex = 1;
+ assertSelectedIndex(select, -1);
+}, "set empty (HTMLOptionsCollection)");
+
+test(function () {
+ var select = document.getElementById('default');
+ assertSelectedIndex(select, 0);
+ select.selectedIndex = 2;
+ assertSelectedIndex(select, 2);
+ this.add_cleanup(() => { select.selectedIndex = 0; });
+}, "set (HTMLSelectElement)");
+
+test(function () {
+ var select = document.getElementById('default');
+ assertSelectedIndex(select, 0);
+ select.options.selectedIndex = 2;
+ assertSelectedIndex(select, 2);
+ this.add_cleanup(() => { select.selectedIndex = 0; });
+}, "set (HTMLOptionsCollection)");
+
+test(function () {
+ var select = document.getElementById('selected');
+ var form = document.getElementById('form');
+ assertSelectedIndex(select, 1);
+ select.selectedIndex = 0;
+ assertSelectedIndex(select, 0);
+ form.reset();
+ assertSelectedIndex(select, 1);
+}, "set and reset (HTMLSelectElement)");
+
+test(function () {
+ var select = document.getElementById('selected');
+ var form = document.getElementById('form');
+ assertSelectedIndex(select, 1);
+ select.options.selectedIndex = 0;
+ assertSelectedIndex(select, 0);
+ form.reset();
+ assertSelectedIndex(select, 1);
+}, "set and reset (HTMLOptionsCollection)");
+
+test(function () {
+ var select = document.getElementById('display-none');
+ assertSelectedIndex(select, 0);
+}, "get display:none");
+
+test(function () {
+ var select = document.getElementById('display-none');
+ select.offsetTop; // force rendering
+ assertSelectedIndex(select, 0);
+ select.options[1].selected = true;
+ assertSelectedIndex(select, 1);
+ select.options[1].selected = false;
+ assertSelectedIndex(select, 0);
+}, "reset to display:none");
+
+test(function() {
+ var select = document.getElementById("minus-one");
+ assertSelectedIndex(select, 0);
+
+ select.selectedIndex = -1;
+
+ assertSelectedIndex(select, -1);
+ assertSelectValue(select, "");
+
+}, "set selectedIndex=-1");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-cv-hidden.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-cv-hidden.html
new file mode 100644
index 0000000000..8990734f93
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-cv-hidden.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Test showPicker() being rendered requirement with content-visibility</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>
+<div style="content-visibility: hidden">
+ <select id="select">
+ <option>Item 1</option>
+ </select>
+</div>
+<script>
+promise_test(async t => {
+ await test_driver.bless('show picker');
+ assert_throws_dom('NotSupportedError', () => { select.showPicker(); });
+
+ // Test that dynamically changing to actually being rendered works.
+ await test_driver.bless('show picker');
+ select.parentElement.style.contentVisibility = 'visible';
+ select.showPicker();
+ select.blur();
+}, 'select showPicker() throws when content-visibility hidden');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-rendered.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-rendered.html
new file mode 100644
index 0000000000..e7be4aea52
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-being-rendered.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>Test showPicker() being rendered 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>
+<select id="select" style="display: none;">
+ <option>Item 1</option>
+</select>
+<script>
+promise_test(async t => {
+ await test_driver.bless('show picker');
+ assert_throws_dom('NotSupportedError', () => { select.showPicker(); });
+
+ // Test that dynamically changing to actually being rendered works.
+ await test_driver.bless('show picker');
+ select.style.display = 'inline-block';
+ select.showPicker();
+ select.blur();
+}, 'select showPicker() throws when not being rendered');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-cross-origin-iframe.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-cross-origin-iframe.tentative.html
new file mode 100644
index 0000000000..3f710b39c6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-cross-origin-iframe.tentative.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,
+ "select",
+ "In cross-origin iframes, showPicker() throws a SecurityError."
+ );
+ });
+
+ 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,
+ "select",
+ "In cross-origin but same-origin-domain iframes, showPicker() throws a SecurityError."
+ );
+ });
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-disabled.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-disabled.tentative.html
new file mode 100644
index 0000000000..f20bc2cf61
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-disabled.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>Test showPicker() disabled 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>
+<select id="select" disabled>
+ <option>Item 1</option>
+</select>
+<script>
+ test(() => {
+ assert_throws_dom('InvalidStateError', () => { select.showPicker(); });
+ }, 'select showPicker() throws when disabled');
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-multiple.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-multiple.tentative.html
new file mode 100644
index 0000000000..c38e98ee4e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-multiple.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test showPicker() on multiple selects</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>
+<select id="select" multiple>
+ <option>Item 1</option>
+</select>
+<script>
+promise_test(async t => {
+ await test_driver.bless('show picker');
+ select.showPicker();
+ select.blur();
+}, `select showPicker() does not throw when called on a <select multiple>`);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-size.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-size.tentative.html
new file mode 100644
index 0000000000..b9b10c42a9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-size.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test showPicker() on sized selects</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>
+<select id="select" size="4">
+ <option>Item 1</option>
+</select>
+<script>
+promise_test(async t => {
+ await test_driver.bless('show picker');
+ select.showPicker();
+ select.blur();
+}, `select showPicker() does not throw when called on a <select size="4">`);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-user-gesture.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-user-gesture.tentative.html
new file mode 100644
index 0000000000..e917fe2a61
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/show-picker-user-gesture.tentative.html
@@ -0,0 +1,24 @@
+<!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>
+ test(() => {
+ const select = document.createElement("select");
+
+ assert_throws_dom('NotAllowedError', () => { select.showPicker(); });
+ }, `select showPicker() requires a user gesture`);
+
+ promise_test(async t => {
+ const select = document.createElement("select");
+ document.body.append(select)
+
+ await test_driver.bless('show picker');
+ select.showPicker();
+ select.blur();
+ }, `select showPicker() does not throw when user activation is active`);
+</script> \ No newline at end of file