Bug 1646907 [wpt PR 24247] - SELECT element: Fix a regression on adding multiple selected OPTIONs to a single-selection SELECT, a=testonly
authorKent Tamura <tkent@chromium.org>
Mon, 22 Jun 2020 10:44:45 +0000
changeset 600936 28cfa6865c05bc6e48070f45e4c1ce0d9f8c46c3
parent 600935 7bdb48de0eaee90fe970078b5c28f4fe413f7297
child 600937 406df6d65cc57594968a45a1fe5ec067979ae53f
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1646907, 24247, 745230, 1095725, 2253260, 780174
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1646907 [wpt PR 24247] - SELECT element: Fix a regression on adding multiple selected OPTIONs to a single-selection SELECT, a=testonly Automatic update from web-platform-tests SELECT element: Fix a regression on adding multiple selected OPTIONs to a single-selection SELECT This CL fixes a regression caused by crrev.com/745230. Bug details: Suppose that |select.innerHTML = '<option selected>Option1' + '<option selected>Option2'| runs. Before crrev.com/745230, 1. Option1 is appended to the SELECT. 2. HTMLOptionElement::InsertedInto() and |HTMLSelectElement:: OptionInserted()| are called for Option1. 3. SelectOption(Option1) is called. 4. DeselectItemsWithoutValidation(Option1) is called 5. Option2 is appended to the SELECT. 6. HTMLOptionElement::InsertedInto() and |HTMLSelectElement:: OptionInserted()| are called for Option2. 7. SelectOption(Option2) is called. 8. DeselectItemsWithoutValidation(Option2) is called. Option1's selected state is cleared. Since crrev.com/745230, 1. Option1 is appended to the SELECT. 2. Option2 is appended to the SELECT. 3. HTMLSelectElement::ChildrenChanged() and |HTMLSelectElement:: OptionInserted()| are called for Option1. 4. SelectOption(Option1) is called. 5. DeselectItemsWithoutValidation(Option1) is called. Option2's selected state is cleared. 6. HTMLSelectElement::ChildrenChanged() and |HTMLSelectElement:: OptionInserted()| are called for Option2. 7. SelectOption(Option2) is NOT called because Option2's selected state was cleared. Fix: DeselectItemsWithoutValidation() should not update 'selected' state of OPTIONs for which OptionInserted() is not called yet. This CL adds a boolean flag to HTMLOptionElement, it represents whether OptionInserted() is called or not, and DeselectItemsWithoutValidation() checks the flag before updating 'selected' state. Bug: 1095725 Change-Id: If19b28c3edb877549ca498b661647466d03e6d1d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2253260 Commit-Queue: Kent Tamura <tkent@chromium.org> Auto-Submit: Kent Tamura <tkent@chromium.org> Reviewed-by: Yoshifumi Inoue <yosin@chromium.org> Cr-Commit-Position: refs/heads/master@{#780174} -- wpt-commits: e75a8342e588e36a6ab387846a50d077621143b4 wpt-pr: 24247
testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/forms/the-select-element/inserted-or-removed.html
@@ -0,0 +1,71 @@
+<!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-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');
+</script>
+</body>