diff options
Diffstat (limited to 'testing/web-platform/tests/html/semantics/forms/the-selectlist-element')
77 files changed, 3728 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance-ref.html new file mode 100644 index 0000000000..fd7f2b7bca --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<button>button</button> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance.tentative.html new file mode 100644 index 0000000000..3ab7044366 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/button-type-selectlist-appearance.tentative.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<link rel=match href="button-type-selectlist-appearance-ref.html"> + +<button type=selectlist>button</button> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-ask-for-reset.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-ask-for-reset.html new file mode 100644 index 0000000000..7cf2aff515 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-ask-for-reset.html @@ -0,0 +1,119 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: ask-for-reset</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<form name="fm1" id="form1"> + <selectlist id="selectlist1"> + <option>one</option> + <option>two</option> + </selectlist> + + <selectlist id="selectlist2"> + <option>one</option> + <option selected>two</option> + </selectlist> + + <selectlist id="selectlist3"> + <option>one</option> + <option selected>two</option> + <option selected>three</option> + </selectlist> +</form> + +<script> +function createSelectList(numberOfOptions) { + let selectList = document.createElement("selectlist"); + for (let i = 0; i < numberOfOptions; i++) { + let option = document.createElement("option"); + option.value = i; + selectList.appendChild(option); + } + return selectList; +} + +function checkSelection(selectList, selectedOptionIndex, msg) { + for (let i = 0; i < selectList.children.length; i++) { + if (i != selectedOptionIndex) { + assert_false(selectList.children[i].selected); + } + } + assert_true(selectList.children[selectedOptionIndex].selected, msg); + assert_equals(selectList.value, selectList.children[selectedOptionIndex].value); +} + +test(() => { + let selectList = createSelectList(5); + + selectList.children[4].selected = true; + checkSelection(selectList, 4); + + selectList.children[4].remove(); + checkSelection(selectList, 0, "After removing the selected option, selection should default to first option."); + + selectList.children[3].selected = true; + checkSelection(selectList, 3); + selectList.children[0].remove(); + checkSelection(selectList, 2, "Removing non-selected option should have no effect."); +}, "ask-for-reset when removing option"); + +test(() => { + let selectList = createSelectList(3); + selectList.children[1].selected = true; + + let newOption = document.createElement("option"); + newOption.selected = true; + selectList.appendChild(newOption); + checkSelection(selectList, 3, "Inserting a selected option should update selection."); + + let newOption2 = document.createElement("option"); + newOption2.selected = true; + selectList.prepend(newOption2); + checkSelection(selectList, 0, "Inserting a selected option should update selection, even though it's not last in tree order."); + + let newOption3 = document.createElement("option"); + selectList.appendChild(newOption3); + checkSelection(selectList, 0, "Inserting a non-selected option should have no effect."); +}, "ask-for-reset when inserting option"); + +test(() => { + let selectList = createSelectList(3); + let options = selectList.children; + + // select options from first to last + for (let i = 0; i < options.length; i++) { + options[i].selected = true; + checkSelection(selectList, i); + } + + // select options from last to first + for (let i = options.length - 1; i >= 0; i--) { + options[i].selected = true; + checkSelection(selectList, i); + } + + options[2].selected = true; + checkSelection(selectList, 2); + options[2].selected = false; + checkSelection(selectList, 0, "First non-disabled option should be selected."); + + options[0].disabled = true; + options[2].selected = true; + checkSelection(selectList, 2); + options[2].selected = false; + checkSelection(selectList, 1, "First non-disabled option should be selected."); +}, "ask-for-reset when changing selectedness of option"); + +test(() => { + let selectList1 = document.getElementById("selectlist1"); + let selectList2 = document.getElementById("selectlist2"); + let selectList3 = document.getElementById("selectlist3"); + + document.getElementById("form1").reset(); + + assert_equals(selectList1.value, "one", "First non-disabled option should be selected."); + assert_equals(selectList2.value, "two", "The selected option should be selected."); + assert_equals(selectList3.value, "three", "Last selected option should be selected.") +}, "ask-for-reset for form"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-closes-listbox.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-closes-listbox.tentative.html new file mode 100644 index 0000000000..d3e6febd78 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-closes-listbox.tentative.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1408838"> +<link rel=help href="https://github.com/openui/open-ui/issues/639"> +<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> + +<selectlist id=defaultbutton-defaultlistbox> + <option>one</option> + <option>two</option> +</selectlist> + +<selectlist id=custombutton-defaultlistbox> + <button type=selectlist>custom button</button> + <option>one</option> + <option>two</option> +</selectlist> + +<selectlist id=defaultbutton-customlistbox> + <listbox> + <option>one</option> + <option>two</option> + </listbox> +</selectlist> + +<selectlist id=custombutton-customlistbox> + <button type=selectlist>custom button</button> + <listbox> + <option>one</option> + <option>two</option> + </listbox> +</selectlist> + +<script> +document.querySelectorAll('selectlist').forEach(selectlist => { + promise_test(async () => { + assert_false(selectlist.matches(':open'), + 'The listbox should not be showing at the start of the test.'); + + await test_driver.click(selectlist); + assert_true(selectlist.matches(':open'), + 'The listbox should be showing after clicking the button.'); + + await test_driver.click(selectlist); + assert_false(selectlist.matches(':open'), + 'The listbox should be closed after clicking the button.'); + }, `${selectlist.id}: Clicking the selectlist's button should toggle the listbox.`); +}); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance-ref.html new file mode 100644 index 0000000000..37d4b1b471 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance-ref.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<button>hello world</button> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance.tentative.html new file mode 100644 index 0000000000..50ad339b05 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-appearance.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<link rel=match href="selectlist-button-type-appearance-ref.html"> + +<selectlist> + <button type=selectlist>hello world</button> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-behavior.tentative.html new file mode 100644 index 0000000000..cc7eb62a63 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-button-type-behavior.tentative.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<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> + +<selectlist> + <button type=selectlist id=b1>first button</button> + <button type=selectlist id=b2>second button</button> + <button id=b3>third button</button> + <option>option</option> +</selectlist> + +<script> +const ESC = '\uE00C' + +promise_test(async () => { + const selectlist = document.querySelector('selectlist'); + const b1 = document.getElementById('b1'); + const b2 = document.getElementById('b2'); + const b3 = document.getElementById('b3'); + + assert_false(selectlist.open, 'The selectlist should start closed.'); + await test_driver.click(b1); + assert_true(selectlist.open, 'The selectlist should get opened when the button is clicked.'); + + await test_driver.send_keys(selectlist, ESC); + assert_false(selectlist.open, 'Pressing escape should close the selectlist.'); + + await test_driver.click(b2); + assert_true(selectlist.open, 'The selectlist should get opened when a second type=selectlist button is clicked.'); + await test_driver.send_keys(selectlist, ESC); + assert_false(selectlist.open, 'Pressing escape should close the selectlist.'); + + await test_driver.click(b3); + assert_false(selectlist.open, 'Clicking a button witout type=selectlist should not open the listbox.'); + + b1.removeAttribute('type'); + await test_driver.click(b1); + assert_false(selectlist.open, 'If the button is not type=selectlist, it should not open the selectlist.'); +}, '<button type=selectlist> should open the parent selectlist when clicked.'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot-ref.html new file mode 100644 index 0000000000..faa96e1f27 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot-ref.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<style> +.container { + display: inline-flex; + font-family: sans-serif; + font-size: 0.875em; +} +</style> +<div class=container> + <div>first child</div> + <div>second child</div> +</div> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot.tentative.html new file mode 100644 index 0000000000..d8688d5957 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-default-button-slot.tentative.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<link rel=match href="selectlist-default-button-slot-ref.html"> +<meta rel=assert title="Child nodes of selectlist should be slotted into the button slot by default"> + +<selectlist> + <div>first child</div> + <div>second child</div> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-disabled.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-disabled.tentative.html new file mode 100644 index 0000000000..f557804d9b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-disabled.tentative.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<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> + +<script> +focused_element_id = null; + +function OnFocus(event) { + focused_element_id = event.target.id; +} +</script> + +<selectlist id="selectlist" onfocus="OnFocus(event)" disabled> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<script> +promise_test(async () => { + const selectlist = document.getElementById("selectlist"); + selectlist.focus(); + assert_equals(focused_element_id, null); +}, "Check that disabled <selectlist> cannot be focused"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-events.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-events.tentative.html new file mode 100644 index 0000000000..a88a3b1f7d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-events.tentative.html @@ -0,0 +1,244 @@ +<!DOCTYPE html> +<title>HTMLSelectListElement Test: events</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> + +<selectlist id="selectList0"> + <div slot="button" behavior="button"> + <span behavior="selected-value"></span> + <button id="selectList0-button">selectList0-button</button> + </div> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<selectlist id="selectList1"> + <option>one</option> + <option> + two + <button id="selectList1-button">selectList1-button</button> + </option> + <option>three</option> +</selectlist> + +<selectlist id="selectList2"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<selectlist id="selectList3"> + <option>same</option> + <option>same</option> +</selectlist> + +<selectlist id="selectList4"> + <option>one</option> + <option id="selectList4-option2">two</option> +</selectlist> + +<selectlist id="selectList5WithTabIndex" tabindex="1"> + <option>one</option> + <option>two</option> +</selectlist> + +<input id="input6"/> +<selectlist id="selectList7"> + <button slot="button" behavior="button" id="selectList7-button"> + selectList7-button + </button> + <option>one</option> + <option>two</option> +</selectlist> + +<script> + + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList = document.getElementById("selectList0"); + const selectListButton = document.getElementById("selectList0-button"); + assert_false(selectList.open); + const selectListButtonPromise = new Promise(async resolve => { + selectListButton.addEventListener("click", (e) => { + assert_false(selectList.open, "Listbox shouldn't have opened yet"); + // PreventDefaulting the event here should prevent UA controller code + // on the button part from opening the listbox. + e.preventDefault(); + resolve(); + }); + }); + + const selectListPromise = new Promise(async resolve => { + selectList.addEventListener("click", (e) => { + assert_true(e.defaultPrevented, "Event should have been defaultPrevented by selectListButton click handler"); + assert_false(selectList.open, "Listbox shouldn't have opened, because click event was defaultPrevented."); + resolve(); + }); + }); + + await clickOn(selectListButton); + return Promise.all([selectListButtonPromise, selectListPromise]); + }, "Button controller code should not run if the click event is preventDefaulted."); + + // See https://w3c.github.io/webdriver/#keyboard-actions + const KEY_CODE_MAP = { + 'Tab': '\uE004', + 'Enter': '\uE007', + 'Space': '\uE00D', + 'ArrowUp': '\uE013', + 'ArrowDown': '\uE015', + }; + + promise_test(async () => { + const selectList = document.getElementById("selectList1"); + const selectListButton = document.getElementById("selectList1-button"); + await clickOn(selectList); + assert_true(selectList.open); + const selectListButtonPromise = new Promise(async resolve => { + selectListButton.addEventListener("click", (e) => { + assert_true(selectList.open, "Listbox shouldn't have closed yet"); + // PreventDefaulting the event here should prevent UA controller code + // on the listbox part from selecting the option and closing the listbox. + e.preventDefault(); + resolve(); + }); + }); + + const selectListPromise = new Promise(async resolve => { + selectList.addEventListener("click", (e) => { + assert_true(e.defaultPrevented, "Event should have been defaultPrevented by selectListButton click handler"); + assert_true(selectList.open, "Listbox shouldn't have closed, because keydown event was defaultPrevented."); + assert_equals(selectList.value, "one", "<selectlist> shouldn't have changed value, because keydown event was defaultPrevented."); + resolve(); + }); + }); + + await clickOn(selectListButton); + return Promise.all([selectListButtonPromise, selectListPromise]); + }, "Listbox controller code should not run if the click event is preventDefaulted."); + + promise_test(async () => { + const selectList = document.getElementById("selectList2"); + const events = []; + + selectList.addEventListener("input", (e) => { + assert_true(e.composed, "input event should be composed."); + events.push('input'); + }); + selectList.addEventListener("change", (e) => { + assert_false(e.composed, "change event should not be composed."); + events.push('change'); + }); + + await clickOn(selectList); + assert_true(selectList.open); + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_false(selectList.open); + assert_equals(selectList.value, "one"); + assert_array_equals(events, [], "input and change shouldn't fire if value wansn't changed."); + + await clickOn(selectList); + assert_true(selectList.open); + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowDown); + assert_equals(selectList.value, "one", "value shouldn't change when user switches options with arrow key."); + assert_array_equals(events, ['input'], "input event should fire when user switches options with arrow key."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_equals(selectList.value, "two"); + assert_array_equals(events, ['input', 'input', 'change'], "input and change should fire after pressing enter."); + }, "<selectlist> should fire input and change events when new option is selected."); + + promise_test(async () => { + const selectList = document.getElementById("selectList3"); + const events = []; + + selectList.addEventListener("input", (e) => { + assert_true(e.composed, "input event should be composed."); + events.push('input'); + }); + selectList.addEventListener("change", (e) => { + assert_false(e.composed, "change event should not be composed."); + events.push('change'); + }); + + await clickOn(selectList); + assert_true(selectList.open); + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowDown); + assert_array_equals(events, ['input'], "input event should have fired after ArrowDown."); + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_array_equals(events, ['input', 'input', 'change'], "input and change should fire after pressing Enter."); + }, "<selectlist> should fire input and change events even when new selected option has the same value as the old."); + + promise_test(async () => { + const selectList = document.getElementById("selectList4"); + const selectListOption2 = document.getElementById("selectList4-option2"); + let input_event_count = 0; + let change_event_count = 0; + + selectList.addEventListener("input", (e) => { + assert_true(e.composed, "input event should be composed"); + assert_equals(input_event_count, 0, "input event should not fire twice"); + assert_equals(change_event_count, 0, "input event should not fire before change"); + input_event_count++; + }); + + selectList.addEventListener("change", (e) => { + assert_false(e.composed, "change event should not be composed"); + assert_equals(input_event_count, 1, "change event should fire after input"); + assert_equals(change_event_count, 0, "change event should not fire twice"); + change_event_count++; + }); + + await clickOn(selectList); + assert_true(selectList.open); + await clickOn(selectListOption2); + assert_equals(input_event_count, 1, "input event shouldn't fire when selected option didn't change"); + assert_equals(change_event_count, 1, "change event shouldn't fire when selected option didn't change"); + }, "<selectlist> should fire input and change events when option in listbox is clicked"); + + promise_test(async() => { + const selectList = document.getElementById("selectList2"); + await test_driver.send_keys(selectList, " "); + assert_true(selectList.open, "<Space> should open selectlist"); + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_false(selectList.open, "<Enter> should close selectlist"); + }, "Check that <Space> opens <selectlist>."); + + promise_test(async() => { + const selectList = document.getElementById("selectList5WithTabIndex"); + await test_driver.send_keys(selectList, " "); + assert_true(selectList.open, "<Space> should open selectlist"); + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_false(selectList.open, "<Enter> should close selectlist"); + }, "Check that <Space> opens <selectlist> when <selectlist> specifies tabindex"); + + promise_test(async() => { + const input6 = document.getElementById("input6"); + const selectList = document.getElementById("selectList7"); + const selectListButton = document.getElementById("selectList7-button") + + var keydown_count = 0; + selectListButton.addEventListener("keydown", (e) => { + keydown_count++; + }); + + // Focus selectlist via Tab traversal because focus() does not work when selectlist + // has custom slot. + // TODO(http://crbug.com/1440573) Fix this. + await test_driver.send_keys(input6, KEY_CODE_MAP.Tab); + + await test_driver.send_keys(selectList, "a"); + assert_equals(keydown_count, 1, "button in shadowroot should have observed keydown"); +}, "Test that <selectlist> button slot receives key events."); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size-ref.tentative.html new file mode 100644 index 0000000000..46d932c4b2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size-ref.tentative.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('option'); + document.body.appendChild(selectlist); + const button = selectlist.querySelector('.fake-selectlist-internal-selectlist-button'); + button.style.width = "400px"; + button.style.height = "50px"; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size.tentative.html new file mode 100644 index 0000000000..d9e52a9fff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-explicit-size.tentative.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<!-- Tests that selectlist respects explicit size --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-explicit-size-ref.tentative.html"> + +<style> +selectlist { + width:400px; + height:50px; +} +</style> +<selectlist> + <option>option</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size-ref.tentative.html new file mode 100644 index 0000000000..46d6dbdb9b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size-ref.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('option'); + document.body.appendChild(selectlist); + selectlist.style.fontSize = "48px"; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size.tentative.html new file mode 100644 index 0000000000..9c30e71bda --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-font-size.tentative.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<!-- Tests that selectlist respects explicit size --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-font-size-ref.tentative.html"> + +<style> +selectlist { + font-size:48px; +} +</style> +<selectlist> + <option>option</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-attribute.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-attribute.tentative.html new file mode 100644 index 0000000000..c1872b9303 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-attribute.tentative.html @@ -0,0 +1,231 @@ +<!-- This test is tentative until the <selectlist> gets adopted by standards. When that happens, + this test can be folded back into these tests: + html/semantics/forms/form-control-infrastructure/form_attribute.html + html/semantics/forms/form-control-infrastructure/form.html --> +<!DOCTYPE html> +<html> + <head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div> + <form id="f1"></form> + <form id="f2"> + <input id="i1" /> + <input id="i2" form="f1" /> + <input id="i3" /> + </form> + <script> + test(function() { + var i1 = document.getElementById("i1"); + var i2 = document.getElementById("i2"); + var i3 = document.getElementById("i3"); + var f1 = document.getElementById("f1"); + var f2 = document.getElementById("f2"); + + assert_equals(i1.form, f2, + "i1 must be associated with f2 by the parser"); + assert_equals(i2.form, f1, + "i2 is not associated with f2 by the parser " + + "since it has the form attribute set to f1"); + + f1.appendChild(i1); + i3.setAttribute("form", "f1"); + + assert_equals(i1.form, f1, + "i1's form owner must be reset when parent changes"); + assert_equals(i3.form, f1, + "i3's form owner must be reset when the form" + + "attribute is set"); + + assert_equals(i2.form, f1); + }, "Tests for parser inserted controls"); + </script> + </div> + + <div id="placeholder"> + </div> + + <script> + var reassociateableElements = [ + "selectlist", + ]; + + var form1 = null; + var form2 = null; + var placeholder = document.getElementById("placeholder"); + + reassociateableElements.forEach(function(localName) { + function testControl(test_, desc) { + test(function() { + var control = document.createElement(localName); + + while(placeholder.firstChild) + placeholder.removeChild(placeholder.firstChild); + + form1 = document.createElement("form"); + form2 = document.createElement("form"); + form1.id = "form1"; + form2.id = "form2"; + placeholder.appendChild(form1); + placeholder.appendChild(form2); + + test_.call(control); + }, "[" + localName.toUpperCase() + "] " + desc); + } + + testControl(function() { + form1.appendChild(this); + assert_equals(this.form, form1); + }, "Basic form association - control with no form attribute is associated with ancestor"); + + testControl(function() { + this.setAttribute("form", "form1"); + form1.appendChild(this); + assert_equals(this.form, form1); + + form1.id = "form-one"; + assert_equals(this.form, null); + }, "Form owner is reset to null when control's form attribute is set to an ID " + + "that does not exist in the document"); + + testControl(function() { + this.setAttribute("form", ""); + form1.appendChild(this); + assert_equals(this.form, null); + }, "Control whose form attribute is an empty string has no form owner"); + + testControl(function() { + form1.id = ""; + this.setAttribute("form", ""); + form1.appendChild(this); + assert_equals(this.form, null); + }, "Control whose form attribute is an empty string has no form owner " + + "even when form with empty attribute is present"); + + testControl(function() { + form1.id = "FORM1"; + this.setAttribute("form", "form1"); + form1.appendChild(this); + assert_equals(this.form, null); + }, "Control's form attribute must be a case sensitive match for the form's id"); + + testControl(function() { + form1.appendChild(this); + assert_equals(this.form, form1); + + this.setAttribute("form", "form2"); + assert_equals(this.form, form2); + }, "Setting the form attribute of a control to the id of a non-ancestor form works"); + + testControl(function() { + this.setAttribute("form", "form1"); + + form2.appendChild(this); + assert_equals(this.form, form1); + + this.removeAttribute("form"); + assert_equals(this.form, form2); + }, "Removing form id from a control resets the form owner to ancestor"); + + testControl(function() { + this.setAttribute("form", "form1"); + + form2.appendChild(this); + assert_equals(this.form, form1); + + placeholder.removeChild(form1); + + assert_equals(this.form, null); + }, "Removing the form owner of a control with form attribute resets " + + "the form owner to null"); + + testControl(function() { + var form3 = document.createElement("form"); + form3.id = "form3"; + placeholder.appendChild(form3); + form3.appendChild(this); + assert_equals(this.form, form3); + + this.setAttribute("form", "form2"); + assert_equals(this.form, form2); + + this.setAttribute("form", "form1"); + assert_equals(this.form, form1); + }, "Changing form attibute of control resets form owner to correct form"); + + testControl(function() { + this.setAttribute("form", "form1"); + var form3 = document.createElement("form"); + form3.id = "form3"; + + placeholder.appendChild(form3); + placeholder.appendChild(this); + assert_equals(this.form, form1); + + form1.appendChild(this); + assert_equals(this.form, form1); + + form2.appendChild(this); + assert_equals(this.form, form1); + }, "Moving a control with form attribute within the document " + + "does not change the form owner"); + + testControl(function() { + form1.id = "form-one"; + this.setAttribute("form", "form1"); + form2.appendChild(this); + assert_equals(this.form, null); + + form1.id = "form1"; + assert_equals(this.form, form1); + }, "When the id of a non-ancestor form changes from not being a match for the " + + "form attribute to being a match, the control's form owner is reset"); + + testControl(function() { + this.setAttribute("form", "form1"); + form1.appendChild(this); + assert_equals(this.form, form1); + + form2.id = "form1"; + form1.parentNode.insertBefore(form2, form1); + assert_equals(this.form, form2); + + form2.parentNode.removeChild(form2); + assert_equals(this.form, form1); + + form1.parentNode.appendChild(form2); + assert_equals(this.form, form1); + }, "When form element with same ID as the control's form attribute is inserted " + + "earlier in tree order, the form owner is changed to the inserted form"); + + testControl(function() { + this.setAttribute("form", "form1"); + form2.appendChild(this); + assert_equals(this.form, form1); + + var span = document.createElement("span"); + span.id = "form1"; + form1.parentNode.insertBefore(span, form1); + assert_equals(this.form, null); + + form1.parentNode.appendChild(span); + assert_equals(this.form, form1); + }, "When non-form element with same ID as the control's form attribute is " + + "inserted earlier in tree order, the control does not have a form owner"); + + testControl(function() { + this.setAttribute("form", "form1"); + form1.appendChild(this); + assert_equals(this.form, form1); + + form1.parentNode.removeChild(form1); + assert_equals(this.form, form1); + }, "A control that is not in the document but has the form attribute set " + + "is associated with the nearest ancestor form if one exists"); + + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-elements.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-elements.tentative.html new file mode 100644 index 0000000000..07e5be6ef4 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-elements.tentative.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: form.elements</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> + +<form id="form0"> +<selectlist id="selectlist0"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> +<form> + +<script> +promise_test(async t => { + // TODO: Move test to /the-form-element/form-elements-filter.html once + // <selectlist> becomes part of the HTML spec. + const formElements = document.querySelector("#form0").elements; + assert_equals(formElements.length, 1); + assert_equals(formElements[0].id, "selectlist0"); +}, "Check that <selectlist> is exposed in form.elements"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-state-restore.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-state-restore.tentative.html new file mode 100644 index 0000000000..f98494a950 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-state-restore.tentative.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: form state restore</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<input id="emptyOnFirstVisit"> +<form action="support/back.html" id="form0"> +<selectlist id="selectlist0"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> +</form> + +<script> +async_test(t => { + window.onload = () => t.step_timeout(() => { + let state = document.getElementById('emptyOnFirstVisit'); + let selectList = document.getElementById("selectlist0"); + + if (!state.value) { + // First visit. + t.step_timeout(() => { + state.value = 'visited'; + assert_equals(selectList.value, "one"); + selectList.value = "two"; + // The form is submitted in a timeout to make sure that a new back/forward list item is created. + document.getElementById('form0').submit(); + }, 0); + } else { + // Went back to this page again, and the form state should be restored. + assert_equals(selectList.value, "two"); + t.done(); + } + }, 1); +}, "Test restoring state after form submission"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-submission.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-submission.tentative.html new file mode 100644 index 0000000000..4b5e497028 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-form-submission.tentative.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: form submission</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<form id="form0"> + <selectlist name="s0" id="selectlist0"> + <option selected>one</option> + <option>two</option> + <option>three</option> + </selectlist> +</form> + +<form id="form1"> + <input type="text" name="i1" value="test"> + <selectlist id="selectlist1"> + <option selected>one</option> + <option>two</option> + <option>three</option> + </selectlist> +</form> + +<script> + +test(() => { + const form0 = document.getElementById("form0"); + const selectList0 = document.getElementById("selectlist0"); + assert_equals(selectList0.value, "one"); + + const formData = new FormData(form0); + let entries = 0; + for (let entry of formData.entries()) { + assert_equals(entry[0], "s0"); + assert_equals(entry[1], "one"); + entries++; + } + assert_equals(entries, 1); +}, "Test that HTMLSelectList.value is used for form submission"); + +test(() => { + const form1 = document.getElementById("form1"); + const selectList1 = document.getElementById("selectlist1"); + assert_equals(selectList1.value, "one"); + + const formData = new FormData(form1); + let entries = 0; + for (let entry of formData.entries()) { + assert_equals(entry[0], "i1"); + assert_equals(entry[1], "test"); + entries++; + } + assert_equals(entries, 1); +}, "Test that HTMLSelectList.value is not used for form submission without name attribute"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard-behavior.tentative.html new file mode 100644 index 0000000000..a70ab7e6a5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard-behavior.tentative.html @@ -0,0 +1,182 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1422275"> +<link rel=help href="https://github.com/openui/open-ui/issues/433#issuecomment-1452461404"> +<link rel=help href="https://github.com/openui/open-ui/issues/386#issuecomment-1452469497"> +<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> +<script src="/resources/testdriver-actions.js"></script> + +<form></form> + +<div id=notform> + <selectlist id=defaultbutton> + <option class=one>one</option> + <option class=two>two</option> + <option class=three>three</option> + </selectlist> + + <selectlist id=custombutton> + <button type=selectlist>custom button</button> + <option class=one>one</option> + <option class=two>two</option> + <option class=three>three</option> + </selectlist> +</div> + +<script> +const Enter = '\uE007'; +const Escape = '\uE00C'; +const ArrowLeft = '\uE012'; +const ArrowUp = '\uE013'; +const ArrowRight = '\uE014'; +const ArrowDown = '\uE015'; +const Space = ' '; +const form = document.querySelector('form'); +const notform = document.getElementById('notform'); + +for (const id of ['defaultbutton', 'custombutton']) { + const selectlist = document.getElementById(id); + + async function closeListbox() { + await test_driver.click(selectlist); + } + + function addCloseCleanup(t) { + t.add_cleanup(async () => { + if (selectlist.matches(':open')) { + await closeListbox(); + } + if (selectlist.matches(':open')) { + throw new Error('selectlist failed to close!'); + } + selectlist.value = 'one'; + }); + } + + promise_test(async t => { + addCloseCleanup(t); + // TODO(http://crbug.com/1350299): When focus for custom buttons is fixed, + // then we shouldn't need to explicitly focus the custom button like this + // anymore. + const customButton = selectlist.querySelector('button'); + if (customButton) { + customButton.focus(); + } else { + selectlist.focus(); + } + assert_false(selectlist.matches(':open'), + 'The selectlist should initially be closed.'); + await test_driver.send_keys(selectlist, Space); + assert_true(selectlist.matches(':open'), + 'The selectlist should be open after pressing space.'); + }, `${id}: When the listbox is closed, spacebar should open the listbox.`); + + promise_test(async t => { + addCloseCleanup(t); + selectlist.value = 'two'; + selectlist.focus(); + assert_false(selectlist.matches(':open'), + 'The selectlist should initially be closed.'); + + await test_driver.send_keys(selectlist, ArrowLeft); + assert_true(selectlist.matches(':open'), + 'Arrow left should open the listbox.'); + assert_equals(selectlist.value, 'two', + 'Arrow left should not change the selected value.'); + await closeListbox(); + + await test_driver.send_keys(selectlist, ArrowUp); + assert_true(selectlist.matches(':open'), + 'Arrow up should open the listbox.'); + assert_equals(selectlist.value, 'two', + 'Arrow up should not change the selected value.'); + await closeListbox(); + + await test_driver.send_keys(selectlist, ArrowRight); + assert_true(selectlist.matches(':open'), + 'Arrow right should open the listbox.'); + assert_equals(selectlist.value, 'two', + 'Arrow right should not change the selected value.'); + await closeListbox(); + + await test_driver.send_keys(selectlist, ArrowDown); + assert_true(selectlist.matches(':open'), + 'Arrow down should open the listbox.'); + assert_equals(selectlist.value, 'two', + 'Arrow down should not change the selected value.'); + }, `${id}: When the listbox is closed, all arrow keys should open the listbox.`); + + promise_test(async t => { + addCloseCleanup(t); + + // TODO(http://crbug.com/1350299): When focus for custom buttons is fixed, + // then we shouldn't need to explicitly use the custom button like this + // anymore. + const customButton = selectlist.querySelector('button'); + if (customButton) { + await test_driver.send_keys(customButton, Enter); + } else { + await test_driver.send_keys(selectlist, Enter); + } + assert_false(selectlist.matches(':open'), + 'Enter should not open the listbox when outside a form.'); + + form.appendChild(selectlist); + let formWasSubmitted = false; + form.addEventListener('submit', event => { + event.preventDefault(); + formWasSubmitted = true; + }, {once: true}); + if (customButton) { + await test_driver.send_keys(customButton, Enter); + } else { + await test_driver.send_keys(selectlist, Enter); + } + assert_true(formWasSubmitted, + 'Enter should submit the form when the listbox is closed.'); + assert_false(selectlist.matches(':open'), + 'Enter should not open the listbox when it is in a form.'); + }, `${id}: When the listbox is closed, the enter key should submit the form or do nothing.`); + + promise_test(async t => { + addCloseCleanup(t); + const optionOne = selectlist.querySelector('.one'); + const optionTwo = selectlist.querySelector('.two'); + const optionThree = selectlist.querySelector('.three'); + + selectlist.value = 'two'; + await test_driver.click(selectlist); + assert_true(selectlist.matches(':open'), + 'The selectlist should open when clicked.'); + assert_equals(document.activeElement, optionTwo, + 'The selected option should receive initial focus.'); + + await test_driver.send_keys(document.activeElement, ArrowDown); + assert_equals(document.activeElement, optionThree, + 'The next option should receive focus when the down arrow key is pressed.'); + assert_equals(selectlist.value, 'two', + 'The selectlists value should not change when focusing another option.'); + + await test_driver.send_keys(document.activeElement, ArrowUp); + assert_equals(document.activeElement, optionTwo, + 'The previous option should receive focus when the up arrow key is pressed.'); + assert_equals(selectlist.value, 'two', + 'The selectlists value should not change when focusing another option.'); + + await test_driver.send_keys(document.activeElement, ArrowUp); + assert_equals(document.activeElement, optionOne, + 'The first option should be selected.'); + assert_equals(selectlist.value, 'two', + 'The selectlists value should not change when focusing another option.'); + + await test_driver.send_keys(document.activeElement, Enter); + assert_false(selectlist.matches(':open'), + 'The listbox should be closed after pressing enter.'); + assert_equals(selectlist.value, 'one', + 'The selectlists value should change after pressing enter on a different option.'); + }, `${id}: When the listbox is open, the enter key should commit the selected option.`); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard.tentative.html new file mode 100644 index 0000000000..5d1c65e941 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-keyboard.tentative.html @@ -0,0 +1,142 @@ +<!doctype html> +<title>HTMLSelectListElement Test: keyboard accessibility</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> + <selectlist id="selectList0"> + <button id="selectList0-button0" type=selectlist>button</button> + <option class=one>one</option> + <option class=two>two</option> + <option class=three>three</option> + </selectlist> + + <selectlist id="selectList1"> + <option id="selectList1-child0">one</option> + </selectlist> + + <selectlist id="selectList2" disabled> + <button id="selectList2-button0" type=selectlist>button</button> + <option disabled>one</option> + <option>two</option> + <option>three</option> + </selectlist> + + <selectlist id="selectList3"> + <button id="selectList3-button0" type=selectlist>button</button> + <option class=one>one</option> + <option disabled>two</option> + <option class=three>three</option> + </selectlist> +<script> +// See https://w3c.github.io/webdriver/#keyboard-actions +const KEY_CODE_MAP = { + 'Enter': '\uE007', + 'Space': '\uE00D', + 'ArrowUp': '\uE013', + 'ArrowDown': '\uE015' +}; + +function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + +promise_test(async t => { + const selectList = document.querySelector("#selectList0"); + const button = document.querySelector("#selectList0-button0"); + assert_false(selectList.open, "selectlist should not be initially open"); + + await test_driver.send_keys(button, KEY_CODE_MAP.Enter); + assert_false(selectList.open, "Enter key shouldn't open selectlist"); + await test_driver.send_keys(button, KEY_CODE_MAP.Space); + assert_true(selectList.open, "Space key should open selectlist"); + assert_equals(selectList.value, "one"); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowDown); + assert_equals(document.activeElement, selectList.querySelector('.two'), + "Down arrow should focus the next option."); + assert_equals(selectList.value, "one", "Down arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowDown); + assert_equals(document.activeElement, selectList.querySelector('.three'), + "Down arrow should focus the next option."); + assert_equals(selectList.value, "one", "Down arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowDown); + assert_equals(document.activeElement, selectList.querySelector('.three'), + "Down arrow should do nothing if already at the last option."); + assert_equals(selectList.value, "one", "Down arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowUp); + assert_equals(document.activeElement, selectList.querySelector('.two'), + "Up arrow should focus the previous option."); + assert_equals(selectList.value, "one", "Up arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowUp); + assert_equals(document.activeElement, selectList.querySelector('.one'), + "Up arrow should focus the previous option."); + assert_equals(selectList.value, "one", "Up arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.ArrowUp); + assert_equals(document.activeElement, selectList.querySelector('.one'), + "Up arrow should do nothing if already at the first option."); + assert_equals(selectList.value, "one", "Up arrow should not commit the newly focused option."); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_false(selectList.open, "Enter key should close selectlist"); + + await test_driver.send_keys(button, KEY_CODE_MAP.Space); + assert_true(selectList.open, "Space key should open selectlist"); + + // This behavior is suspicious (since Space key can open the selectlist), + // but it maches <select>. See https://github.com/openui/open-ui/issues/386 + await test_driver.send_keys(selectList, " "); + assert_true(selectList.open, "Space key should *not* close selectlist"); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_false(selectList.open, "Enter key should close selectlist"); +}, "Validate Enter, Up/Down Arrow, and Space keyboard accessibility support for <selectlist>"); + +promise_test(async t => { + const selectListOption = document.getElementById("selectList1-child0"); + const event = document.createEvent("Event"); + event.initEvent("keydown"); + selectListOption.dispatchEvent(event); +}, "Firing a synthetic event at a selectlist's option doesn't crash"); + +promise_test(async t => { + const selectList2 = document.querySelector("#selectList2"); + const selectList2Button = document.querySelector("#selectList2-button0"); + assert_false(selectList2.open, "selectlist should not be initially open"); + + await test_driver.send_keys(selectList2Button, KEY_CODE_MAP.Enter); + assert_false(selectList2.open, "Enter key should not open a disabled selectlist"); + await clickOn(selectList2); + assert_false(selectList2.open, "Click should not open a disabled selectlist"); + assert_equals(selectList2.value, "one"); + + const selectList3 = document.querySelector("#selectList3"); + const selectList3Button = document.querySelector("#selectList3-button0"); + assert_false(selectList3.open, "selectlist should not be initially open"); + + await test_driver.send_keys(selectList3Button, KEY_CODE_MAP.Enter); + assert_false(selectList3.open, "Enter key shouldn't open selectlist"); + + await test_driver.send_keys(selectList3Button, KEY_CODE_MAP.Space); + assert_true(selectList3.open, "Space key should open selectlist"); + assert_equals(selectList3.value, "one"); + + await test_driver.send_keys(selectList3, KEY_CODE_MAP.ArrowDown); + assert_equals(document.activeElement, selectList3.querySelector('.three'), + "Down arrow should go to next non-disabled option"); + + await test_driver.send_keys(selectList3, KEY_CODE_MAP.ArrowUp); + assert_equals(document.activeElement, selectList3.querySelector('.one'), + "Up arrow should go to the previous non-disabled option"); +}, "Validate Enter, Up/Down Arrow keyboard accessibility support for disabled <selectlist>"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-labels.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-labels.tentative.html new file mode 100644 index 0000000000..819da49fdd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-labels.tentative.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: labels</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<label id="label1" for="selectlist1">Label 1</label> +<selectlist id="selectlist1"> + <option>one</option> + <option>two</option> + <option>three</option> + <option>four</option> +</selectlist> +<label id="label2" for="selectlist1">Label 2</label> +<label id="label3" for="invalid-selectlist1">Label 3</label> + +<script> + +test(() => { + let selectList = document.getElementById("selectlist1"); + + assert_true(selectList.labels instanceof NodeList); + assert_equals(selectList.labels.length, 2); + assert_equals(selectList.labels[0], document.getElementById("label1")); + assert_equals(selectList.labels[1], document.getElementById("label2")); +}, "Validate selectlist.labels"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element-ref.html new file mode 100644 index 0000000000..5533a97f60 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element-ref.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> +const selectlist = createFakeSelectlist('button', /*includeListbox=*/true); +document.body.appendChild(selectlist); + +selectlist.querySelector('button').remove(); +selectlist.insertAdjacentHTML('afterbegin', `<button>button</button>`); + +const listbox = selectlist.querySelector('.fake-selectlist-listbox'); +listbox.innerHTML = ` + <option id=optone tabindex=0>one</option> + <option>two</option> +`; +document.getElementById('optone').focus(); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element.tentative.html new file mode 100644 index 0000000000..14223633b9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-element.tentative.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<link rel=match href="selectlist-listbox-element-ref.html"> + +<selectlist> + <button type=selectlist>button</button> + <listbox> + <option>one</option> + <option>two</option> + </listbox> +</selectlist> + +<script> +document.querySelector('button').click(); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-fallback-change-crash.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-fallback-change-crash.tentative.html new file mode 100644 index 0000000000..1a9e81d817 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-listbox-fallback-change-crash.tentative.html @@ -0,0 +1,35 @@ +<!doctype html> +<html class="test-wait"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1400522"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> + +<selectlist id="selectList" style="position: absolute;"> + <div slot="button"> + <button id="b1" behavior="button"></button> + </div> + <selectlist> + <div slot="button"> + <button id="b2" behavior="button">x</button> + </div> + <div id="listbox" popover slot="listbox" behavior="listbox"> + <option>y</option> + </div> + </selectlist> +</selectlist> + +<script type="module"> + const raf = () => new Promise(resolve => requestAnimationFrame(resolve)); + + document.querySelector('#b1').click(); + document.querySelector('#b2').click(); + + document.querySelector('#selectList').style.top = '-25px'; + + await raf(); + await raf(); + + document.querySelector('#selectList').style.top = '0px'; + + document.documentElement.classList.remove('test-wait'); +</script> +</html> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-many-options.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-many-options.tentative.html new file mode 100644 index 0000000000..36bae1a82b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-many-options.tentative.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html> +<title>HTMLSelectListElement Test: many options</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<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> + #selectList0 { + position: absolute; + top: 0px; + left: 0px; + } + + #selectList0-popover { + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + 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; + padding: 4px; + } +</style> + +<selectlist id="selectList0"> + <div popover slot="listbox" behavior="listbox" id="selectList0-popover"> + <option>bottom left</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + <option>two</option> + <option>three</option> + </div> +</selectlist> +<br> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Popover = document.getElementById("selectList0-popover"); + + await clickOn(selectList0); + assert_equals(Math.round(selectList0.getBoundingClientRect().bottom), Math.round(selectList0Popover.getBoundingClientRect().top)); + assert_equals(Math.round(selectList0.getBoundingClientRect().left), Math.round(selectList0Popover.getBoundingClientRect().left)); + assert_equals(window.innerHeight, Math.round(selectList0Popover.getBoundingClientRect().bottom)); + }, "The popover should be bottom left positioned"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned-ref.tentative.html new file mode 100644 index 0000000000..b1df8a6581 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned-ref.tentative.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<style> +div { + width:300px; + display:flex; + justify-content:flex-end; +} +selectlist { + width:100px; +} +selectlist::part(button) { + border-style:none; + background-color:rgba(0,0,0,0) +} +</style> +<div> +<selectlist> + <option></option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned.tentative.html new file mode 100644 index 0000000000..c2540acb36 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-end-aligned.tentative.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<!-- Tests that <selectlist> marker is end-aligned --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-marker-end-aligned-ref.tentative.html"> + +<style> +div { + width:300px; + display:flex; + justify-content:flex-end; +} +selectlist { + width:200px; +} +selectlist::part(button) { + border-style:none; + background-color:rgba(0,0,0,0) +} +</style> +<div> +<selectlist> + <option></option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part-ref.html new file mode 100644 index 0000000000..1a1302b96d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part-ref.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('hello world'); + document.body.appendChild(selectlist); + selectlist.querySelector('.fake-selectlist-internal-selectlist-button-icon') + .style.backgroundColor = 'red'; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part.tentative.html new file mode 100644 index 0000000000..dedabc9bab --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-part.tentative.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-marker-part-ref.html"> + +<style> +selectlist::part(marker) { + background-color: red; +} +</style> +<selectlist> + <option>hello world</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot-ref.html new file mode 100644 index 0000000000..e910df4c5a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot-ref.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('hello world'); + document.body.appendChild(selectlist); + + const oldMarker = selectlist.querySelector('.fake-selectlist-internal-selectlist-button-icon'); + const newMarker = document.createElement('div'); + newMarker.textContent = 'marker'; + + replaceChildElement(newMarker, oldMarker); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot.tentative.html new file mode 100644 index 0000000000..de43a02c33 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-slot.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-marker-slot-ref.html"> + +<selectlist> + <div slot=marker>marker</div> + <option>hello world</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow-ref.tentative.html new file mode 100644 index 0000000000..dda53db5bf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow-ref.tentative.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +selectlist { + width:100px; +} +</style> +<div> +<selectlist> + <option> </option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow.tentative.html new file mode 100644 index 0000000000..345c205983 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-marker-visible-overflow.tentative.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<!-- Tests that the marker is visible when the <selectlist> contains more text than it can show --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-marker-visible-overflow-ref.tentative.html"> + +<style> +selectlist { + width:100px; +} +</style> +<div> +<selectlist> + <option> </option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-nested.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-nested.tentative.html new file mode 100644 index 0000000000..c29413f180 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-nested.tentative.html @@ -0,0 +1,94 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: nested selects</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> + +<selectlist id="selectList0"> + <div popover slot="listbox" behavior="listbox"> + <selectlist id="nested0"> + <option id="child1">one</option> + <option id="child2">two</option> + </selectlist> + <option id="child3">three</option> + </div> +</selectlist> + +<selectlist id="selectList1"> + <div popover slot="listbox" behavior="listbox"> + <select> + <option>one</option> + <option>two</option> + </select> + <option>three</option> + </div> +</selectlist> + +<selectlist id="selectList2"> + <div slot="button"> + <selectlist id="nested2"> + <button type=selectlist id="selectList2-button0">button0</button> + <option id="nested2-option1">one</option> + </selectlist> + <button type=selectlist id="selectList2-button1">button1</button> + </div> + <option>two</option> +</selectlist> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const nested0 = document.getElementById("nested0"); + const child2 = document.getElementById("child2"); + assert_equals(selectList0.value, "three", "Options nested in another <selectlist> should not get controller code from outer <selectlist>"); + await clickOn(selectList0); + assert_true(selectList0.open); + assert_false(nested0.open); + + await clickOn(nested0); + assert_true(nested0.open); + + await clickOn(child2); + assert_false(nested0.open); + assert_equals(nested0.value, "two"); + assert_true(selectList0.open, "click on option in inner <selectlist> should not close outer <selectlist>"); + assert_equals(selectList0.value, "three", "click on option in inner <selectlist> should not change value of outer <selectlist>"); + }, "A <selectlist> shouldn't apply controller code to parts nested in a <selectlist> child"); + + promise_test(async () => { + const selectList1 = document.getElementById("selectList1"); + assert_equals(selectList0.value, "three"); + }, "A <selectlist> shouldn't apply controller code to parts nested in a <select> child"); + + promise_test(async () => { + const selectList2 = document.getElementById("selectList2"); + const nested2 = document.getElementById("nested2"); + const button0 = document.getElementById("selectList2-button0"); + const button1 = document.getElementById("selectList2-button1"); + const nested2Option1 = document.getElementById("nested2-option1"); + assert_false(selectList2.open); + assert_false(nested2.open); + + await clickOn(button0); + assert_false(selectList2.open, "Clicking the button of a nested <selectlist> should not open the outer <selectlist>"); + assert_true(nested2.open, "Clicking the button of a nested <selectlist> should open the outer <selectlist>"); + + await clickOn(nested2Option1); + assert_false(nested2.open); + + await clickOn(button1); + assert_true(selectList2.open); + assert_false(nested2.open); + }, "A nested button part in a nested <selectlist> shouldn't get controller code even if it comes first in document order"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed-ref.tentative.html new file mode 100644 index 0000000000..126bbc5dd7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed-ref.tentative.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<link rel="stylesheet" href="/fonts/ahem.css"> + +<selectlist id="selectList0"> + <option>option with image displayed</option> +</selectlist> +<div id=fakelistbox> + option with image displayed + <img src="/images/green-256x256.png"> +</div> + +<style> + html,selectlist { + font-family: Ahem; + } + #fakelistbox { + /* Per spec: */ + display: block; + position: fixed; + top: 30px; + left: 0; + font-size: 0.765625em /* 0.875 * 0.875 */; + /* Per settings in test file: */ + width: fit-content; + height: fit-content; + background: light-dark(white, black); + color: light-dark(black, white); + border: 1px solid rgba(0, 0, 0, 1); + border-radius: 0px; + 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; + padding: 4px; + } + + selectlist { + position: absolute; + top: 0px; + left: 0px; + height: 30px; + } +</style> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html new file mode 100644 index 0000000000..2d51002fb2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-displayed.tentative.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<title>HTMLSelectListElement Test: option arbitrary content displayed</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<link rel=match href="selectlist-option-arbitrary-content-displayed-ref.tentative.html"> +<link rel="stylesheet" href="/fonts/ahem.css"> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<style> + html,selectlist { + font-family: Ahem; + } + selectlist { + position: absolute; + top: 0px; + left: 0px; + height: 30px; + } + + [popover] { + width: fit-content; + height: fit-content; + background: white; + color: black; + border: 1px solid rgba(0, 0, 0, 1); + border-radius: 0px; + 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; + padding: 4px; + } + + option { + background-color: white !important; + padding: 0px; + } +</style> + +<selectlist id="selectList0"> + <div popover slot="listbox" behavior="listbox"> + <option> + option with image displayed + <img src="/images/green-256x256.png"> + </option> + </div> +</selectlist> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + async function test() { + const selectList0 = document.getElementById("selectList0"); + + await clickOn(selectList0); + document.documentElement.classList.remove('reftest-wait'); + } + + test(); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed-ref.tentative.html new file mode 100644 index 0000000000..fa44198fff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed-ref.tentative.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> + +<option> + option with image not displayed +</option> + +<selectlist> +</selectlist> + +<option> + option with image not displayed +</option>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed.tentative.html new file mode 100644 index 0000000000..e7cacdba27 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-arbitrary-content-not-displayed.tentative.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<title>HTMLSelectListElement Test: option arbitrary content not displayed</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<link rel=match href="selectlist-option-arbitrary-content-not-displayed-ref.tentative.html"> + +<option> + option with image not displayed + <img src="/images/green-256x256.png"> +</option> + +<selectlist id="selectList0"> + <option id="selectList0-option"> + option with image not displayed + <img src="/images/green-256x256.png"> + </option> +</selectlist> + +<script> + const selectList0Option = document.getElementById("selectList0-option"); + + // removing an option from <selectlist> should revert back to its original display behavior + selectList0Option.remove(); + document.body.append(selectList0Option); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-focusable.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-focusable.tentative.html new file mode 100644 index 0000000000..993ef007e6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-focusable.tentative.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: option facusable</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<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> + +<selectlist id="selectlist0"> + <option>one</option> + <option id="selectlist0-option2">two</option> + <option>three</option> +</selectlist> + +<script> +// See https://w3c.github.io/webdriver/#keyboard-actions +const KEY_CODE_MAP = { + 'Enter': '\uE007', + 'Space': '\uE00D', + 'ArrowUp': '\uE013', + 'ArrowDown': '\uE015' +}; + +function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); +} + +promise_test(async t => { + const selectList = document.querySelector("#selectlist0"); + assert_false(selectList.open, "selectlist should not be initially open"); + + await clickOn(selectList); + assert_true(selectList.open); + assert_equals(selectList.value, "one"); + + const option2 = document.querySelector('#selectlist0-option2'); + option2.focus(); + assert_equals(document.activeElement, option2); + + await test_driver.send_keys(selectList, KEY_CODE_MAP.Enter); + assert_equals(selectList.value, "two"); +}, "Validate <option> is focusable when is a descendant of <selectlist>"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering-ref.html new file mode 100644 index 0000000000..1ab1d54722 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<selectlist> + <option>textcontent</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering.tentative.html new file mode 100644 index 0000000000..c719ee0e07 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-option-label-rendering.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-option-label-rendering-ref.html"> +<link rel=assert title="option elements should not render their label attributes when used in selectlist."> + +<selectlist> + <option label=label>textcontent</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x-ref.tentative.html new file mode 100644 index 0000000000..df87060359 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x-ref.tentative.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<style> +selectlist { + width:30px; + height:20px; +} +selectlist::part(button) { + background-color:blue; +} +</style> +<selectlist> + <option> </option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x.tentative.html new file mode 100644 index 0000000000..93c1b948a0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-overflow-x.tentative.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<!-- Tests that selectlist button part text is truncated by the button. --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-overflow-x-ref.tentative.html"> +<style> +selectlist { + width:30px; + height:20px; +} +selectlist::part(button) { + background-color:blue; +} +</style> +<selectlist> + <option> </option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-parts-structure.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-parts-structure.tentative.html new file mode 100644 index 0000000000..104ae841f7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-parts-structure.tentative.html @@ -0,0 +1,495 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: part structure</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<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> + +<selectlist id="selectList0"> + <div popover slot="listbox" behavior="listbox"> + <option id="selectList0-child1">one</option> + <option id="selectList0-child2">two</option> + <div behavior="option" id="selectList0-child3">three</div> + </div> + <option id="selectList0-child4">four</option> +</selectlist> + +<selectlist id="selectList1"> + <listbox id="selectList1-popover"> + <button type=selectlist id="selectList1-button"> + Custom button + </button> + <option>one</option> + <option id="selectList1-child2">two</option> + </listbox> +</selectlist> + +<selectlist id="selectList2"> + <button type=selectlist id="selectList2-button"> + Custom button + <listbox id="selectList2-popover"> + Custom listbox + </listbox> + </button> + <option>three</option> + <div> + This is some text. + <option id="selectList2-child4">four</option> + More text. + </div> +</selectlist> + +<selectlist id="selectList3"> + <div slot="button" id="selectList3-button-slot"> + <button type=selectlist id="selectList3-button0">button0</button> + </div> + <option>one</option> +</selectlist> + +<selectlist id="selectList4"> + <button type=selectlist id="selectList4-button0">button0</button> + <div slot="listbox" id="selectList4-listbox-slot"> + <div popover behavior="listbox" id="selectList4-listbox0"> + <option>one</option> + <option id="selectList4-option2">two</option> + </div> + </div> +</selectlist> + +<selectlist id="selectList5"> + <div slot="button" id="selectList5-button-slot"> + <button type=selectlist id="selectList5-button0">button0</button> + <div behavior="selected-value" id="selectList5-selectedValue0"></div> + </div> + <option>one</option> + <option id="selectList5-option0">two</option> +</selectlist> + +<!-- No associated JS test -- just don't crash when parsing! --> +<selectlist id="selectList6"> + <div slot="button"></div> + <div popover slot="listbox" behavior="listbox"></div> +</selectlist> + +<!-- No associated JS test -- just don't crash when parsing! --> +<selectlist id="selectList7"> + <div slot="listbox"></div> + <button type=selectlist></button> +</selectlist> + +<!-- No associated JS test -- just don't crash when parsing! --> +<selectlist id="selectList8"> + <div slot="listbox"></div> + <option>one</option> +</selectlist> + +<selectlist id="selectList9"> + <div slot="listbox" id="selectList9-listbox-slot"> + <div popover behavior="listbox" id="selectList9-originalListbox"> + <option>one</option> + <option id="selectList9-option2">two</option> + </div> + </div> +</selectlist> + +<selectlist id="selectList11"> + <div popover slot="listbox" behavior="listbox"> + <option>one</option> + </div> + <div slot="button" behavior="listbox" id="selectList11-button">Test</div> +</selectlist> + +<selectlist id="selectList12"> + <button type=selectlist id="selectList12-button0">button0</button> + <listbox id="selectList12-listbox"> + <option id="selectList12-option1">one</option> + <option>two</option> + </listbox> +</selectlist> + +<selectlist id="selectList13"> + <div slot="button" id="selectList12-button-slot"> + <div id="selectList13-removeContent-button"> + <button type=selectlist id="selectList13-button0">button0</button> + <button type=selectlist id="selectList13-button1">button1</button> + </div> + <button type=selectlist id="selectList13-button2">button2</button> + </div> + <div slot="listbox" id="selectList13-listbox-slot"> + <div id="selectList13-removeContent-listbox"> + <div popover behavior="listbox" id="selectList13-originalListbox"> + <option id="selectList13-option1">one</option> + <option id="selectList13-option2">two</option> + </div> + </div> + <div popover behavior="listbox" id="selectList13-newListbox"> + <option>three</option> + <option id="selectList13-option4">four</option> + </div> + </div> +</selectlist> + +<selectlist id="selectList14"> + <button type=selectlist id="selectList14-button0">button0</button> + <option>one</option> + <option id="selectList14-option2">two</option> +</selectlist> + +<selectlist id="selectList15"> + <div slot="button" id="selectList15-div0"></div> + <option>one</option> +</selectlist> + +<selectlist id="selectList16"> + <div slot="button"> + <div id="selectList16-div0"> + <button type=selectlist id="selectList16-button0">button</button> + </div> + </div> + <option>one</option> +</selectlist> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Child1 = document.getElementById("selectList0-child1"); + const selectList0Child2 = document.getElementById("selectList0-child2"); + const selectList0Child3 = document.getElementById("selectList0-child3"); + assert_equals(selectList0.value, "one"); + await clickOn(selectList0); + await clickOn(selectList0Child2); + assert_equals(selectList0.value, "two"); + + await clickOn(selectList0); + await clickOn(selectList0Child3); + assert_equals(selectList0.value, "two", "Clicking a non-HTMLOptionElement labeled as an option should do nothing"); + + await clickOn(selectList0Child1); + assert_equals(selectList0.value, "one"); + assert_false(selectList0.open); + }, "HTMLOptionElements (and not other element types) should receive option controller code"); + + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Child4 = document.getElementById("selectList0-child4"); + + assert_equals(selectList0.value, "one"); + await clickOn(selectList0); + assert_true(selectList0.open); + selectList0Child4.click(); + assert_equals(selectList0.value, "one", "Clicking an option outside of the popover should not change the value"); + }, "To receive option part controller code, an option must be a descendant of the listbox part in a flat tree traversal"); + + promise_test(async () => { + const selectList1 = document.getElementById("selectList1"); + const selectList1Popover = document.getElementById("selectList1-popover"); + const selectList1Button = document.getElementById("selectList1-button"); + const selectList1Child2 = document.getElementById("selectList1-child2"); + assert_false(selectList1Popover.matches(':popover-open')); + selectList1Button.click(); + assert_false(selectList1Popover.matches(':popover-open'), "Clicking a button part that is a descendant of the listbox part should have no effect"); + + assert_equals(selectList1.value, "one"); + await clickOn(selectList1); + assert_true(selectList1Popover.matches(':popover-open')); + await clickOn(selectList1Child2); + assert_equals(selectList1.value, "two", "Clicking an <option> should change the value"); + }, "To receive button part controller code, an element labeled as a button must not be a descendant of the listbox part in a flat tree traversal"); + + promise_test(async () => { + const selectList2 = document.getElementById("selectList2"); + const selectList2Popover = document.getElementById("selectList2-popover"); + const selectList2Button = document.getElementById("selectList2-button"); + const selectList2Child2 = document.getElementById("selectList2-child2"); + const selectList2Child4 = document.getElementById("selectList2-child4"); + + assert_false(selectList2Popover.matches(':popover-open')); + await clickOn(selectList2Button); + assert_false(selectList2Popover.matches(':popover-open'), "Clicking a button part should not show an invalid listbox part"); + + assert_equals(selectList2.value, "three"); + await clickOn(selectList2Child4); + assert_equals(selectList2.value, "four", "Clicking an <option> that is a descendant of a valid listbox part should update the value"); + }, "To receive listbox part controller code, an element labeled as a listbox must not be a descendant of the button part in a flat tree traversal"); + + promise_test(async () => { + const selectList3 = document.getElementById("selectList3"); + const selectList3ButtonSlot = document.getElementById("selectList3-button-slot"); + const selectList3Button0 = document.getElementById("selectList3-button0"); + + assert_false(selectList3.open); + + let button1 = document.createElement("div"); + button1.innerText = "button1"; + button1.setAttribute("behavior", "button"); + selectList3ButtonSlot.appendChild(button1); + + await clickOn(button1); + assert_false(selectList3.open, "A button part should only get controller code if it's first in document order, even if added dynamically"); + + await clickOn(selectList3Button0); + assert_true(selectList3.open, "A button part should get controller code if it's first in document order"); + }, "Button controller code should be applied in flat tree traversal order regardless of dynamic insertion order"); + + promise_test(async () => { + const selectList4 = document.getElementById("selectList4"); + const selectList4Button0 = document.getElementById("selectList4-button0"); + const selectList4ListboxSlot = document.getElementById("selectList4-listbox-slot"); + const selectList4Option2 = document.getElementById("selectList4-option2"); + + assert_false(selectList4.open); + + let listbox2 = document.createElement("div"); + listbox2.innerHTML = ` + <option>three</option> + <option id="selectList4-option4">four</option> + `; + listbox2.setAttribute("behavior", "listbox"); + selectList4ListboxSlot.appendChild(listbox2); + + await clickOn(selectList4Button0); + assert_true(selectList4.open); + + const selectList4Option4 = document.getElementById("selectList4-option4"); + await clickOn(selectList4Option4); + assert_equals(selectList3.value, "one", "An option in a listbox should not get controller code if its listbox isn't first in document order, even if added dynamically"); + + await clickOn(selectList4Button0); + assert_true(selectList4.open); + + await clickOn(selectList4Option2); + assert_equals(selectList4.value, "two", "An option in a listbox should get controller code if its listbox is first in document order, even if another listbox was added dynamically"); +}, "Listbox controller code should be applied in flat tree traversal order regardless of dynamic insertion order"); + +promise_test(async () => { + const selectList5 = document.getElementById("selectList5"); + const selectList5ButtonSlot = document.getElementById("selectList5-button-slot"); + const selectList5Button0 = document.getElementById("selectList5-button0"); + const selectList5SelectedValue0 = document.getElementById("selectList5-selectedValue0"); + + assert_false(selectList3.open); + assert_equals(selectList5SelectedValue0.innerText, "one"); + + let selectedValue1 = document.createElement("div"); + selectList5ButtonSlot.appendChild(selectedValue1); + + await clickOn(selectList5Button0); + assert_true(selectList5.open); + + await clickOn(document.getElementById("selectList5-option0")); + assert_false(selectList5.open); + assert_equals(selectList5SelectedValue0.innerText, "two", "first selected-value part in flat tree order should get controller code"); + assert_equals(selectedValue1.innerText, "", "Dynamically inserted selected-value part shouldn't get controller code if it's not first in flat tree order"); + }, "selected-value controller code should be applied in flat tree traversal order regardless of dynamic insertion order"); + + promise_test(async () => { + const selectList = document.getElementById("selectList9"); + const originalListbox = document.getElementById("selectList9-originalListbox"); + const option2 = document.getElementById("selectList9-option2"); + assert_equals(selectList.value, "one", "Initial value should be the first option"); + + let newListbox = document.createElement("div"); + newListbox.setAttribute("popover", "auto"); + newListbox.setAttribute("behavior", "listbox"); + let newOption = document.createElement("option"); + newOption.innerText = "three"; + newListbox.appendChild(newOption); + let newOption2 = document.createElement("option"); + newOption2.innerText = "four"; + newListbox.appendChild(newOption2); + originalListbox.parentElement.insertBefore(newListbox, originalListbox); + + await clickOn(selectList); + assert_true(selectList.open, "Menu should open when clicked"); + + option2.click(); // clickOn doesn't work because the old options are not displayed + assert_equals(selectList.value, "three", "Elements in second popover should no longer be option parts"); + assert_true(selectList.open, "Clicking non-part options shouldn't close the popover"); + + await clickOn(newOption2); + assert_false(selectList.open); + assert_equals(selectList.value, "four", "New options should get controller code after listbox switch"); + }, "Ensure that option controller code is updated when listbox changes"); + + promise_test(async () => { + const selectList = document.getElementById("selectList11"); + const selectList11Button= document.getElementById("selectList11-button"); + + await clickOn(selectList11Button); + assert_false(selectList.open, "Controller code not applied due to part attribute not being button"); + selectList11Button.remove(); + + await clickOn(selectList); + assert_true(selectList.open, "Default button part should be used"); + }, "Ensure that controller code is applied when slot and part attributes are different"); + + promise_test(async () => { + const selectList = document.getElementById("selectList12"); + const originalListbox = document.getElementById("selectList12-listbox"); + assert_equals(selectList.value, "one", "Initial value should be the first option"); + + const selectListButton0 = document.getElementById("selectList12-button0"); + const selectListOption1 = document.getElementById("selectList12-option1"); + + assert_false(selectList.open); + let button1 = document.createElement("button"); + button1.innerText = "button1"; + button1.setAttribute("type", "selectlist"); + selectList.insertBefore(button1, selectListButton0); + button1.click(); + assert_true(selectList.open, "Controller code should be applied to the new first button in document order"); + await clickOn(selectListOption1); + assert_false(selectList.open, "listbox should close after clicking option1."); + selectListButton0.click(); + assert_true(selectList.open, "listbox should open after clicking button0."); + selectListButton0.click(); + assert_false(selectList.open, "listbox should close after clicking button0 again."); + + let button2 = document.createElement("button"); + button2.innerText = "button2"; + selectList.insertBefore(button2, button1); + button2.click(); + assert_false(selectList.open, "Controller code should not be applied to button2 since it doesn't have type=selectlist."); + button2.setAttribute("type", "selectlist"); + button2.click(); + assert_true(selectList.open, "Controller code should be applied to the new button part"); + await clickOn(selectListOption1); + assert_false(selectList.open); + + let newListbox = document.createElement("listbox"); + let newOption = document.createElement("option"); + newOption.innerText = "three"; + newListbox.appendChild(newOption); + let newOption2 = document.createElement("option"); + newOption2.innerText = "four"; + newListbox.appendChild(newOption2); + originalListbox.parentElement.insertBefore(newListbox, originalListbox); + assert_equals(selectList.value, "three", "New value should be the first option"); + + newListbox.innerHTML = "<option>five</option><option>six</option>"; + assert_equals(selectList.value, "five", "New value should be the first option"); + + selectList.innerHTML = "<option>seven</option><option id='selectList12-option2'>eight</option>"; + assert_equals(selectList.value, "seven", "New value should be the first option"); + const selectListOption2 = document.getElementById("selectList12-option2"); + await clickOn(selectList); + assert_true(selectList.open); + await clickOn(selectListOption2); + assert_equals(selectList.value, "eight", "Controller code should be applied to new options"); + + selectListOption2.slot = "button"; + assert_equals(selectList.value, "seven", "Previous selected option should become invalid"); + }, "Ensure that controller code is synchronously applied"); + + promise_test(async () => { + const selectList = document.getElementById("selectList13"); + assert_equals(selectList.value, "one"); + + const selectListButton0 = document.getElementById("selectList13-button0"); + const selectListButton1 = document.getElementById("selectList13-button1"); + selectListButton1.click(); + assert_false(selectList.open); + selectListButton0.click(); + assert_true(selectList.open, "First button should receive controller code"); + await clickOn(document.getElementById("selectList13-option2")); + assert_equals(selectList.value, "two"); + let divButtonToRemove = document.getElementById("selectList13-removeContent-button"); + divButtonToRemove.innerHTML = ""; + selectListButton0.click(); + assert_false(selectList.open, "The first button is invalid"); + const selectListButton2 = document.getElementById("selectList13-button2"); + selectListButton2.click(); + assert_true(selectList.open, "The button part should be updated") + await clickOn(document.getElementById("selectList13-option1")); + assert_equals(selectList.value, "one"); + + const selectListOption4 = document.getElementById("selectList13-option4"); + selectListOption4.click(); + assert_equals(selectList.value, "one"); + let divListboxToRemove = document.getElementById("selectList13-removeContent-listbox"); + divListboxToRemove.innerHTML = ""; + assert_equals(selectList.value, "three", "The listbox part should be updated"); + selectListOption4.click(); + assert_equals(selectList.value, "four", "Controller code should be applied to the new options"); + + let selectListNewListbox = document.getElementById("selectList13-newListbox"); + selectListNewListbox.innerHTML = ""; + assert_equals(selectList.value, ""); + selectListOption4.click(); + assert_equals(selectList.value, ""); + }, "Controller code should be updated when nested parts are removed"); + + promise_test(async () => { + let selectList = document.getElementById("selectList14"); + assert_equals(selectList.value, "one"); + const selectListButton0 = document.getElementById("selectList14-button0"); + const selectListOption2 = document.getElementById("selectList14-option2"); + + selectListButton0.click(); + assert_true(selectList.open); + await clickOn(selectListOption2); + assert_equals(selectList.value, "two"); + + document.body.removeChild(selectList); + selectList.removeChild(selectListOption2); + assert_equals(selectList.value, "one"); + let newOption = document.createElement("option"); + newOption.innerText = "three"; + selectList.appendChild(newOption); + newOption.click(); + assert_equals(selectList.value, "three", "New option should receive controller code"); + + let doc = document.implementation.createHTMLDocument(''); + let selectList1 = doc.createElement('selectlist'); + let firstOption = doc.createElement('option'); + firstOption.innerText = 'one'; + let secondOption = doc.createElement('option'); + secondOption.innerText = 'two'; + selectList1.appendChild(firstOption); + selectList1.appendChild(secondOption); + assert_equals(selectList1.value, "one"); + secondOption.click(); + assert_equals(selectList1.value, "two"); + document.body.appendChild(selectList1); + selectList1.removeChild(secondOption); + assert_equals(selectList1.value, "one"); + }, "Moving a selectlist between documents should keep controller code active"); + + promise_test(async () => { + const selectList = document.getElementById("selectList15"); + const selectListButtonContainer = document.getElementById("selectList15-div0"); + + const outerDiv = document.createElement("div"); + const button = document.createElement("input"); + button.type = button.value = "button"; + button.setAttribute("behavior", "button"); + outerDiv.appendChild(button); + selectListButtonContainer.appendChild(outerDiv); + + await clickOn(selectList); + assert_true(selectList.open, "New button should receive controller code"); + }, "New parts should be detected even when in the subtree of an inserted node"); + + promise_test(async () => { + const selectList = document.getElementById("selectList16"); + const selectListButtonContainer = document.getElementById("selectList16-div0"); + const selectListButton = document.getElementById("selectList16-button0"); + + selectListButtonContainer.remove(); + + selectListButton.click(); + assert_false(selectList.open, "Removed button should no longer have controller code"); + }, "Part removals should be detected even when in the subtree of a removed node"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position-with-zoom.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position-with-zoom.tentative.html new file mode 100644 index 0000000000..692eed7caa --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position-with-zoom.tentative.html @@ -0,0 +1,135 @@ +<!DOCTYPE html> +<html> +<title>HTMLSelectListElement Test: popover position with zoom</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<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> + #selectList0 { + position: absolute; + top: 0px; + left: 0px; + zoom: 2; + } + + #selectList1 { + position: absolute; + bottom: 0px; + left: 0px; + zoom: 1.5; + } + + #selectList1-popover { + zoom: 2; + } + + #selectList2 { + position: absolute; + top: 0px; + right: 0px; + zoom: 3; + } + + #selectList3 { + position: absolute; + bottom: 0px; + right: 0px; + zoom: 4; + } + + #selectList3-popover { + zoom: 1.5; + } +</style> + +<selectlist id="selectList0"> + <button type=selectlist id="selectList0-button">Custom bottom left</button> + <listbox id="selectList0-popover"> + <option>bottom left</option> + <option>two</option> + <option>three</option> + </listbox> +</selectlist> +<br> + +<selectlist id="selectList1"> + <button type=selectlist id="selectList1-button">Custom top left</button> + <listbox id="selectList1-popover"> + <option>top left</option> + <option>two</option> + <option>three</option> + </listbox> +</selectlist> + +<selectlist id="selectList2"> + <button type=selectlist id="selectList2-button">Custom bottom right</button> + <listbox id="selectList2-popover"> + <option>bottom right</option> + <option>two</option> + <option>three</option> + </listbox> +</selectlist> + +<selectlist id="selectList3"> + <button type=selectlist id="selectList3-button">Custom top right</button> + <listbox id="selectList3-popover"> + <option>top right</option> + <option>two</option> + <option>three</option> + </listbox> +</selectlist> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Popover = document.getElementById("selectList0-popover"); + const selectList0Button = document.getElementById("selectList0-button"); + + await clickOn(selectList0); + assert_equals(Math.abs(Math.trunc(selectList0.getBoundingClientRect().bottom - selectList0Popover.getBoundingClientRect().top)), 0); + assert_equals(Math.abs(Math.trunc(selectList0.getBoundingClientRect().left - selectList0Popover.getBoundingClientRect().left)), 0); + }, "The popover should be bottom left positioned"); + + promise_test(async () => { + const selectList1 = document.getElementById("selectList1"); + const selectList1Popover = document.getElementById("selectList1-popover"); + const selectList1Button = document.getElementById("selectList1-button"); + + selectList1Button.click(); + assert_equals(Math.abs(Math.trunc(selectList1.getBoundingClientRect().top - selectList1Popover.getBoundingClientRect().bottom * 2)), 0); + assert_equals(Math.abs(Math.trunc(selectList1.getBoundingClientRect().left - selectList1Popover.getBoundingClientRect().left * 2)), 0); + }, "The popover should be top left positioned"); + + promise_test(async () => { + const selectList2 = document.getElementById("selectList2"); + const selectList2Popover = document.getElementById("selectList2-popover"); + const selectList2Button = document.getElementById("selectList2-button"); + + selectList2Button.click(); + assert_equals(Math.abs(Math.trunc(selectList2.getBoundingClientRect().bottom - selectList2Popover.getBoundingClientRect().top)), 0); + assert_equals(Math.abs(Math.trunc(selectList2.getBoundingClientRect().right - selectList2Popover.getBoundingClientRect().right)), 0); + }, "The popover should be bottom right positioned"); + + promise_test(async () => { + const selectList3 = document.getElementById("selectList3"); + const selectList3Popover = document.getElementById("selectList3-popover"); + const selectList3Button = document.getElementById("selectList3-button"); + + selectList3Button.click(); + assert_equals(Math.abs(Math.trunc(selectList3.getBoundingClientRect().top - selectList3Popover.getBoundingClientRect().bottom * 1.5)), 0); + assert_equals(Math.abs(Math.trunc(selectList3.getBoundingClientRect().right - selectList3Popover.getBoundingClientRect().right * 1.5)), 0); + }, "The popover should be top right positioned"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position.tentative.html new file mode 100644 index 0000000000..a19e2b0d28 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover-position.tentative.html @@ -0,0 +1,115 @@ +<!DOCTYPE html> +<html> +<title>HTMLSelectListElement Test: popover position</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<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> + #selectList0 { + position: absolute; + top: 0px; + left: 0px; + } + + #selectList1 { + position: absolute; + bottom: 0px; + left: 0px; + } + + #selectList2 { + position: absolute; + top: 0px; + right: 0px; + } + + #selectList3 { + position: absolute; + bottom: 0px; + right: 0px; + } +</style> + +<selectlist id="selectList0"> + <div popover slot="listbox" behavior="listbox" id="selectList0-popover"> + <option>bottom left</option> + <option>two</option> + <option>three</option> + </div> +</selectlist> +<br> + +<selectlist id="selectList1"> + <div popover slot="listbox" behavior="listbox" id="selectList1-popover"> + <option>top left</option> + <option>two</option> + <option>three</option> + </div> +</selectlist> + +<selectlist id="selectList2"> + <div popover slot="listbox" behavior="listbox" id="selectList2-popover"> + <option>bottom right</option> + <option>two</option> + <option>three</option> + </div> +</selectlist> + +<selectlist id="selectList3"> + <div popover slot="listbox" behavior="listbox" id="selectList3-popover"> + <option>top right</option> + <option>two</option> + <option>three</option> + </div> +</selectlist> + +<script> + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Popover = document.getElementById("selectList0-popover"); + + await clickOn(selectList0); + assert_equals(Math.abs(Math.trunc(selectList0.getBoundingClientRect().bottom - selectList0Popover.getBoundingClientRect().top)), 0); + assert_equals(Math.abs(Math.trunc(selectList0.getBoundingClientRect().left - selectList0Popover.getBoundingClientRect().left)), 0); + }, "The popover should be bottom left positioned"); + + promise_test(async () => { + const selectList1 = document.getElementById("selectList1"); + const selectList1Popover = document.getElementById("selectList1-popover"); + + await clickOn(selectList1); + assert_equals(Math.abs(Math.trunc(selectList1.getBoundingClientRect().top - selectList1Popover.getBoundingClientRect().bottom)), 0); + assert_equals(Math.abs(Math.trunc(selectList1.getBoundingClientRect().left - selectList1Popover.getBoundingClientRect().left)), 0); + }, "The popover should be top left positioned"); + + promise_test(async () => { + const selectList2 = document.getElementById("selectList2"); + const selectList2Popover = document.getElementById("selectList2-popover"); + + await clickOn(selectList2); + assert_equals(Math.abs(Math.trunc(selectList2.getBoundingClientRect().bottom - selectList2Popover.getBoundingClientRect().top)), 0); + assert_equals(Math.abs(Math.trunc(selectList2.getBoundingClientRect().right - selectList2Popover.getBoundingClientRect().right)), 0); + }, "The popover should be bottom right positioned"); + + promise_test(async () => { + const selectList3 = document.getElementById("selectList3"); + const selectList3Popover = document.getElementById("selectList3-popover"); + + await clickOn(selectList3); + assert_equals(Math.abs(Math.trunc(selectList3.getBoundingClientRect().top - selectList3Popover.getBoundingClientRect().bottom)), 0); + assert_equals(Math.abs(Math.trunc(selectList3.getBoundingClientRect().right - selectList3Popover.getBoundingClientRect().right)), 0); + }, "The popover should be top right positioned"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover.tentative.html new file mode 100644 index 0000000000..a26d026649 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-popover.tentative.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<title>HTMLSelectListElement Test: popover</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> + +<selectlist id="selectList0"> + <option>one</option> + <option id="selectList0-child2">two</option> + <option>three</option> + <option>four</option> +</selectlist> + +<selectlist id="selectList1"> + <button type=selectlist class=button> + Custom button + </button> + <listbox> + <option>one</option> + <option class="child2">two</option> + <option class="child3">three</option> + </listbox> +</selectlist> + +<selectlist id="selectList2"> + <!-- Swap out the listbox part without providing a replacement --> + <div slot="listbox"></div> +</selectlist> + +<selectlist id="selectList3"> + <div slot="listbox"> + <div popover behavior="listbox" id="selectList3-listbox"> + <option>one</option> + </div> + </div> +</selectlist> +<script> + + function clickOn(element) { + const actions = new test_driver.Actions(); + return actions.pointerMove(0, 0, {origin: element}) + .pointerDown({button: actions.ButtonType.LEFT}) + .pointerUp({button: actions.ButtonType.LEFT}) + .send(); + } + + promise_test(async () => { + const selectList0 = document.getElementById("selectList0"); + const selectList0Child2 = document.getElementById("selectList0-child2"); + assert_equals(selectList0.value, "one"); + assert_equals(selectList0.open, false); + await clickOn(selectList0); + assert_equals(selectList0.open, true); + await clickOn(selectList0Child2); + assert_equals(selectList0.value, "two"); + assert_equals(selectList0.open, false); + + await clickOn(selectList0); + assert_equals(selectList0.open, true); + await clickOn(selectList0Child2); + assert_equals(selectList0.open, false); + }, "Opening the popover and clicking an option should change the selectlist's value"); + + promise_test(async () => { + const selectList1 = document.getElementById("selectList1"); + const button = selectList1.querySelector(".button"); + const child2 = selectList1.querySelector(".child2"); + const child3 = selectList1.querySelector(".child3"); + assert_equals(selectList1.value, "one"); + assert_equals(selectList1.open, false); + await clickOn(button); + assert_equals(selectList1.open, true); + await clickOn(child2); + assert_equals(selectList1.value, "two", "Clicking an <option> should change the value"); + assert_equals(selectList1.open, false); + + await clickOn(button); + assert_equals(selectList1.open, true); + await clickOn(child3); + assert_equals(selectList1.value, "three", "Clicking a <div part='option'> should change the value"); + assert_equals(selectList1.open, false); + }, "With custom button and popover: opening the popover and clicking an option should change the selectlist's value"); + + promise_test(async () => { + const selectList2 = document.getElementById("selectList2"); + await clickOn(selectList2); + assert_equals(selectList2.value, ""); + assert_equals(selectList2.open, false); + }, "Clicking a popover with no listbox part does nothing"); + + promise_test(async () => { + const selectList3 = document.getElementById("selectList3"); + const selectList3Listbox = document.getElementById("selectList3-listbox"); + selectList3Listbox.remove(); + + await clickOn(selectList3); + assert_equals(selectList3.value, ""); + assert_equals(selectList3.open, false); + }, "Clicking a popover with a listbox that was removed does nothing"); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-light-dismiss-invalidation.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-light-dismiss-invalidation.tentative.html new file mode 100644 index 0000000000..bda5842a37 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-light-dismiss-invalidation.tentative.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="http://crbug.com/1429839"> +<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> + +<selectlist id=selectlist> + <option id=optone>one</option> + <option id=opttwo>two</option> +</selectlist> +<style> +selectlist { + background-color: rgb(0, 0, 255); +} +selectlist:closed { + background-color: rgb(0, 255, 0); +} +selectlist:open { + background-color: rgb(255, 0, 0); +} +</style> +<button id=button>hello world</button> + +<script> +promise_test(async () => { + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(0, 255, 0)', + 'The selectlist should match :closed at the start of the test.'); + + await test_driver.click(selectlist); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(255, 0, 0)', + 'The selectlist should match :open when opened.'); + + await test_driver.click(opttwo); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(0, 255, 0)', + 'The selectlist should match :closed after clicking an option.'); + + await test_driver.click(selectlist); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(255, 0, 0)', + 'The selectlist should match :open when reopened.'); + + await test_driver.click(button); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(0, 255, 0)', + 'The selectlist should match :closed after light dismiss.'); +}, 'selectlist should not match :open when light dismissed.'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-open-closed.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-open-closed.tentative.html new file mode 100644 index 0000000000..1d5a082c03 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-pseudo-open-closed.tentative.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/547"> +<link rel=help href="https://drafts.csswg.org/selectors/#open-state"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist id=myselectlist> + <button type=selectlist id=custombutton>button</button> + <option>one</option> + <option>two</option> +</selectlist> + +<script> +test(() => { + assert_false(myselectlist.matches(':open'), + 'Selectlist should not match :open while it is closed.'); + assert_true(myselectlist.matches(':closed'), + 'Selectlist should match :closed while it is closed.'); + + custombutton.click(); + + assert_true(myselectlist.matches(':open'), + 'Selectlist should match :open while it is open.'); + assert_false(myselectlist.matches(':closed'), + 'Selectlist should not match :closed while it is open.'); +}, 'Selectlist should support :open and :closed pseudo selectors.'); +</script> + +<selectlist id=selectlistinvalidation> + <button type=selectlist>button</button> + <option>one</option> + <option>two</option> +</selectlist> +<style> +selectlist:closed { + background-color: red; +} +selectlist:open { + background-color: green; +} +</style> + +<script> +test(() => { + const selectlist = document.getElementById('selectlistinvalidation'); + const button = selectlist.querySelector('button'); + const option = selectlist.querySelector('option'); + + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(255, 0, 0)', + 'The style rules from :closed should apply when the selectlist is closed.'); + + button.click(); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(0, 128, 0)', + 'The style rules from :open should apply when the selectlist is open.'); + + option.click(); + assert_equals(getComputedStyle(selectlist).backgroundColor, 'rgb(255, 0, 0)', + 'The style rules from :closed should apply when the selectlist is opened and closed again.'); +}, 'Selectlist :open and :closed should invalidate correctly.'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-required-attribute.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-required-attribute.tentative.html new file mode 100644 index 0000000000..ef4408915b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-required-attribute.tentative.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: required attribute</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> + selectlist:required { + border: 3px dashed rgb(255, 0, 0); + } + + selectlist:optional { + border: 1px solid rgb(128, 128, 128); + } +</style> + +<selectlist id="selectlist0" required> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<selectlist id="selectlist1"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<selectlist id="selectlist2"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> + +<script> +function checkRequired(style) { + assert_equals(style.borderWidth, '3px'); + assert_equals(style.borderStyle, 'dashed'); + assert_equals(style.borderColor, 'rgb(255, 0, 0)'); +} + +function checkOptional(style) { + assert_equals(style.borderWidth, '1px'); + assert_equals(style.borderStyle, 'solid'); + assert_equals(style.borderColor, 'rgb(128, 128, 128)'); +} + +test(() => { + const selectList0 = document.getElementById("selectlist0"); + const selectList1 = document.getElementById("selectlist1"); + const selectList2 = document.getElementById("selectlist2"); + + checkRequired(window.getComputedStyle(selectList0)); + checkOptional(window.getComputedStyle(selectList1)); + checkOptional(window.getComputedStyle(selectList2)); + selectList2.required = true; + checkRequired(window.getComputedStyle(selectList2)); +}, "Test required attribute"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl-ref.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl-ref.tentative.html new file mode 100644 index 0000000000..7c71ea079c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl-ref.tentative.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('option'); + document.body.appendChild(selectlist); + const button = selectlist.querySelector('.fake-selectlist-internal-selectlist-button'); + button.style.direction = "rtl"; + button.style.width = "300px"; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl.tentative.html new file mode 100644 index 0000000000..24f7959632 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-rtl.tentative.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<!-- Tests selectlist text alignment in rtl --> +<link rel=author href="mailto:pkotwicz@chromium.org"> +<link rel="match" href="selectlist-rtl-ref.tentative.html"> + +<style> +selectlist { + direction:rtl; + width:300px; +} +</style> +<selectlist> + <option>option</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior-ref.html new file mode 100644 index 0000000000..7d76f1c817 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior-ref.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('hello world'); + document.body.appendChild(selectlist); + selectlist.querySelector('.fake-selectlist-selected-value') + .style.color = 'blue'; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior.tentative.html new file mode 100644 index 0000000000..a43e43d267 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-behavior.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-selected-value-behavior-ref.html"> + +<selectlist> + <div style="color:blue" slot=selected-value behavior=selected-value></div> + <option>hello world</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part-ref.html new file mode 100644 index 0000000000..3be168beba --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part-ref.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('hello world'); + document.body.appendChild(selectlist); + selectlist.querySelector('.fake-selectlist-selected-value') + .style.backgroundColor = 'red'; +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part.tentative.html new file mode 100644 index 0000000000..8fc05480d1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-part.tentative.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-selected-value-part-ref.html"> + +<style> +selectlist::part(selected-value) { + background-color: red; +} +</style> +<selectlist> + <option>hello world</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot-ref.html new file mode 100644 index 0000000000..ecb8c886a1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot-ref.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<script src="support/fake-selectlist.js"></script> +<body> +<script> + const selectlist = createFakeSelectlist('hello world'); + document.body.appendChild(selectlist); + + const oldSelectedValue = selectlist.querySelector('.fake-selectlist-selected-value'); + const newSelectedValue = document.createElement('div'); + newSelectedValue.textContent = 'new selected value'; + + replaceChildElement(newSelectedValue, oldSelectedValue); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot.tentative.html new file mode 100644 index 0000000000..c69a962c29 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selected-value-slot.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=match href="selectlist-selected-value-slot-ref.html"> + +<selectlist> + <div slot=selected-value>new selected value</div> + <option>hello world</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning-ref.html new file mode 100644 index 0000000000..1c0be58d67 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<button> + <span style="color:red">red</span> one +</button> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning.tentative.html new file mode 100644 index 0000000000..5d273c21bf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element-cloning.tentative.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/571"> +<link rel=match href="selectlist-selectedoption-element-cloning-ref.html"> + +<selectlist> + <button type=selectlist> + <selectedoption></selectedoption> + </button> + <option><span style="color:red">red</span> one</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element.tentative.html new file mode 100644 index 0000000000..593c4a6f21 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-selectedoption-element.tentative.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist> + <div>Foo <selectedoption></selectedoption> Bar</div> + <option>one</option> + <option>two</option> +</selectlist> + +<script> +test(() => { + const selectlist = document.querySelector('selectlist'); + const selectedoption = document.querySelector('selectedoption'); + const div = document.querySelector('div'); + + assert_equals(selectlist.value, 'one', 'one should be selected initially.'); + assert_equals(selectedoption.textContent, 'one', "selectedoption's initial text content should be one."); + assert_equals(div.textContent, 'Foo one Bar', 'Outer textContent should include default selectedoption.'); + + selectlist.value = 'two'; + assert_equals(selectlist.value, 'two', "assigning two into selectlists's value should work."); + assert_equals(selectedoption.textContent, 'two', "selectedoption's text content should be updated with the new value."); + assert_equals(div.textContent, 'Foo two Bar', 'Outer textContent should include new selectedoption.'); +}, "<selectedoption>'s text contents should be replaced with its ancestor <selectlist>'s selected value."); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tab-navigation.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tab-navigation.tentative.html new file mode 100644 index 0000000000..3b7d9d3d9a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tab-navigation.tentative.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<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 id="input1"> +<selectlist id="selectlist"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> +<input id="input3"> + +<script> +promise_test(async () => { + const TAB_KEY = "\uE004"; + + const input1 = document.getElementById("input1"); + const selectlist = document.getElementById("selectlist"); + + input1.focus(); + assert_equals(document.activeElement.id, "input1", "input1 should be active"); + + await test_driver.send_keys(input1, TAB_KEY); + assert_equals(document.activeElement.id, "selectlist", "selectlist should be active"); + + await test_driver.send_keys(selectlist, TAB_KEY); + assert_equals(document.activeElement.id, "input3", "input3 should be active"); +}, "Check that <selectlist> occupies just one slot in tab navigation."); +</script> + diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tabindex-order.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tabindex-order.tentative.html new file mode 100644 index 0000000000..c93efe1118 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-tabindex-order.tentative.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<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 id="input1"> +<selectlist id="selectlist" tabindex="2"> + <option>one</option> + <option>two</option> + <option>three</option> +</selectlist> +<input id="input3" tabindex="1"> + +<script> +promise_test(async () => { + const TAB_KEY = "\uE004"; + + const input1 = document.getElementById("input1"); + const input3 = document.getElementById("input3"); + + input1.focus(); + assert_equals(document.activeElement.id, "input1", "input1 should be active"); + + await test_driver.send_keys(input1, TAB_KEY); + assert_equals(document.activeElement.id, "input3", "input3 should be active"); + + await test_driver.send_keys(input3, TAB_KEY); + assert_equals(document.activeElement.id, "selectlist", "selectlist should be active"); +}, "Check that tabindex applies to <selectlist>"); +</script> + diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only-ref.html new file mode 100644 index 0000000000..ab28fbede6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only-ref.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<style> +.container { + display: inline-flex; + font-family: sans-serif; + font-size: 0.875em; +} +</style> +<div class=container>text node</div> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only.tentative.html new file mode 100644 index 0000000000..ceefeca608 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-text-only.tentative.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/702"> +<link rel=match href="selectlist-text-only-ref.html"> + +<selectlist> + text node + <option>option</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-user-select.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-user-select.tentative.html new file mode 100644 index 0000000000..078e8a4d83 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-user-select.tentative.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/687"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist id=useragent> + <option id=useragentoptionone>one</option> + <option id=useragentoptiontwo>two</option> +</selectlist> + +<selectlist id=custom> + <div id=custombutton slot=button behavior=button>button</div> + <div id=customlistbox popover=auto slot=listbox behavior=listbox>listbox</div> +</selectlist> + +<selectlist id=customwithselection style="user-select:auto"> + <div id=custombuttonwithselection slot=button behavior=button>button</div> + <div id=customlistboxwithselection popover=auto slot=listbox behavior=listbox>listbox</div> +</selectlist> + +<selectlist id=customwithmixedselection> + <div id=custombuttonwithmixedselection slot=button behavior=button style="user-select:auto">button</div> + <div id=customlistboxwithmixedselection popover=auto slot=listbox behavior=listbox style="user-select:auto">listbox</div> +</selectlist> + +<script> +test(() => { + assert_equals(getComputedStyle(useragent).userSelect, 'none', + 'The selectlist should have user-select:none.'); + assert_equals(getComputedStyle(useragentoptionone).userSelect, 'none', + 'The first option should have user-select:none.'); + assert_equals(getComputedStyle(useragentoptiontwo).userSelect, 'none', + 'The second option should have user-select:none.'); +}, 'Option elements should have user-select:none without slotting buttons or listboxes.'); + +test(() => { + assert_equals(getComputedStyle(custom).userSelect, 'none', + 'The selectlist should have user-select:none.'); + assert_equals(getComputedStyle(custombutton).userSelect, 'none', + 'The custom button should have user-select:none.'); + assert_equals(getComputedStyle(customlistbox).userSelect, 'none', + 'The custom listbox should have user-select:none.'); +}, 'Slotted in buttons and listboxes should have user-select:none.'); + +test(() => { + assert_equals(getComputedStyle(customwithselection).userSelect, 'auto', + 'The selectlist should have user-select:auto.'); + assert_equals(getComputedStyle(custombuttonwithselection).userSelect, 'auto', + 'The custom button should have user-select:auto.'); + assert_equals(getComputedStyle(customlistboxwithselection).userSelect, 'auto', + 'The custom listbox should have user-select:auto.'); +}, 'Setting user-select:auto on selectlists should re-enable selection.'); + +test(() => { + assert_equals(getComputedStyle(customwithmixedselection).userSelect, 'none', + 'The selectlist should have user-select:none.'); + assert_equals(getComputedStyle(custombuttonwithmixedselection).userSelect, 'auto', + 'The custom button should have user-select:auto.'); + assert_equals(getComputedStyle(customlistboxwithmixedselection).userSelect, 'auto', + 'The custom listbox should have user-select:auto.'); +}, 'Children of selectlist should be able to opt-in to user-select.'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-validity.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-validity.tentative.html new file mode 100644 index 0000000000..2b2033f668 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-validity.tentative.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html lang="en"> +<title>HTMLSelectListElement Test: validity</title> +<link rel="author" title="Ionel Popescu" href="mailto:iopopesc@microsoft.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist id="selectlist1" required> + <option>one</option> + <option>two</option> + <option>three</option> + <option>four</option> +</selectlist> + +<form> + <selectlist id="selectlist2" required> + </selectlist> +</form> + +<script> + +test(() => { + let selectList = document.createElement('selectlist'); + assert_true(selectList.willValidate, "A selectlist element is a submittable element that is a candidate for constraint validation."); + let option = document.createElement('option'); + selectList.appendChild(option); + assert_true(selectList.checkValidity(), "Always valid when the selectlist isn't a required value."); + + selectList.required = true; + assert_equals(selectList.value, ""); + assert_false(selectList.checkValidity(), "A selected placeholder option should invalidate the selectlist."); + + let emptyOption = document.createElement('option'); + selectList.appendChild(emptyOption); + assert_false(selectList.checkValidity(), "A selected placeholder option should invalidate the selectlist even if there are multiple options."); + emptyOption.selected = true; + assert_true(selectList.checkValidity(), "An empty non-placeholder option should be a valid choice."); + + let filledOption = document.createElement('option'); + filledOption.value = "test"; + selectList.appendChild(filledOption); + filledOption.selected = true; + assert_equals(selectList.value, "test", "The non-empty value should be set."); + assert_true(selectList.checkValidity(), "A non-empty non-placeholder option should be a valid choice."); + + selectList.removeChild(option); + selectList.appendChild(emptyOption); + emptyOption.selected = true; + assert_equals(selectList.value, "", "The empty value should be set."); + assert_true(selectList.checkValidity(), "Only the first option can be seen as a placeholder."); + + selectList.removeChild(filledOption); + assert_false(selectList.checkValidity(), "A selected placeholder option should invalidate the selectlist."); + + emptyOption.value = "test2"; + assert_equals(selectList.value, "test2"); + assert_true(selectList.checkValidity(), "A non-empty option value should be a valid choice."); + + emptyOption.removeAttribute("value"); + assert_equals(selectList.value, ""); + assert_false(selectList.checkValidity()); + emptyOption.innerText = "test"; + assert_equals(selectList.value, "test"); + assert_true(selectList.checkValidity(), "A non-empty option should be a valid choice."); + + const selectList1 = document.getElementById('selectlist1'); + assert_equals(selectList1.value, "one"); + assert_true(selectList1.checkValidity(), "A selectlist with non-empty placeholder option should be valid."); +}, "Validation for placeholder option"); + +test(() => { + const selectList2 = document.getElementById('selectlist2'); + assert_equals(selectList2.value, ""); + assert_false(selectList2.checkValidity()); + let form = document.querySelector('form'); + let invalidControl = form.querySelector('selectlist:invalid'); + assert_equals(selectList2, invalidControl); + let didDispatchInvalid = false; + invalidControl.addEventListener('invalid', e => { didDispatchInvalid = true; }); + let didDispatchSubmit = false; + form.addEventListener('submit', event => { event.preventDefault(); didDispatchSubmit = true; }); + + form.requestSubmit(); + assert_true(didDispatchInvalid); + assert_false(didDispatchSubmit); +}, "Check form not submitted for invalid selectlist"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-option.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-option.tentative.html new file mode 100644 index 0000000000..243067937c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-option.tentative.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/664"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist id=selectlist> + <option id=optone>innertext one</option> + <option id=opttwo value=valueattribute>innertext two</option> +</selectlist> + +<script> +test(() => { + assert_equals(selectlist.value, 'innertext one', + 'The first option should be selected initially.'); + selectlist.value = 'valueattribute'; + assert_equals(selectlist.value, 'valueattribute', + 'Assigning value should look at the options value, not innertext'); +}, 'selectlist.value should reflect option.value'); +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-selectedOption.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-selectedOption.tentative.html new file mode 100644 index 0000000000..20e72ac1dc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-value-selectedOption.tentative.html @@ -0,0 +1,224 @@ +<!DOCTYPE html> +<title>HTMLSelectListElement Test: value and selectedOption</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<selectlist id="selectList0"></selectlist> + +<selectlist id="selectList1"> + <option>one</option> + <option>two</option> + <div>I'm a div with no part attr</div> + <option id="selectList1-option3">three</option> + <option>four</option> +</selectlist> + +<selectlist id="selectList2"> + <div behavior="option">one</div> + <div behavior="option">two</div> + <div>I'm a div with no part attr</div> + <div behavior="option">three</div> + <div behavior="option">four</div> +</selectlist> + +<selectlist id="selectList3"> + <div>I'm a div with no part attr</div> + <option id="selectList3-child1">one</option> + <option id="selectList3-child2">two</option> + <option id="selectList3-child3">three</option> +</selectlist> + +<selectlist id="selectList4"> + <div slot="button" behavior="button"> + <div behavior="selected-value" id="selectList4-custom-selected-value">Default custom selected-value text</div> + </div> + <option id="selectList4-option1">one</option> + <option id="selectList4-option2">two</option> +</selectlist> + +<selectlist id="selectList5"> + <div slot="button" behavior="button"> + <div behavior="selected-value" id="selectList5-custom-selected-value">Default custom selected-value text</div> + </div> + <div popover slot="listbox" behavior="listbox"> + <option id="selectList5-option1">one</option> + <option id="selectList5-option2">two</option> + </div> +</selectlist> + +<selectlist id="selectList6"> + <option id="selectList6-option1">one</option> + <option id="selectList6-option2" selected>two</option> + <option id="selectList6-option3">three</option> +</selectlist> + +<selectlist id="selectList7"> + <option id="selectList7-option1">one</option> + <option id="selectList7-option2" selected value="test">two</option> + <option>three</option> +</selectlist> + +<script> + +test(() => { + const selectList0 = document.getElementById("selectList0"); + assert_equals(selectList0.value, ""); + assert_equals(selectList0.selectedOption, null); + selectList0.value = "something"; + assert_equals(selectList0.value, "", "If there is no matching option, selectlist should be cleared"); + assert_equals(selectList0.selectedOption, null); +}, "Test that HTMLSelectList with no options has empty string for value and null for selectedOption"); + +test(() => { + const selectList1 = document.getElementById("selectList1"); + assert_equals(selectList1.value, "one", "value should start with the text of the first option part"); + + selectList1.value = "three"; + assert_equals(selectList1.value, "three", "value can be set to the text of an option part"); + assert_equals(selectList1.selectedOption, document.getElementById("selectList1-option3")); + + selectList1.value = "I'm a div with no part attr"; + assert_equals(selectList1.value, "", "If there is no matching option selectlist should be cleared"); + assert_equals(selectList1.selectedOption, null); +}, "Test value and selectedOption with HTMLOptionElement element option parts"); + +test(() => { + const selectList1 = document.getElementById("selectList1"); + selectList1.value = "one"; + assert_equals(selectList1.value, "one"); + + selectList1.value = null; + assert_equals(selectList1.value, ""); + assert_equals(selectList1.selectedOption, null); +}, "Test value and selectedOption when value is null"); + +test(() => { + const selectList1 = document.getElementById("selectList1"); + selectList1.value = "one"; + assert_equals(selectList1.value, "one"); + + selectList1.value = undefined; + assert_equals(selectList1.value, ""); + assert_equals(selectList1.selectedOption, null); +}, "Test value and selectedOption when value is undefined"); + +test(() => { + const selectList2 = document.getElementById("selectList2"); + assert_equals(selectList2.value, "", "Non-HTMLOptionElements shouldn't be treated as option parts"); + assert_equals(selectList2.selectedOption, null); + + selectList2.value = "three"; + assert_equals(selectList2.value, "", "value can't be set when there are no option parts'"); + assert_equals(selectList2.selectedOption, null); +}, "Test value with non-HTMLOptionElement elements labeled as parts"); + +test(() => { + const selectList3 = document.getElementById("selectList3"); + assert_equals(selectList3.value, "one", "value should start with the text of the first option part"); + assert_equals(selectList3.selectedOption, document.getElementById("selectList3-child1")); + + document.getElementById("selectList3-child3").remove(); + assert_equals(selectList3.value, "one", "Removing a non-selected option should not change the value"); + assert_equals(selectList3.selectedOption, document.getElementById("selectList3-child1")); + + document.getElementById("selectList3-child1").remove(); + assert_equals(selectList3.value, "two", "When the selected option is removed, the new first option should become selected"); + assert_equals(selectList3.selectedOption, document.getElementById("selectList3-child2")); + + document.getElementById("selectList3-child2").remove(); + assert_equals(selectList3.value, "", "When all options are removed, value should be the empty string"); + assert_equals(selectList3.selectedOption, null); +}, "Test that value and selectedOption are updated when options are removed"); + +test(() => { + const selectList4 = document.getElementById("selectList4"); + let customSelectedValuePart = document.getElementById("selectList4-custom-selected-value"); + assert_equals(selectList4.value, "one", "value should start with the text of the first option part"); + assert_equals(selectList4.selectedOption, document.getElementById("selectList4-option1")); + assert_equals(customSelectedValuePart.innerText, "one", "Custom selected value part should be set to initial value of selectlist"); + + selectList4.value = "two"; + assert_equals(customSelectedValuePart.innerText, "two", "Custom selected value part should be updated when value of selectlist changes"); + assert_equals(selectList4.selectedOption, document.getElementById("selectList4-option2")); +}, "Test that slotted-in selected-value part is updated to value of selectlist"); + +test(() => { + const selectList5 = document.getElementById("selectList5"); + let customSelectedValuePart = document.getElementById("selectList5-custom-selected-value"); + assert_equals(selectList5.value, "one", "value should start with the text of the first option part"); + assert_equals(selectList5.selectedOption, document.getElementById("selectList5-option1")); + assert_equals(customSelectedValuePart.innerText, "one", "Custom selected value part should be set to initial value of selectlist"); + + selectList5.value = "two"; + assert_equals(customSelectedValuePart.innerText, "two", "Custom selected value part should be updated when value of selectlist changes"); + assert_equals(selectList5.selectedOption, document.getElementById("selectList5-option2")); +}, "Test that option parts in a slotted-in listbox are reflected in the value property"); + +test(() => { + let selectList = document.createElement('selectlist'); + assert_equals(selectList.value, ""); + let option = document.createElement('option'); + option.innerText = "one"; + selectList.appendChild(option); + assert_equals(selectList.value, "one"); + assert_equals(selectList.selectedOption, option); + + let newOption = document.createElement('option'); + newOption.innerText = 'two'; + selectList.appendChild(newOption); + selectList.value = "two"; + assert_equals(selectList.value, "two"); + assert_equals(selectList.selectedOption, newOption); + + option.click(); + assert_equals(selectList.value, "one"); + assert_equals(selectList.selectedOption, option); +}, "Test that value and selectedOption are correctly updated"); + +test(() => { + const selectList = document.getElementById("selectList6"); + let selectListOption1 = document.getElementById("selectList6-option1"); + + assert_equals(selectList.value, "two"); + assert_equals(selectList.selectedOption, document.getElementById("selectList6-option2")); + assert_false(selectListOption1.selected); + selectListOption1.selected = true; + assert_equals(selectList.value, "one"); + assert_equals(selectList.selectedOption, selectListOption1); + + let newOption = document.createElement("option"); + newOption.innerText = "four"; + newOption.selected = true; + selectList.appendChild(newOption); + assert_equals(selectList.value, "four"); + assert_equals(selectList.selectedOption, newOption); + assert_false(selectListOption1.selected); + + selectList.value = "three"; + assert_equals(selectList.selectedOption, document.getElementById("selectList6-option3")); + assert_false(newOption.selected); +}, "Test that HTMLOption.selected updates selectlist.value and selectlist.selectedOption"); + +test(() => { + const selectList = document.getElementById("selectList7"); + let selectListOption1 = document.getElementById("selectList7-option1"); + + assert_equals(selectList.value, "test"); + assert_equals(selectList.selectedOption, document.getElementById("selectList7-option2")); + assert_false(selectListOption1.selected); + selectListOption1.selected = true; + assert_equals(selectList.value, "one"); + assert_equals(selectList.selectedOption, selectListOption1); + + selectListOption1.value = "new test"; + assert_equals(selectList.value, "new test"); + assert_equals(selectList.selectedOption, selectListOption1); + selectListOption1.removeAttribute("value"); + assert_equals(selectList.value, "one"); + assert_equals(selectList.selectedOption, selectListOption1); + selectListOption1.value = ""; + assert_equals(selectList.value, ""); + assert_equals(selectList.selectedOption, selectListOption1); +}, "Test that HTMLOption.value updates selectlist.value"); + +</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-lr.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-lr.tentative.html new file mode 100644 index 0000000000..9973696ddd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-lr.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/600"> +<link rel=mismatch href="selectlist-writingmode-tb-ref.html"> + +<selectlist style="writing-mode: vertical-lr"> + <option>hello</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-rl.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-rl.tentative.html new file mode 100644 index 0000000000..dc74203e69 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-rl.tentative.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/600"> +<link rel=mismatch href="selectlist-writingmode-tb-ref.html"> + +<selectlist style="writing-mode: vertical-rl"> + <option>hello</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-tb-ref.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-tb-ref.html new file mode 100644 index 0000000000..db922f5f9f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/selectlist-writingmode-tb-ref.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<selectlist style="writing-mode: horizontal-tb"> + <option>hello</option> +</selectlist> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/back.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/back.html new file mode 100644 index 0000000000..9cc5a1d603 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/back.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<script>history.back()</script> diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/fake-selectlist.js b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/fake-selectlist.js new file mode 100644 index 0000000000..77b3f74921 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/fake-selectlist.js @@ -0,0 +1,112 @@ +function replaceChildElement(newChild, oldChild) { + oldChild.parentElement.replaceChild(newChild, oldChild); +} + +function createFakeSelectlist(selectedValueText, includeListbox) { + const selectlist = document.createElement('div'); + selectlist.classList.add('fake-selectlist'); + selectlist.innerHTML = ` + <button class="fake-selectlist-internal-selectlist-button"> + <div class="fake-selectlist-selected-value"></div> + <div class="fake-selectlist-internal-selectlist-button-icon"></div> + </button> + `; + if (includeListbox) { + const listbox = document.createElement('div'); + listbox.classList.add('fake-selectlist-listbox'); + listbox.anchorElement = selectlist; + selectlist.appendChild(listbox); + } + selectlist.appendChild(createFakeSelectlistStyles()); + + const selectedvalue = selectlist.querySelector('.fake-selectlist-selected-value'); + if (selectedValueText) { + selectedvalue.textContent = selectedValueText; + } + + return selectlist; +} + +function createFakeSelectlistStyles() { + const style = document.createElement('style'); + style.textContent = ` + .fake-selectlist { + display: inline-flex; + font-family: sans-serif; + font-size: 0.875em; + user-select: none; + } + + .fake-selectlist-internal-selectlist-button { + color: fieldtext; + background-color: field; + appearance: none; + cursor: default; + font-size: inherit; + text-align: inherit; + display: inline-flex; + flex-grow: 1; + flex-shrink: 1; + align-items: center; + overflow-x: hidden; + overflow-y: hidden; + padding: 0.25em; + border-width: 1px; + border-style: solid; + border-color: buttonborder; + border-image: initial; + border-radius: 0.25em; + } + + .fake-selectlist-selected-value { + color: FieldText; + flex-grow:1; + } + + .fake-selectlist-internal-selectlist-button-icon { + background-image: url(support/selectlist_button_icon.svg); + background-origin: content-box; + background-repeat: no-repeat; + background-size: contain; + height: 1.0em; + margin-inline-start: 4px; + opacity: 1; + outline: none; + padding-bottom: 2px; + padding-inline-start: 3px; + padding-inline-end: 3px; + padding-top: 2px; + width: 1.2em; + } + + .fake-selectlist-listbox { + font-family: sans-serif; + box-shadow: rgba(0, 0, 0, 0.13) 0px 12.8px 28.8px, rgba(0, 0, 0, 0.11) 0px 0px 9.2px; + box-sizing: border-box; + background-color: canvas; + min-inline-size: anchor-size(self-inline); + min-block-size: 1lh; + position: fixed; + width: fit-content; + height: fit-content; + color: canvastext; + overflow: auto; + border-width: initial; + border-style: solid; + border-color: initial; + border-image: initial; + border-radius: 0.25em; + padding: 0.25em; + margin: 0px; + inset: auto; + + top: anchor(bottom); + } + + .fake-selectlist option { + font-size: 0.875em; + padding: 0.25em; + } + `; + return style; +} diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/selectlist_button_icon.svg b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/selectlist_button_icon.svg new file mode 100644 index 0000000000..1a6c0193e8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/support/selectlist_button_icon.svg @@ -0,0 +1,3 @@ +<svg width="20" height="14" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">\ + <path d="M4 6 L10 12 L 16 6" stroke="WindowText" stroke-width="3" stroke-linejoin="round"/>\ +</svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/tab-closes-listbox.tentative.html b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/tab-closes-listbox.tentative.html new file mode 100644 index 0000000000..1706ed34cc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/the-selectlist-element/tab-closes-listbox.tentative.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/openui/open-ui/issues/599"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1359089"> +<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> + +<selectlist id=defaultlistbox> + <option>one</option> + <option>two</option> +</selectlist> + +<selectlist id=customlistbox> + <listbox> + <option>one</option> + <option>two</option> + </listbox> +</selectlist> + +<script> +const tabKey = '\uE004'; + +document.querySelectorAll('selectlist').forEach(selectlist => { + promise_test(async () => { + selectlist.focus(); + await test_driver.send_keys(selectlist, ' '); + assert_true(selectlist.open, 'Listbox should be open after pressing space.'); + + selectlist.addEventListener('keydown', event => { + if (event.key === 'Tab') { + event.preventDefault(); + } + }, {once: true}); + await test_driver.send_keys(document.activeElement, tabKey); + assert_true(selectlist.open, 'Listbox should stay open when the tab keydown is preventDefaulted.'); + + await test_driver.send_keys(document.activeElement, tabKey); + assert_false(selectlist.open, 'Listbox should close after pressing the tab key.'); + }, `${selectlist.id}: Pressing tab should close the listbox.`); +}); +</script> |