1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import org.htmlunit.WebDriverTestCase;
18 import org.htmlunit.junit.annotation.Alerts;
19 import org.htmlunit.junit.annotation.HtmlUnitNYI;
20 import org.junit.jupiter.api.AfterEach;
21 import org.junit.jupiter.api.Test;
22 import org.openqa.selenium.By;
23 import org.openqa.selenium.WebDriver;
24
25
26
27
28
29
30
31
32
33
34 public class FocusableElement2Test extends WebDriverTestCase {
35
36
37
38
39
40 @AfterEach
41 public void shutDownRealBrowsers() throws Exception {
42 super.shutDownAll();
43 }
44
45
46
47
48 @Test
49 @Alerts(DEFAULT = {"body", "active: body", "onload", "active: body",
50 "onfocus:[object Window]", "active: body"},
51 CHROME = {"body", "active: body", "onload", "active: body"},
52 EDGE = {"body", "active: body", "onload", "active: body"})
53 @HtmlUnitNYI(FF = {"body", "active: body", "onload", "active: body"},
54 FF_ESR = {"body", "active: body", "onload", "active: body"})
55
56 public void bodyLoad() throws Exception {
57 final String html = DOCTYPE_HTML
58 + "<html>\n"
59 + " <head>\n"
60 + " <script>\n"
61 + logger()
62 + " function test() {\n"
63 + " log('onload');\n"
64 + " }\n"
65 + " </script>\n"
66 + " </head>\n"
67 + " <body id='body' onload='test()' " + logEvents("") + ">\n"
68 + " <script>\n"
69 + " log('body');"
70 + " </script>\n"
71 + " </body>\n"
72 + "</html>\n";
73
74 final WebDriver driver = loadPage2(html);
75 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
76 }
77
78
79
80
81 @Test
82 @Alerts(DEFAULT = {"onfocus:[object Window]", "active: focusId",
83 "before", "active: focusId", "after", "active: focusId"},
84 CHROME = {"before", "active: focusId", "after", "active: focusId"},
85 EDGE = {"before", "active: focusId", "after", "active: focusId"})
86 @HtmlUnitNYI(FF = {"before", "active: focusId", "after", "active: focusId"},
87 FF_ESR = {"before", "active: focusId", "after", "active: focusId"})
88
89 public void body() throws Exception {
90 final String html = DOCTYPE_HTML
91 + "<html>\n"
92 + " <head>\n"
93 + " <script>\n"
94 + logger()
95 + " function test() {\n"
96 + " log('before');\n"
97 + " document.getElementById('focusId').focus();\n"
98 + " document.getElementById('focusId').focus();\n"
99 + " document.getElementById('focusId').blur();\n"
100 + " document.getElementById('focusId').blur();\n"
101 + " log('after');\n"
102 + " }\n"
103 + " </script>\n"
104 + " </head>\n"
105 + " <body id='focusId' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
106 + " </body>\n"
107 + "</html>\n";
108
109 final WebDriver driver = loadPage2(html);
110 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
111 }
112
113
114
115
116 @Test
117 @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
118 "before", "active: body", "after", "active: body"},
119 CHROME = {"before", "active: body", "after", "active: body"},
120 EDGE = {"before", "active: body", "after", "active: body"})
121 @HtmlUnitNYI(FF = {"before", "active: body", "after", "active: body"},
122 FF_ESR = {"before", "active: body", "after", "active: body"})
123
124 public void bodySwitchFromBodyToNotFocusable() throws Exception {
125 final String html = DOCTYPE_HTML
126 + "<html>\n"
127 + " <head>\n"
128 + " <script>\n"
129 + logger()
130 + " function test() {\n"
131 + " log('before');\n"
132 + " document.getElementById('focusId').focus();\n"
133 + " document.getElementById('focusId').blur();\n"
134 + " log('after');\n"
135 + " }\n"
136 + " </script>\n"
137 + " </head>\n"
138 + " <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
139 + " <div id='focusId' " + logEvents("F") + ">div</div>\n"
140 + " </body>\n"
141 + "</html>\n";
142
143 final WebDriver driver = loadPage2(html);
144 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
145 }
146
147
148
149
150 @Test
151 @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
152 "before", "active: body",
153 "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
154 "active: focusId", "onfocusin:focusId", "active: focusId",
155 "onblurF:focusId", "active: body", "onfocusoutF:focusId",
156 "active: body", "onfocusout:focusId", "active: body",
157 "after", "active: body"},
158 CHROME = {"before", "active: body",
159 "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
160 "active: focusId", "onfocusin:focusId", "active: focusId",
161 "onblurF:focusId", "active: body", "onfocusoutF:focusId",
162 "active: body", "onfocusout:focusId", "active: body",
163 "after", "active: body"},
164 EDGE = {"before", "active: body",
165 "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
166 "active: focusId", "onfocusin:focusId", "active: focusId",
167 "onblurF:focusId", "active: body", "onfocusoutF:focusId",
168 "active: body", "onfocusout:focusId", "active: body",
169 "after", "active: body"})
170 @HtmlUnitNYI(FF = {"before", "active: body",
171 "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
172 "active: focusId", "onfocusin:focusId", "active: focusId",
173 "onblurF:focusId", "active: body", "onfocusoutF:focusId",
174 "active: body", "onfocusout:focusId", "active: body",
175 "after", "active: body"},
176 FF_ESR = {"before", "active: body",
177 "onfocusF:focusId", "active: focusId", "onfocusinF:focusId",
178 "active: focusId", "onfocusin:focusId", "active: focusId",
179 "onblurF:focusId", "active: body", "onfocusoutF:focusId",
180 "active: body", "onfocusout:focusId", "active: body",
181 "after", "active: body"})
182
183 public void bodySwitchFromBodyToFocusable() throws Exception {
184 final String html = DOCTYPE_HTML
185 + "<html>\n"
186 + " <head>\n"
187 + " <script>\n"
188 + logger()
189 + " function test() {\n"
190 + " log('before');\n"
191 + " document.getElementById('focusId').focus();\n"
192 + " document.getElementById('focusId').blur();\n"
193 + " log('after');\n"
194 + " }\n"
195 + " </script>\n"
196 + " </head>\n"
197 + " <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
198 + " <input type='text' id='focusId' " + logEvents("F") + ">\n"
199 + " </body>\n"
200 + "</html>\n";
201
202 final WebDriver driver = loadPage2(html);
203 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
204 }
205
206
207
208
209 @Test
210 @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body",
211 "before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
212 CHROME = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
213 EDGE = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"})
214 @HtmlUnitNYI(FF = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"},
215 FF_ESR = {"before", "active: body", "onfocusin:focusId1", "active: focusId1", "after", "active: focusId1"})
216
217 public void bodySwitchFromFocusableToNotFocusable() throws Exception {
218 testBodySwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
219 + "<div id='focusId2'>div</div>");
220 }
221
222
223
224
225 @Test
226 @Alerts(DEFAULT = {"onfocus:[object Window]", "active: body", "before", "active: body",
227 "onfocusin:focusId1", "active: focusId1",
228 "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
229 "after", "active: focusId2"},
230 CHROME = {"before", "active: body",
231 "onfocusin:focusId1", "active: focusId1",
232 "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
233 "after", "active: focusId2"},
234 EDGE = {"before", "active: body",
235 "onfocusin:focusId1", "active: focusId1",
236 "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
237 "after", "active: focusId2"})
238 @HtmlUnitNYI(FF = {"before", "active: body",
239 "onfocusin:focusId1", "active: focusId1",
240 "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
241 "after", "active: focusId2"},
242 FF_ESR = {"before", "active: body",
243 "onfocusin:focusId1", "active: focusId1",
244 "onfocusout:focusId1", "active: body", "onfocusin:focusId2", "active: focusId2",
245 "after", "active: focusId2"})
246
247 public void bodySwitchFromFocusableToFocusable() throws Exception {
248 testBodySwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
249 + "<input type='text' id='focusId2'>");
250 }
251
252 private void testBodySwitchWithCallFocusAndBlur(final String snippet) throws Exception {
253 final String html = DOCTYPE_HTML
254 + "<html>\n"
255 + " <head>\n"
256 + " <script>\n"
257 + logger()
258 + " function test() {\n"
259 + " log('before');\n"
260 + " document.getElementById('focusId1').focus();\n"
261 + " document.getElementById('focusId2').focus();\n"
262 + " log('after');\n"
263 + " }\n"
264 + " </script>\n"
265 + " </head>\n"
266 + " <body id='body' onload='setTimeout(test, 10)' " + logEvents("") + ">\n"
267 + snippet
268 + " </body>\n"
269 + "</html>\n";
270
271 final WebDriver driver = loadPage2(html);
272 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
273 }
274
275
276
277
278 @Test
279 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
280 public void notFocusable() throws Exception {
281 testWithCallFocusAndBlur("<div id='focusId'>div</div>");
282 }
283
284
285
286
287 @Test
288 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
289 public void notFocusableWithTabIndexEmpty() throws Exception {
290 testWithCallFocusAndBlur("<div tabindex='' id='focusId'>div</div>");
291 }
292
293
294
295
296 @Test
297 @Alerts({"before", "active: body",
298 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
299 "between", "active: focusId",
300 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
301 "after", "active: body"})
302 public void notFocusableWithTabIndexNegative() throws Exception {
303 testWithCallFocusAndBlur("<div tabindex='-1' id='focusId'>div</div>");
304 }
305
306
307
308
309 @Test
310 @Alerts({"before", "active: body",
311 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
312 "between", "active: focusId",
313 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
314 "after", "active: body"})
315 public void notFocusableWithTabIndexZero() throws Exception {
316 testWithCallFocusAndBlur("<div tabindex='0' id='focusId'>div</div>");
317 }
318
319
320
321
322 @Test
323 @Alerts({"before", "active: body",
324 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
325 "between", "active: focusId",
326 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
327 "after", "active: body"})
328 public void notFocusableWithTabIndexPositive() throws Exception {
329 testWithCallFocusAndBlur("<div tabindex='1' id='focusId'>div</div>");
330 }
331
332
333
334
335 @Test
336 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
337 public void notFocusableWithTabIndexNotDisplayed() throws Exception {
338 testWithCallFocusAndBlur("<div tabindex='0' style='display: none;' id='focusId'>div</div>");
339 }
340
341
342
343
344 @Test
345 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
346 public void notFocusableWithTabIndexNotVisible() throws Exception {
347 testWithCallFocusAndBlur("<div tabindex='0' style='visibility: hidden;' id='focusId'>div</div>");
348 }
349
350
351
352
353 @Test
354 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
355 public void notFocusableWithTabIndexHidden() throws Exception {
356 testWithCallFocusAndBlur("<div tabindex='0' hidden id='focusId'>div</div>");
357 }
358
359
360
361
362 @Test
363 @Alerts({"before", "active: body",
364 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
365 "between", "active: focusId",
366 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
367 "after", "active: body"})
368 public void anchor() throws Exception {
369 testWithCallFocusAndBlur("<a href='#' id='focusId'>link</a>");
370 }
371
372
373
374
375 @Test
376 @Alerts({"before", "active: body",
377 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
378 "between", "active: focusId",
379 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
380 "after", "active: body"})
381 public void anchorWithEmptyHref() throws Exception {
382 testWithCallFocusAndBlur("<a href='' id='focusId'>link</a>");
383 }
384
385
386
387
388 @Test
389 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
390 public void anchorWithoutHref() throws Exception {
391 testWithCallFocusAndBlur("<a id='focusId'>link</a>");
392 }
393
394
395
396
397 @Test
398 @Alerts({"before", "active: body",
399 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
400 "between", "active: focusId",
401 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
402 "after", "active: body"})
403 public void area() throws Exception {
404 testWithCallFocusAndBlur("<map name='dot'><area shape='rect' coords='0,0,5,5' href='#' id='focusId' /></map>"
405 + "<img usemap='#dot'"
406 + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
407 + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>");
408 }
409
410
411
412
413 @Test
414 @Alerts({"before", "active: body",
415 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
416 "between", "active: focusId",
417 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
418 "after", "active: body"})
419 public void areaWithEmptyHref() throws Exception {
420 testWithCallFocusAndBlur("<img usemap='#dot'"
421 + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
422 + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
423 + "<map name='dot'><area shape='rect' coords='0,0,1,1' href='' id='focusId' /></map>");
424 }
425
426
427
428
429 @Test
430 @Alerts(DEFAULT = {"before", "active: body", "between", "active: body", "after", "active: body"},
431 FF = {"before", "active: body",
432 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
433 "between", "active: focusId",
434 "onblur:focusId", "active: body", "onfocusout:focusId",
435 "active: body", "after", "active: body"},
436 FF_ESR = {"before", "active: body",
437 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
438 "between", "active: focusId",
439 "onblur:focusId", "active: body", "onfocusout:focusId",
440 "active: body", "after", "active: body"})
441 public void areaWithoutHref() throws Exception {
442 testWithCallFocusAndBlur("<img usemap='#dot'"
443 + " src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAA"
444 + "HElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>\n"
445 + "<map name='dot'><area shape='rect' coords='0,0,1,1' id='focusId' /></map>");
446 }
447
448
449
450
451 @Test
452 @Alerts({"before", "active: body",
453 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
454 "between", "active: focusId",
455 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
456 "after", "active: body"})
457 public void button() throws Exception {
458 testWithCallFocusAndBlur("<button id='focusId'>button</button>");
459 }
460
461
462
463
464 @Test
465 @Alerts({"before", "active: body",
466 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
467 "between", "active: focusId",
468 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
469 "after", "active: body"})
470 public void input() throws Exception {
471 testWithCallFocusAndBlur("<input type='text' id='focusId'>");
472 }
473
474
475
476
477 @Test
478 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
479 public void inputHidden() throws Exception {
480 testWithCallFocusAndBlur("<input type='hidden' id='focusId'>");
481 }
482
483
484
485
486 @Test
487 @Alerts({"before", "active: body",
488 "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
489 "between", "active: textId", "after", "active: textId"})
490 public void labelFor() throws Exception {
491 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label><input type='text' id='textId' "
492 + logEvents("T") + ">");
493 }
494
495
496
497
498 @Test
499 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
500 public void labelForDisabled() throws Exception {
501 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
502 + "<input type='text' disabled id='textId' " + logEvents("T") + ">");
503 }
504
505
506
507
508 @Test
509 @Alerts({"before", "active: body",
510 "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
511 "between", "active: textId", "after", "active: textId"})
512 public void labelForReadonly() throws Exception {
513 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
514 + "<input type='text' readonly id='textId' " + logEvents("T") + ">");
515 }
516
517
518
519
520 @Test
521 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
522 public void labelForNotDisplayed() throws Exception {
523 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label"
524 + "</label><input type='text' style='display: none;' id='textId' " + logEvents("T") + ">");
525 }
526
527
528
529
530 @Test
531 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
532 public void labelForNotVisible() throws Exception {
533 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
534 + "<input type='text' style='visibility: hidden;' id='textId' " + logEvents("T") + ">");
535 }
536
537
538
539
540 @Test
541 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
542 public void labelForHidden() throws Exception {
543 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label</label>"
544 + "<input type='text' hidden id='textId' " + logEvents("T") + ">");
545 }
546
547
548
549
550 @Test
551 @Alerts({"before", "active: body",
552 "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
553 "between", "active: textId", "after", "active: textId"})
554 public void labelNotDisplayedFor() throws Exception {
555 testWithCallFocusAndBlur("<label for='textId' style='display: none;' id='focusId'>label</label>"
556 + "<input type='text' id='textId' " + logEvents("T") + ">");
557 }
558
559
560
561
562 @Test
563 @Alerts({"before", "active: body",
564 "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
565 "between", "active: textId", "after", "active: textId"})
566 public void labelNotVisibleFor() throws Exception {
567 testWithCallFocusAndBlur("<label for='textId' style='visibility: hidden;' id='focusId'>label</label>"
568 + "<input type='text' id='textId' " + logEvents("T") + ">");
569 }
570
571
572
573
574 @Test
575 @Alerts({"before", "active: body",
576 "onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
577 "between", "active: textId", "after", "active: textId"})
578 public void labelHiddenFor() throws Exception {
579 testWithCallFocusAndBlur("<label for='textId' hidden id='focusId'>label</label>"
580 + "<input type='text' id='textId' " + logEvents("T") + ">");
581 }
582
583
584
585
586 @Test
587 @Alerts({"before", "active: body",
588 "onfocusT:textId", "active: textId", "onfocusinT:textId",
589 "active: textId", "onfocusin:textId", "active: textId",
590 "between", "active: textId", "after", "active: textId"})
591 public void labelNested() throws Exception {
592 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' id='textId' "
593 + logEvents("T") + "></label>");
594 }
595
596
597
598
599 @Test
600 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
601 public void labelNestedDisabled() throws Exception {
602 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
603 + "<input type='text' disabled id='textId' " + logEvents("T") + "></label>");
604 }
605
606
607
608
609 @Test
610 @Alerts({"before", "active: body",
611 "onfocusT:textId", "active: textId", "onfocusinT:textId",
612 "active: textId", "onfocusin:textId", "active: textId",
613 "between", "active: textId", "after", "active: textId"})
614 public void labelNestedReadonly() throws Exception {
615 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' readonly id='textId' "
616 + logEvents("T") + "></label>");
617 }
618
619
620
621
622 @Test
623 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
624 public void labelNestedNotDisplayed() throws Exception {
625 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
626 + "<input type='text' style='display: none;' id='textId' " + logEvents("T") + "></label>");
627 }
628
629
630
631
632 @Test
633 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
634 public void labelNestedNotVisible() throws Exception {
635 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label "
636 + "<input type='text' style='display: none;' id='textId' "
637 + logEvents("T") + "></label>");
638 }
639
640
641
642
643 @Test
644 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
645 public void labelNestedHidden() throws Exception {
646 testWithCallFocusAndBlur("<label for='textId' id='focusId'>label <input type='text' hidden id='textId' "
647 + logEvents("T") + "></label>");
648 }
649
650
651
652
653 @Test
654 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
655 public void labelNotDisplayedNested() throws Exception {
656 testWithCallFocusAndBlur("<label for='textId' style='display: none;' id='focusId'>label "
657 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
658 }
659
660
661
662
663 @Test
664 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
665 public void labelNotVisibleNested() throws Exception {
666 testWithCallFocusAndBlur("<label for='textId' style='visibility: hidden;' id='focusId'>label "
667 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
668 }
669
670
671
672
673 @Test
674 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
675 public void labelHiddenNested() throws Exception {
676 testWithCallFocusAndBlur("<label for='textId' hidden id='focusId'>label "
677 + "<input type='text' id='textId' " + logEvents("T") + "></label>");
678 }
679
680
681
682
683 @Test
684 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
685 public void optionGroup() throws Exception {
686 testWithCallFocusAndBlur("<select><optgroup label='group' id='focusId'><option>1</option></optgroup></select>");
687 }
688
689
690
691
692 @Test
693 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
694 public void option() throws Exception {
695 testWithCallFocusAndBlur("<select><option id='focusId'>1</option></select>");
696 }
697
698
699
700
701 @Test
702 @Alerts({"before", "active: body",
703 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
704 "between", "active: focusId",
705 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
706 "after", "active: body"})
707 public void select() throws Exception {
708 testWithCallFocusAndBlur("<select id='focusId'><option>1</option></select>");
709 }
710
711
712
713
714 @Test
715 @Alerts({"before", "active: body",
716 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
717 "between", "active: focusId",
718 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
719 "after", "active: body"})
720 public void textArea() throws Exception {
721 testWithCallFocusAndBlur("<textarea id='focusId'></textarea>");
722 }
723
724
725
726
727 @Test
728 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
729 public void focusableDisabled() throws Exception {
730 testWithCallFocusAndBlur("<input type='text' disabled id='focusId'>");
731 }
732
733
734
735
736 @Test
737 @Alerts({"before", "active: body",
738 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
739 "between", "active: focusId",
740 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
741 "after", "active: body"})
742 public void focusableReadonly() throws Exception {
743 testWithCallFocusAndBlur("<input type='text' readonly id='focusId'>");
744 }
745
746
747
748
749 @Test
750 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
751 public void focusableNotDisplayed() throws Exception {
752 testWithCallFocusAndBlur("<input type='text' style='display: none;' id='focusId'>");
753 }
754
755
756
757
758 @Test
759 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
760 public void focusableNotVisible() throws Exception {
761 testWithCallFocusAndBlur("<input type='text' style='visibility: hidden;' id='focusId'>");
762 }
763
764
765
766
767 @Test
768 @Alerts({"before", "active: body", "between", "active: body", "after", "active: body"})
769 public void focusableHidden() throws Exception {
770 testWithCallFocusAndBlur("<input type='text' hidden id='focusId'>");
771 }
772
773 private void testWithCallFocusAndBlur(String snippet) throws Exception {
774 snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
775
776 final String html = DOCTYPE_HTML
777 + "<html>\n"
778 + " <head>\n"
779 + " <script>\n"
780 + logger()
781 + " function test() {\n"
782 + " log('before');\n"
783 + " document.getElementById('focusId').focus();\n"
784 + " document.getElementById('focusId').focus();\n"
785 + " log('between');\n"
786 + " document.getElementById('focusId').blur();\n"
787 + " document.getElementById('focusId').blur();\n"
788 + " log('after');\n"
789 + " }\n"
790 + " </script>\n"
791 + " </head>\n"
792 + " <body id='body' onload='setTimeout(test, 10)'>\n"
793 + snippet
794 + " </body>\n"
795 + "</html>\n";
796
797 final WebDriver driver = loadPage2(html);
798 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
799 }
800
801
802
803
804 @Test
805 @Alerts({"before", "active: body",
806 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
807 "after", "active: focusId1"})
808 public void switchFromFocusableToNotFocusable() throws Exception {
809 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
810 + "<div id='focusId2'>div</div>");
811 }
812
813
814
815
816 @Test
817 @Alerts({"before", "active: body",
818 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
819 "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
820 "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2",
821 "after", "active: focusId2"})
822 public void switchFromFocusableToFocusable() throws Exception {
823 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
824 + "<input type='text' id='focusId2'>");
825 }
826
827
828
829
830 @Test
831 @Alerts({"before", "active: body",
832 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
833 "after", "active: focusId1"})
834 public void switchFromFocusableToFocusableDisabled() throws Exception {
835 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
836 + "<input type='text' disabled id='focusId2'>");
837 }
838
839
840
841
842 @Test
843 @Alerts({"before", "active: body",
844 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
845 "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
846 "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2",
847 "after", "active: focusId2"})
848 public void switchFromFocusableToFocusableReadonly() throws Exception {
849 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
850 + "<input type='text' readonly id='focusId2'>");
851 }
852
853
854
855
856 @Test
857 @Alerts({"before", "active: body",
858 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
859 "after", "active: focusId1"})
860 public void switchFromFocusableToFocusableNotDisplayed() throws Exception {
861 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
862 + "<input type='text' style='display: none;' id='focusId2'>");
863 }
864
865
866
867
868 @Test
869 @Alerts({"before", "active: body",
870 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
871 "after", "active: focusId1"})
872 public void switchFromFocusableToFocusableNotVisible() throws Exception {
873 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
874 + "<input type='text' style='visibility: hidden;' id='focusId2'>");
875 }
876
877
878
879
880 @Test
881 @Alerts({"before", "active: body",
882 "onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
883 "after", "active: focusId1"})
884 public void switchFromFocusableToFocusableHidden() throws Exception {
885 testSwitchWithCallFocusAndBlur("<input type='text' id='focusId1'>\n"
886 + "<input type='text' hidden id='focusId2'>");
887 }
888
889 private void testSwitchWithCallFocusAndBlur(String snippet) throws Exception {
890 snippet = snippet.replaceFirst("id='focusId1'( /)?>", "id='focusId1' " + logEvents("1") + "$1>");
891 snippet = snippet.replaceFirst("id='focusId2'( /)?>", "id='focusId2' " + logEvents("2") + "$1>");
892
893 final String html = DOCTYPE_HTML
894 + "<html>\n"
895 + " <head>\n"
896 + " <script>\n"
897 + logger()
898 + " function test() {\n"
899 + " log('before');\n"
900 + " document.getElementById('focusId1').focus();\n"
901 + " document.getElementById('focusId2').focus();\n"
902 + " log('after');\n"
903 + " }\n"
904 + " </script>\n"
905 + " </head>\n"
906 + " <body id='body' onload='setTimeout(test, 10)'>\n"
907 + snippet
908 + " </body>\n"
909 + "</html>\n";
910
911 final WebDriver driver = loadPage2(html);
912 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
913 }
914
915
916
917
918 @Test
919 @Alerts({"before", "active: body", "after", "active: body"})
920 public void jsClickOnNotFocusable() throws Exception {
921 testWithCallClick("<div id='focusId'>div</div>");
922 }
923
924
925
926
927 @Test
928 @Alerts({"before", "active: body", "after", "active: body"})
929 @HtmlUnitNYI(CHROME = {"before", "active: body",
930 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
931 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
932 "after", "active: body"},
933 EDGE = {"before", "active: body",
934 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
935 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
936 "after", "active: body"},
937 FF = {"before", "active: body",
938 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
939 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
940 "after", "active: body"},
941 FF_ESR = {"before", "active: body",
942 "onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
943 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body",
944 "after", "active: body"})
945
946 public void jsClickOnNotFocusableWithTabIndex() throws Exception {
947 testWithCallClick("<div tabindex='0' id='focusId'>div</div>");
948 }
949
950
951
952
953 @Test
954 @Alerts({"before", "active: body", "after", "active: body"})
955 public void jsClickOnFocusable() throws Exception {
956 testWithCallClick("<input type='text' id='focusId'>");
957 }
958
959 private void testWithCallClick(String snippet) throws Exception {
960 snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
961
962 final String html = DOCTYPE_HTML
963 + "<html>\n"
964 + " <head>\n"
965 + " <script>\n"
966 + logger()
967 + " function test() {\n"
968 + " log('before');\n"
969 + " document.getElementById('focusId').click();\n"
970 + " document.getElementById('focusId').click();\n"
971 + " document.getElementById('otherId').click();\n"
972 + " log('after');\n"
973 + " }\n"
974 + " </script>\n"
975 + " </head>\n"
976 + " <body id='body' onload='setTimeout(test, 10)'>\n"
977 + snippet
978 + " <div id='otherId'>div</div>\n"
979 + " </body>\n"
980 + "</html>\n";
981
982 final WebDriver driver = loadPage2(html);
983 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
984 }
985
986
987
988
989 @Test
990 public void clickOnNotFocusable() throws Exception {
991 testWithClick("<div id='focusId'>div</div>");
992 }
993
994
995
996
997 @Test
998 @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
999 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1000 public void clickOnNotFocusableWithTabIndex() throws Exception {
1001 testWithClick("<div tabindex='0' id='focusId'>div</div>");
1002 }
1003
1004
1005
1006
1007 @Test
1008 @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
1009 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1010 public void clickOnFocusable() throws Exception {
1011 testWithClick("<input type='text' id='focusId'>");
1012 }
1013
1014
1015
1016
1017 @Test
1018 public void clickOnFocusableDisabled() throws Exception {
1019 testWithClick("<input type='text' disabled id='focusId'>");
1020 }
1021
1022
1023
1024
1025 @Test
1026 @Alerts({"onfocus:focusId", "active: focusId", "onfocusin:focusId", "active: focusId",
1027 "onblur:focusId", "active: body", "onfocusout:focusId", "active: body"})
1028 public void clickOnFocusableReadonly() throws Exception {
1029 testWithClick("<input type='text' readonly id='focusId'>");
1030 }
1031
1032
1033
1034
1035 @Test
1036 @Alerts({"onfocusT:textId", "active: textId", "onfocusinT:textId", "active: textId",
1037 "onblurT:textId", "active: body", "onfocusoutT:textId", "active: body"})
1038 public void clickOnLabelFor() throws Exception {
1039 testWithClick("<label for='textId' id='focusId'>label</label><input type='text' id='textId' "
1040 + logEvents("T") + ">");
1041 }
1042
1043
1044
1045
1046 @Test
1047 @Alerts({"onfocusT:textId", "active: textId", "onfocusinT:textId",
1048 "active: textId", "onfocusin:textId", "active: textId",
1049 "onblurT:textId", "active: body", "onfocusoutT:textId",
1050 "active: body", "onfocusout:textId", "active: body"})
1051 public void clickOnLabelNested() throws Exception {
1052 testWithClick("<label for='textId' id='focusId'>label <input type='text' id='textId' "
1053 + logEvents("T") + "></label>");
1054 }
1055
1056 private void testWithClick(String snippet) throws Exception {
1057 snippet = snippet.replaceFirst("id='focusId'( /)?>", "id='focusId' " + logEvents("") + "$1>");
1058
1059 final String html = DOCTYPE_HTML
1060 + "<html>\n"
1061 + " <head>\n"
1062 + " <script>\n"
1063 + logger()
1064 + " </script>\n"
1065 + " </head>\n"
1066 + " <body id='body'>\n"
1067 + snippet
1068 + " <div id='otherId'>div</div>\n"
1069 + " </body>\n"
1070 + "</html>\n";
1071
1072 final WebDriver driver = loadPage2(html);
1073
1074 driver.findElement(By.id("focusId")).click();
1075 driver.findElement(By.id("otherId")).click();
1076
1077 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
1078 }
1079
1080
1081
1082
1083 @Test
1084 @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1085 "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
1086 "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2"})
1087 public void clickFromFocusableToFocusable() throws Exception {
1088 testSwitchWithClick("<input type='text' id='focusId1'>\n"
1089 + "<input type='text' id='focusId2'>");
1090 }
1091
1092
1093
1094
1095 @Test
1096 @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1097 "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body"})
1098 @HtmlUnitNYI(CHROME = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1099 EDGE = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1100 FF = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"},
1101 FF_ESR = {"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1"})
1102 public void clickFromFocusableToFocusableDisabled() throws Exception {
1103 testSwitchWithClick("<input type='text' id='focusId1'>\n"
1104 + "<input type='text' disabled id='focusId2'>");
1105 }
1106
1107
1108
1109
1110 @Test
1111 @Alerts({"onfocus1:focusId1", "active: focusId1", "onfocusin1:focusId1", "active: focusId1",
1112 "onblur1:focusId1", "active: body", "onfocusout1:focusId1", "active: body",
1113 "onfocus2:focusId2", "active: focusId2", "onfocusin2:focusId2", "active: focusId2"})
1114 public void clickFromFocusableToFocusableReadonly() throws Exception {
1115 testSwitchWithClick("<input type='text' id='focusId1'>\n"
1116 + "<input type='text' readonly id='focusId2'>");
1117 }
1118
1119 private void testSwitchWithClick(String snippet) throws Exception {
1120 snippet = snippet.replaceFirst("id='focusId1'( /)?>", "id='focusId1' " + logEvents("1") + "$1>");
1121 snippet = snippet.replaceFirst("id='focusId2'( /)?>", "id='focusId2' " + logEvents("2") + "$1>");
1122
1123 final String html = DOCTYPE_HTML
1124 + "<html>\n"
1125 + " <head>\n"
1126 + " <script>\n"
1127 + logger()
1128 + " </script>\n"
1129 + " </head>\n"
1130 + " <body id='body'>\n"
1131 + snippet
1132 + " </body>\n"
1133 + "</html>\n";
1134
1135 final WebDriver driver = loadPage2(html);
1136
1137 driver.findElement(By.id("focusId1")).click();
1138 driver.findElement(By.id("focusId2")).click();
1139
1140 assertTitle(driver, String.join(";", getExpectedAlerts()) + (getExpectedAlerts().length > 0 ? ";" : ""));
1141 }
1142
1143 private static String logger() {
1144 return " function log(x, e) {\n"
1145 + " document.title += x + (e ? ':' + (e.target.id ? e.target.id : e.target) : '') + ';';\n"
1146 + " document.title += 'active: ' "
1147 + "+ (document.activeElement ? document.activeElement.id : 'null') + ';';\n"
1148 + " }\n";
1149 }
1150
1151 private static String logEvents(final String aSuffix) {
1152 return "onblur=\"log('onblur" + aSuffix + "', event)\" "
1153 + "onfocusin=\"log('onfocusin" + aSuffix + "', event)\" "
1154 + "onfocusout=\"log('onfocusout" + aSuffix + "', event)\" "
1155 + "onfocus=\"log('onfocus" + aSuffix + "', event)\"";
1156 }
1157 }