1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
<!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>
<!-- This test is optional because the HTML spec does not require that specific
behaviors are mapped to specific keyboard buttons. -->
<select id="select0">
<button id="select0-button">
<selectedcontent></selectedcontent>
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");
assert_false(select.matches(':open'));
const selectButtonWatcher = new EventWatcher(t, select, ["mousedown"]);
const selectButtonPromise = selectButtonWatcher.wait_for("mousedown").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, ["mousedown"]);
const selectPromise = selectWatcher.wait_for("mousedown").then((e) => {
assert_true(e.defaultPrevented, "Event should have been defaultPrevented by select mousedown handler");
assert_false(select.matches(':open'), "Listbox shouldn't have opened, because mousedown event was defaultPrevented.");
});
return Promise.all([selectButtonPromise, selectPromise, clickOn(select)]);
}, "Button controller code should not run if the mousedown 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 (t) => {
const select = document.getElementById("select1");
await clickOn(select);
assert_true(select.matches(':open'));
const selectButtonWatcher = new EventWatcher(t, select, ["mousedown"]);
const selectButtonPromise = selectButtonWatcher.wait_for("mousedown").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, ["mousedown"]);
const selectPromise = selectWatcher.wait_for("mousedown").then((e) => {
assert_true(e.defaultPrevented, "Event should have been defaultPrevented by select mousedown 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(select)]);
}, "Listbox controller code should not run if the mousedown 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(document.activeElement, 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(document.activeElement, 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 event should not fire when user switches options with arrow key.");
await test_driver.send_keys(document.activeElement, KEY_CODE_MAP.Enter);
assert_equals(select.value, "two");
assert_array_equals(events, ['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 event not should have fired after ArrowDown.");
await test_driver.send_keys(select, KEY_CODE_MAP.Enter);
assert_array_equals(events, [], "input and change should not fire after pressing Enter.");
}, "<select> should not fire input and change events 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(document.activeElement, 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(document.activeElement, KEY_CODE_MAP.Enter);
assert_false(select.matches(':open'), "<Enter> should close select");
}, "Check that <Space> opens <select> when <select> specifies tabindex");
</script>
|