Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<title>HTMLselectElement 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>
<select id="select0">
<button id="select0-button">
<selectedvalue></selectedvalue>
select0-button
</button>
<option>one</option>
<option>two</option>
<option>three</option>
</select>
<select id="select1">
<option>one</option>
<option>
two
<button id="select1-button">select1-button</button>
</option>
<option>three</option>
</select>
<select id="select2">
<option>one</option>
<option>two</option>
<option>three</option>
</select>
<select id="select3">
<option>same</option>
<option>same</option>
</select>
<select id="select4">
<option>one</option>
<option id="select4-option2">two</option>
</select>
<select id="select5WithTabIndex" tabindex="1">
<option>one</option>
<option>two</option>
</select>
<input id="input6"/>
<select id="select7">
<button id="select7-button">
select7-button
</button>
<option>one</option>
<option>two</option>
</select>
<style>
select, ::picker(select) {
appearance: base-select;
}
</style>
<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 (t) => {
const select = document.getElementById("select0");
const selectButton = document.getElementById("select0-button");
assert_false(select.matches(':open'));
const selectButtonWatcher = new EventWatcher(t, selectButton, ["click"]);
const selectButtonPromise = selectButtonWatcher.wait_for("click").then((e) => {
assert_false(select.matches(':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();
});
const selectWatcher = new EventWatcher(t, select, ["click"]);
const selectPromise = selectWatcher.wait_for("click").then((e) => {
assert_true(e.defaultPrevented, "Event should have been defaultPrevented by selectButton click handler");
assert_false(select.matches(':open'), "Listbox shouldn't have opened, because click event was defaultPrevented.");
});
return Promise.all([selectButtonPromise, selectPromise, clickOn(selectButton)]);
}, "Button controller code should not run if the click event is preventDefaulted.");
const KEY_CODE_MAP = {
'Tab': '\uE004',
'Enter': '\uE007',
'Space': '\uE00D',
'ArrowUp': '\uE013',
'ArrowDown': '\uE015',
};
promise_test(async (t) => {
const select = document.getElementById("select1");
const selectButton = document.getElementById("select1-button");
await clickOn(select);
assert_true(select.matches(':open'));
const selectButtonWatcher = new EventWatcher(t, selectButton, ["click"]);
const selectButtonPromise = selectButtonWatcher.wait_for("click").then((e) => {
assert_true(select.matches(':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();
});
const selectWatcher = new EventWatcher(t, select, ["click"]);
const selectPromise = selectWatcher.wait_for("click").then((e) => {
assert_true(e.defaultPrevented, "Event should have been defaultPrevented by selectButton click handler");
assert_true(select.matches(':open'), "Listbox shouldn't have closed, because keydown event was defaultPrevented.");
assert_equals(select.value, "one", "<select> shouldn't have changed value, because keydown event was defaultPrevented.");
});
return Promise.all([selectButtonPromise, selectPromise, clickOn(selectButton)]);
}, "Listbox controller code should not run if the click event is preventDefaulted.");
promise_test(async (t) => {
const select = document.getElementById("select2");
const events = [];
select.addEventListener("input", t.step_func((e) => {
assert_true(e.composed, "input event should be composed.");
events.push('input');
}));
select.addEventListener("change", t.step_func((e) => {
assert_false(e.composed, "change event should not be composed.");
events.push('change');
}));
await clickOn(select);
assert_true(select.matches(':open'));
await test_driver.send_keys(select, KEY_CODE_MAP.Enter);
assert_false(select.matches(':open'));
assert_equals(select.value, "one");
assert_array_equals(events, [], "input and change shouldn't fire if value wansn't changed.");
await clickOn(select);
assert_true(select.matches(':open'));
await test_driver.send_keys(select, KEY_CODE_MAP.ArrowDown);
assert_equals(select.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(select, KEY_CODE_MAP.Enter);
assert_equals(select.value, "two");
assert_array_equals(events, ['input', 'input', 'change'], "input and change should fire after pressing enter.");
}, "<select> should fire input and change events when new option is selected.");
promise_test(async (t) => {
const select = document.getElementById("select3");
const events = [];
select.addEventListener("input", t.step_func((e) => {
assert_true(e.composed, "input event should be composed.");
events.push('input');
}));
select.addEventListener("change", t.step_func((e) => {
assert_false(e.composed, "change event should not be composed.");
events.push('change');
}));
await clickOn(select);
assert_true(select.matches(':open'));
await test_driver.send_keys(select, KEY_CODE_MAP.ArrowDown);
assert_array_equals(events, ['input'], "input event should have fired after ArrowDown.");
await test_driver.send_keys(select, KEY_CODE_MAP.Enter);
assert_array_equals(events, ['input', 'input', 'change'], "input and change should fire after pressing Enter.");
}, "<select> should fire input and change events even when new selected option has the same value as the old.");
promise_test(async (t) => {
const select = document.getElementById("select4");
const selectOption2 = document.getElementById("select4-option2");
let input_event_count = 0;
let change_event_count = 0;
select.addEventListener("input", t.step_func((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++;
}));
select.addEventListener("change", t.step_func((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(select);
assert_true(select.matches(':open'));
await clickOn(selectOption2);
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");
}, "<select> should fire input and change events when option in listbox is clicked");
promise_test(async() => {
const select = document.getElementById("select2");
await test_driver.send_keys(select, " ");
assert_true(select.matches(':open'), "<Space> should open select");
await test_driver.send_keys(select, KEY_CODE_MAP.Enter);
assert_false(select.matches(':open'), "<Enter> should close select");
}, "Check that <Space> opens <select>.");
promise_test(async() => {
const select = document.getElementById("select5WithTabIndex");
await test_driver.send_keys(select, " ");
assert_true(select.matches(':open'), "<Space> should open select");
await test_driver.send_keys(select, KEY_CODE_MAP.Enter);
assert_false(select.matches(':open'), "<Enter> should close select");
}, "Check that <Space> opens <select> when <select> specifies tabindex");
promise_test(async() => {
const input6 = document.getElementById("input6");
const select = document.getElementById("select7");
const selectButton = document.getElementById("select7-button")
var keydown_count = 0;
selectButton.addEventListener("keydown", (e) => {
keydown_count++;
});
// Focus select via Tab traversal because focus() does not work when select
// 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(select, "a");
assert_equals(keydown_count, 1, "button in shadowroot should have observed keydown");
}, "Test that <select> button slot receives key events.");
</script>