|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <!-- |
|
4 https://bugzilla.mozilla.org/show_bug.cgi?id=935876 |
|
5 --> |
|
6 <head> |
|
7 <meta charset="utf-8"> |
|
8 <title>Test for Bug 935876</title> |
|
9 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
10 <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> |
|
11 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> |
|
12 </head> |
|
13 <body> |
|
14 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=935876">Mozilla Bug 935876</a> |
|
15 <p id="display"></p> |
|
16 <div> |
|
17 <select id="listbox" size="3"> |
|
18 <option selected>1</option> |
|
19 <option>2</option> |
|
20 <option>3</option> |
|
21 <option>4</option> |
|
22 <option>5</option> |
|
23 <option>6</option> |
|
24 <option>7</option> |
|
25 </select> |
|
26 <select id="multipleListbox" size="3" multiple> |
|
27 <option selected>1</option> |
|
28 <option>2</option> |
|
29 <option>3</option> |
|
30 <option>4</option> |
|
31 <option>5</option> |
|
32 <option>6</option> |
|
33 <option>7</option> |
|
34 </select> |
|
35 <select id="combobox"> |
|
36 <option selected>1</option> |
|
37 <option>2</option> |
|
38 <option>3</option> |
|
39 <option>4</option> |
|
40 <option>5</option> |
|
41 <option>6</option> |
|
42 <option>7</option> |
|
43 </select> |
|
44 </div> |
|
45 <pre id="test"> |
|
46 </pre> |
|
47 <script type="application/javascript"> |
|
48 SimpleTest.waitForExplicitFinish(); |
|
49 |
|
50 const kIsWin = navigator.platform.indexOf("Win") == 0; |
|
51 const kIsMac = navigator.platform.indexOf("Mac") == 0; |
|
52 const kIsAndroid = navigator.appVersion.indexOf("Android") != 0; |
|
53 |
|
54 function runTests() |
|
55 { |
|
56 var doPreventDefault = false; |
|
57 function onKeydown(aEvent) |
|
58 { |
|
59 if (doPreventDefault) { |
|
60 aEvent.preventDefault(); |
|
61 } |
|
62 } |
|
63 |
|
64 var keyPressEventFired = false; |
|
65 function onKeypress(aEvent) |
|
66 { |
|
67 keyPressEventFired = true; |
|
68 } |
|
69 |
|
70 var keyDownEventConsumedByJS = false; |
|
71 var keyDownEventConsumed = false; |
|
72 function onkeydownInSystemEventGroup(aEvent) |
|
73 { |
|
74 keyDownEventConsumedByJS = aEvent.defaultPrevented; |
|
75 keyDownEventConsumed = aEvent.getPreventDefault(); |
|
76 } |
|
77 |
|
78 function reset() |
|
79 { |
|
80 keyPressEventFired = false; |
|
81 keyDownEventConsumedByJS = false; |
|
82 keyDownEventConsumed = false; |
|
83 } |
|
84 |
|
85 function check(aExpectingKeydownConsumed, aDescription) |
|
86 { |
|
87 if (doPreventDefault) { |
|
88 ok(!keyPressEventFired, "keypress event shouldn't be fired for " + aDescription + |
|
89 " if preventDefault() of keydown event was called"); |
|
90 ok(keyDownEventConsumedByJS, "keydown event of " + aDescription + |
|
91 " should be consumed in content level if preventDefault() of keydown event is called"); |
|
92 ok(keyDownEventConsumed, "keydown event of " + aDescription + |
|
93 " should be consumed in system level if preventDefault() of keydown event is called"); |
|
94 } else if (aExpectingKeydownConsumed) { |
|
95 ok(!keyPressEventFired, "keypress event shouldn't be fired for " + aDescription); |
|
96 ok(!keyDownEventConsumedByJS, "keydown event of " + aDescription + " shouldn't be consumed in content level"); |
|
97 ok(keyDownEventConsumed, "keydown event of " + aDescription + " should be consumed in system level"); |
|
98 } else { |
|
99 ok(keyPressEventFired, "keypress event should be fired for " + aDescription); |
|
100 ok(!keyDownEventConsumedByJS, "keydown event of " + aDescription + " shouldn't be consumed in content level"); |
|
101 ok(!keyDownEventConsumed, "keydown event of " + aDescription + " should be consumed in system level"); |
|
102 } |
|
103 } |
|
104 |
|
105 var listbox = document.getElementById("listbox"); |
|
106 listbox.addEventListener("keydown", onKeydown, false); |
|
107 listbox.addEventListener("keypress", onKeypress, false); |
|
108 SpecialPowers.addSystemEventListener(listbox, "keydown", onkeydownInSystemEventGroup, false); |
|
109 |
|
110 listbox.focus(); |
|
111 |
|
112 [ false, true ].forEach(function (consume) { |
|
113 doPreventDefault = consume; |
|
114 for (var i = 0; i < listbox.options.length + 1; i++) { |
|
115 reset() |
|
116 synthesizeKey("VK_DOWN", {}); |
|
117 check(true, "DownArrow key on listbox #" + i); |
|
118 } |
|
119 |
|
120 for (var i = 0; i < listbox.options.length + 1; i++) { |
|
121 reset() |
|
122 synthesizeKey("VK_UP", {}); |
|
123 check(true, "UpArrow key on listbox #" + i); |
|
124 } |
|
125 |
|
126 for (var i = 0; i < listbox.options.length + 1; i++) { |
|
127 reset() |
|
128 synthesizeKey("VK_RIGHT", {}); |
|
129 check(true, "RightArrow key on listbox #" + i); |
|
130 } |
|
131 |
|
132 for (var i = 0; i < listbox.options.length + 1; i++) { |
|
133 reset() |
|
134 synthesizeKey("VK_LEFT", {}); |
|
135 check(true, "LeftArrow key on listbox #" + i); |
|
136 } |
|
137 |
|
138 for (var i = 0; i < 4; i++) { |
|
139 reset() |
|
140 synthesizeKey("VK_PAGE_DOWN", {}); |
|
141 check(true, "PageDown key on listbox #" + i); |
|
142 } |
|
143 |
|
144 for (var i = 0; i < 4; i++) { |
|
145 reset() |
|
146 synthesizeKey("VK_PAGE_UP", {}); |
|
147 check(true, "PageUp key on listbox #" + i); |
|
148 } |
|
149 |
|
150 for (var i = 0; i < 2; i++) { |
|
151 reset() |
|
152 synthesizeKey("VK_END", {}); |
|
153 check(true, "End key on listbox #" + i); |
|
154 } |
|
155 |
|
156 for (var i = 0; i < 2; i++) { |
|
157 reset() |
|
158 synthesizeKey("VK_HOME", {}); |
|
159 check(true, "Home key on listbox #" + i); |
|
160 } |
|
161 |
|
162 reset() |
|
163 synthesizeKey("VK_RETURN", {}); |
|
164 check(false, "Enter key on listbox"); |
|
165 |
|
166 reset() |
|
167 synthesizeKey("VK_ESCAPE", {}); |
|
168 check(false, "Esc key on listbox"); |
|
169 |
|
170 reset() |
|
171 synthesizeKey("VK_F4", {}); |
|
172 check(false, "F4 key on listbox"); |
|
173 |
|
174 reset() |
|
175 synthesizeKey("a", {}); |
|
176 check(false, "'A' key on listbox"); |
|
177 }); |
|
178 |
|
179 listbox.removeEventListener("keydown", onKeydown, false); |
|
180 listbox.removeEventListener("keypress", onKeypress, false); |
|
181 SpecialPowers.removeSystemEventListener(listbox, "keydown", onkeydownInSystemEventGroup, false); |
|
182 |
|
183 |
|
184 |
|
185 var multipleListbox = document.getElementById("multipleListbox"); |
|
186 multipleListbox.addEventListener("keydown", onKeydown, false); |
|
187 multipleListbox.addEventListener("keypress", onKeypress, false); |
|
188 SpecialPowers.addSystemEventListener(multipleListbox, "keydown", onkeydownInSystemEventGroup, false); |
|
189 |
|
190 multipleListbox.focus(); |
|
191 |
|
192 [ false, true ].forEach(function (consume) { |
|
193 doPreventDefault = consume; |
|
194 for (var i = 0; i < multipleListbox.options.length + 1; i++) { |
|
195 reset() |
|
196 synthesizeKey("VK_DOWN", {}); |
|
197 check(true, "DownArrow key on multiple listbox #" + i); |
|
198 } |
|
199 |
|
200 for (var i = 0; i < multipleListbox.options.length + 1; i++) { |
|
201 reset() |
|
202 synthesizeKey("VK_UP", {}); |
|
203 check(true, "UpArrow key on multiple listbox #" + i); |
|
204 } |
|
205 |
|
206 for (var i = 0; i < multipleListbox.options.length + 1; i++) { |
|
207 reset() |
|
208 synthesizeKey("VK_RIGHT", {}); |
|
209 check(true, "RightArrow key on multiple listbox #" + i); |
|
210 } |
|
211 |
|
212 for (var i = 0; i < multipleListbox.options.length + 1; i++) { |
|
213 reset() |
|
214 synthesizeKey("VK_LEFT", {}); |
|
215 check(true, "LeftArrow key on multiple listbox #" + i); |
|
216 } |
|
217 |
|
218 for (var i = 0; i < 4; i++) { |
|
219 reset() |
|
220 synthesizeKey("VK_PAGE_DOWN", {}); |
|
221 check(true, "PageDown key on multiple listbox #" + i); |
|
222 } |
|
223 |
|
224 for (var i = 0; i < 4; i++) { |
|
225 reset() |
|
226 synthesizeKey("VK_PAGE_UP", {}); |
|
227 check(true, "PageUp key on multiple listbox #" + i); |
|
228 } |
|
229 |
|
230 for (var i = 0; i < 2; i++) { |
|
231 reset() |
|
232 synthesizeKey("VK_END", {}); |
|
233 check(true, "End key on multiple listbox #" + i); |
|
234 } |
|
235 |
|
236 for (var i = 0; i < 2; i++) { |
|
237 reset() |
|
238 synthesizeKey("VK_HOME", {}); |
|
239 check(true, "Home key on multiple listbox #" + i); |
|
240 } |
|
241 |
|
242 reset() |
|
243 synthesizeKey("VK_RETURN", {}); |
|
244 check(true, "Enter key on multiple listbox"); |
|
245 |
|
246 reset() |
|
247 synthesizeKey("VK_ESCAPE", {}); |
|
248 check(false, "Esc key on multiple listbox"); |
|
249 |
|
250 reset() |
|
251 synthesizeKey("VK_F4", {}); |
|
252 check(false, "F4 key on multiple listbox"); |
|
253 |
|
254 reset() |
|
255 synthesizeKey("a", {}); |
|
256 check(false, "'A' key on multiple listbox"); |
|
257 }); |
|
258 |
|
259 multipleListbox.removeEventListener("keydown", onKeydown, false); |
|
260 multipleListbox.removeEventListener("keypress", onKeypress, false); |
|
261 SpecialPowers.removeSystemEventListener(multipleListbox, "keydown", onkeydownInSystemEventGroup, false); |
|
262 |
|
263 |
|
264 |
|
265 var combobox = document.getElementById("combobox"); |
|
266 combobox.addEventListener("keydown", onKeydown, false); |
|
267 combobox.addEventListener("keypress", onKeypress, false); |
|
268 SpecialPowers.addSystemEventListener(combobox, "keydown", onkeydownInSystemEventGroup, false); |
|
269 |
|
270 combobox.focus(); |
|
271 |
|
272 [ false, true ].forEach(function (consume) { |
|
273 doPreventDefault = consume; |
|
274 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
275 reset() |
|
276 synthesizeKey("VK_DOWN", {}); |
|
277 check(true, "DownArrow key on combobox #" + i); |
|
278 } |
|
279 |
|
280 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
281 reset() |
|
282 synthesizeKey("VK_UP", {}); |
|
283 check(true, "UpArrow key on combobox #" + i); |
|
284 } |
|
285 |
|
286 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
287 reset() |
|
288 synthesizeKey("VK_RIGHT", {}); |
|
289 check(true, "RightArrow key on combobox #" + i); |
|
290 } |
|
291 |
|
292 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
293 reset() |
|
294 synthesizeKey("VK_LEFT", {}); |
|
295 check(true, "LeftArrow key on combobox #" + i); |
|
296 } |
|
297 |
|
298 for (var i = 0; i < 4; i++) { |
|
299 reset() |
|
300 synthesizeKey("VK_PAGE_DOWN", {}); |
|
301 check(true, "PageDown key on combobox #" + i); |
|
302 } |
|
303 |
|
304 for (var i = 0; i < 4; i++) { |
|
305 reset() |
|
306 synthesizeKey("VK_PAGE_UP", {}); |
|
307 check(true, "PageUp key on combobox #" + i); |
|
308 } |
|
309 |
|
310 for (var i = 0; i < 2; i++) { |
|
311 reset() |
|
312 synthesizeKey("VK_END", {}); |
|
313 check(true, "End key on combobox #" + i); |
|
314 } |
|
315 |
|
316 for (var i = 0; i < 2; i++) { |
|
317 reset() |
|
318 synthesizeKey("VK_HOME", {}); |
|
319 check(true, "Home key on combobox #" + i); |
|
320 } |
|
321 |
|
322 reset() |
|
323 synthesizeKey("VK_RETURN", {}); |
|
324 check(false, "Enter key on combobox"); |
|
325 |
|
326 reset() |
|
327 synthesizeKey("VK_ESCAPE", {}); |
|
328 check(true, "Esc key on combobox"); |
|
329 |
|
330 if (!kIsWin) { |
|
331 reset() |
|
332 synthesizeKey("VK_F4", {}); |
|
333 check(false, "F4 key on combobox"); |
|
334 } |
|
335 |
|
336 reset() |
|
337 synthesizeKey("a", {}); |
|
338 check(false, "'A' key on combobox"); |
|
339 }); |
|
340 |
|
341 function finish() |
|
342 { |
|
343 combobox.removeEventListener("keydown", onKeydown, false); |
|
344 combobox.removeEventListener("keypress", onKeypress, false); |
|
345 SpecialPowers.removeSystemEventListener(combobox, "keydown", onkeydownInSystemEventGroup, false); |
|
346 SimpleTest.finish(); |
|
347 } |
|
348 |
|
349 // Mac uses native popup for dropdown. Let's skip the tests for popup |
|
350 // since it's not handled in nsListControlFrame. |
|
351 // Similarly, Android doesn't use popup for dropdown. |
|
352 if (kIsMac || kIsAndroid) { |
|
353 finish(); |
|
354 return; |
|
355 } |
|
356 |
|
357 function testDropDown(aCallback) |
|
358 { |
|
359 testOpenDropDown(function () { |
|
360 reset() |
|
361 synthesizeKey("VK_DOWN", { altKey: true }); |
|
362 }, function () { |
|
363 check(true, "Alt + DownArrow key on combobox at opening dropdown"); |
|
364 |
|
365 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
366 reset() |
|
367 synthesizeKey("VK_DOWN", {}); |
|
368 check(true, "DownArrow key on combobox during dropdown open #" + i); |
|
369 } |
|
370 |
|
371 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
372 reset() |
|
373 synthesizeKey("VK_UP", {}); |
|
374 check(true, "UpArrow key on combobox during dropdown open #" + i); |
|
375 } |
|
376 |
|
377 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
378 reset() |
|
379 synthesizeKey("VK_RIGHT", {}); |
|
380 check(true, "RightArrow key on combobox during dropdown open #" + i); |
|
381 } |
|
382 |
|
383 for (var i = 0; i < combobox.options.length + 1; i++) { |
|
384 reset() |
|
385 synthesizeKey("VK_LEFT", {}); |
|
386 check(true, "LeftArrow key on combobox during dropdown open #" + i); |
|
387 } |
|
388 |
|
389 for (var i = 0; i < 4; i++) { |
|
390 reset() |
|
391 synthesizeKey("VK_PAGE_DOWN", {}); |
|
392 check(true, "PageDown key on combobox during dropdown open #" + i); |
|
393 } |
|
394 |
|
395 for (var i = 0; i < 4; i++) { |
|
396 reset() |
|
397 synthesizeKey("VK_PAGE_UP", {}); |
|
398 check(true, "PageUp key on combobox during dropdown open #" + i); |
|
399 } |
|
400 |
|
401 for (var i = 0; i < 2; i++) { |
|
402 reset() |
|
403 synthesizeKey("VK_END", {}); |
|
404 check(true, "End key on combobox during dropdown open #" + i); |
|
405 } |
|
406 |
|
407 for (var i = 0; i < 2; i++) { |
|
408 reset() |
|
409 synthesizeKey("VK_HOME", {}); |
|
410 check(true, "Home key on combobox during dropdown open #" + i); |
|
411 } |
|
412 |
|
413 testCloseDropDown(function () { |
|
414 reset() |
|
415 synthesizeKey("VK_RETURN", {}); |
|
416 }, function () { |
|
417 testOpenDropDown(function () { |
|
418 check(true, "Enter key on combobox at closing dropdown"); |
|
419 |
|
420 synthesizeKey("VK_UP", { altKey: true }); |
|
421 }, function () { |
|
422 check(true, "Alt + UpArrow key on combobox at opening dropdown"); |
|
423 |
|
424 testCloseDropDown(function () { |
|
425 reset() |
|
426 synthesizeKey("VK_ESCAPE", {}); |
|
427 }, function () { |
|
428 check(true, "Esc key on combobox at closing dropdown"); |
|
429 |
|
430 // F4 key opens/closes dropdown only on Windows. So, other platforms |
|
431 // don't need to do anymore. |
|
432 if (!kIsWin) { |
|
433 aCallback(); |
|
434 return; |
|
435 } |
|
436 |
|
437 testOpenDropDown(function () { |
|
438 reset() |
|
439 synthesizeKey("VK_F4", {}); |
|
440 }, function () { |
|
441 check(true, "F4 key on combobox at opening dropdown on Windows"); |
|
442 |
|
443 testCloseDropDown(function () { |
|
444 reset() |
|
445 synthesizeKey("VK_F4", {}); |
|
446 }, function () { |
|
447 check(true, "F4 key on combobox at closing dropdown on Windows"); |
|
448 |
|
449 aCallback(); |
|
450 return; |
|
451 }); |
|
452 }); |
|
453 }); |
|
454 }); |
|
455 }); |
|
456 }); |
|
457 } |
|
458 |
|
459 doPreventDefault = false; |
|
460 testDropDown(function () { |
|
461 // Even if keydown event is consumed by JS, opening/closing dropdown |
|
462 // should work for a11y and security (e.g., cannot close dropdown causes |
|
463 // staying top-most window on the screen). If it's blocked by JS, this |
|
464 // test would cause permanent timeout. |
|
465 doPreventDefault = true; |
|
466 testDropDown(finish); |
|
467 }); |
|
468 } |
|
469 |
|
470 function testOpenDropDown(aTest, aOnOpenDropDown) |
|
471 { |
|
472 document.addEventListener("popupshowing", function (aEvent) { |
|
473 document.removeEventListener(aEvent.type, arguments.callee, false); |
|
474 setTimeout(aOnOpenDropDown, 0); |
|
475 }, false); |
|
476 aTest(); |
|
477 } |
|
478 |
|
479 function testCloseDropDown(aTest, aOnCloseDropDown) |
|
480 { |
|
481 document.addEventListener("popuphiding", function (aEvent) { |
|
482 document.removeEventListener(aEvent.type, arguments.callee, false); |
|
483 setTimeout(aOnCloseDropDown, 0) |
|
484 }, false); |
|
485 aTest(); |
|
486 } |
|
487 |
|
488 SimpleTest.waitForFocus(runTests); |
|
489 </script> |
|
490 </body> |
|
491 </html> |