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