View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.css;
16  
17  import java.net.URL;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.apache.commons.lang3.StringUtils;
22  import org.htmlunit.MockWebConnection;
23  import org.htmlunit.WebClient;
24  import org.htmlunit.WebDriverTestCase;
25  import org.htmlunit.junit.BrowserRunner;
26  import org.htmlunit.junit.annotation.Alerts;
27  import org.htmlunit.junit.annotation.HtmlUnitNYI;
28  import org.htmlunit.util.MimeType;
29  import org.htmlunit.util.NameValuePair;
30  import org.junit.Test;
31  import org.junit.runner.RunWith;
32  import org.openqa.selenium.By;
33  import org.openqa.selenium.WebDriver;
34  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
35  
36  /**
37   * Unit tests for {@link CSSStyleSheet}.
38   *
39   * @author Marc Guillemot
40   * @author Ahmed Ashour
41   * @author Frank Danek
42   * @author Ronald Brill
43   * @author Carsten Steul
44   */
45  @RunWith(BrowserRunner.class)
46  public class CSSStyleSheetTest extends WebDriverTestCase {
47  
48      /**
49       * @throws Exception on test failure
50       */
51      @Test
52      @Alerts({"[object CSSStyleSheet]", "[object HTMLStyleElement]", "true", "undefined", "false"})
53      public void owningNodeOwningElement() throws Exception {
54          final String html = DOCTYPE_HTML
55                  + "<html><head>\n"
56                  + "<script>\n"
57                  + LOG_TITLE_FUNCTION
58                  + "function test() {\n"
59                  + "  var myStyle = document.getElementById('myStyle');\n"
60                  + "  var stylesheet = document.styleSheets[0];\n"
61                  + "  log(stylesheet);\n"
62                  + "  log(stylesheet.ownerNode);\n"
63                  + "  log(stylesheet.ownerNode == myStyle);\n"
64                  + "  log(stylesheet.owningElement);\n"
65                  + "  log(stylesheet.owningElement == myStyle);\n"
66                  + "}\n"
67                  + "</script>\n"
68                  + "<style id='myStyle' type='text/css'></style>\n"
69                  + "</head><body onload='test()'>\n"
70                  + "</body></html>";
71          loadPageVerifyTitle2(html);
72      }
73  
74      /**
75       * @throws Exception on test failure
76       */
77      @Test
78      @Alerts(DEFAULT = {"4", "0", "1", "2", "3", "length", "item"},
79              FF = {"4", "0", "1", "2", "3", "item", "length"},
80              FF_ESR = {"4", "0", "1", "2", "3", "item", "length"})
81      public void rules() throws Exception {
82          final String html = DOCTYPE_HTML
83                  + "<html><head>\n"
84                  + "<style>\n"
85                  + "  BODY { background-color: white; color: black; }\n"
86                  + "  H1 { font: 8pt Arial bold; }\n"
87                  + "  P  { font: 10pt Arial; text-indent: 0.5in; }\n"
88                  + "  A  { text-decoration: none; color: blue; }\n"
89                  + "</style>\n"
90                  + "<script>\n"
91                  + LOG_TITLE_FUNCTION
92                  + "  function test() {\n"
93                  + "    var rules;\n"
94                  + "    if (document.styleSheets[0].cssRules)\n"
95                  + "      rules = document.styleSheets[0].cssRules;\n"
96                  + "    else\n"
97                  + "      rules = document.styleSheets[0].rules;\n"
98                  + "    log(rules.length);\n"
99                  + "    for (var i in rules)\n"
100                 + "      log(i);\n"
101                 + "  }\n"
102                 + "</script>\n"
103                 + "</head><body onload='test()'>\n"
104                 + "</body></html>";
105         loadPageVerifyTitle2(html);
106     }
107 
108     /**
109      * Test for bug #680 (missing href attribute).
110      * @throws Exception if an error occurs
111      */
112     @Test
113     @Alerts({"4", "§§URL§§style2.css", "§§URL§§style4.css", "null", "null"})
114     public void href() throws Exception {
115         final String html = DOCTYPE_HTML
116             + "<html>\n"
117             + "  <head>\n"
118             + "    <link href='" + URL_FIRST + "style1.css' type='text/css'></link>\n"
119             + "    <link href='" + URL_FIRST + "style2.css' rel='stylesheet'></link>\n"
120             + "    <link href='" + URL_FIRST + "style3.css'></link>\n"
121             + "    <link href='style4.css' rel='stylesheet'></link>\n"
122             + "    <style>div.x { color: red; }</style>\n"
123             + "  </head>\n"
124             + "  <body>\n"
125             + "    <style>div.y { color: green; }</style>\n"
126             + "    <script>\n"
127             + LOG_TITLE_FUNCTION
128             + "      log(document.styleSheets.length);\n"
129             + "      for (i = 0; i < document.styleSheets.length; i++) {\n"
130             + "        log(document.styleSheets[i].href);\n"
131             + "      }\n"
132             + "    </script>\n" + "  </body>\n"
133             + "</html>";
134 
135         final MockWebConnection conn = getMockWebConnection();
136         conn.setResponse(new URL(URL_FIRST, "style1.css"), "", MimeType.TEXT_CSS);
137         conn.setResponse(new URL(URL_FIRST, "style2.css"), "", MimeType.TEXT_CSS);
138         conn.setResponse(new URL(URL_FIRST, "style3.css"), "", MimeType.TEXT_CSS);
139         conn.setResponse(new URL(URL_FIRST, "style4.css"), "", MimeType.TEXT_CSS);
140 
141         expandExpectedAlertsVariables(URL_FIRST);
142         loadPageVerifyTitle2(html);
143     }
144 
145     /**
146      * @throws Exception if an error occurs
147      */
148     @Test
149     @Alerts({"8", "§§URL§§style1.css 1", "§§URL§§style2.css 0",
150              "§§URL§§style3.css 0", "§§URL§§style4.css 1",
151              "§§URL§§style5.css 1", "§§URL§§style6.css 0",
152              "§§URL§§style7.css 0", "§§URL§§style8.css 1"})
153     public void hrefWrongContentType() throws Exception {
154         final String html = DOCTYPE_HTML
155             + "<html>\n"
156             + "  <head>\n"
157             + "    <link href='" + URL_FIRST + "style1.css' rel='stylesheet' type='text/css'></link>\n"
158             + "    <link href='" + URL_FIRST + "style2.css' rel='stylesheet' type='text/css'></link>\n"
159             + "    <link href='" + URL_FIRST + "style3.css' rel='stylesheet' type='text/css'></link>\n"
160             + "    <link href='" + URL_FIRST + "style4.css' rel='stylesheet' type='text/css'></link>\n"
161             + "    <link href='" + URL_FIRST + "style5.css' rel='stylesheet' ></link>\n"
162             + "    <link href='" + URL_FIRST + "style6.css' rel='stylesheet' ></link>\n"
163             + "    <link href='" + URL_FIRST + "style7.css' rel='stylesheet' ></link>\n"
164             + "    <link href='" + URL_FIRST + "style8.css' rel='stylesheet' ></link>\n"
165             + "  </head>\n" + "  <body>\n"
166             + "    <script>\n"
167             + LOG_TITLE_FUNCTION
168             + "      log(document.styleSheets.length);\n"
169             + "      for (i = 0; i < document.styleSheets.length; i++) {\n"
170             + "        var sheet = document.styleSheets[i];\n"
171             + "        log(sheet.href + ' ' + sheet.cssRules.length);\n"
172             + "      }\n"
173             + "    </script>\n" + "  </body>\n"
174             + "</html>";
175 
176         final MockWebConnection conn = getMockWebConnection();
177         conn.setResponse(new URL(URL_FIRST, "style1.css"), "div { color: red; }", MimeType.TEXT_CSS);
178         conn.setResponse(new URL(URL_FIRST, "style2.css"), "div { color: red; }", MimeType.TEXT_HTML);
179         conn.setResponse(new URL(URL_FIRST, "style3.css"), "div { color: red; }", MimeType.TEXT_PLAIN);
180         conn.setResponse(new URL(URL_FIRST, "style4.css"), "div { color: red; }", "");
181         conn.setResponse(new URL(URL_FIRST, "style5.css"), "div { color: red; }", MimeType.TEXT_CSS);
182         conn.setResponse(new URL(URL_FIRST, "style6.css"), "div { color: red; }", MimeType.TEXT_HTML);
183         conn.setResponse(new URL(URL_FIRST, "style7.css"), "div { color: red; }", MimeType.TEXT_PLAIN);
184         conn.setResponse(new URL(URL_FIRST, "style8.css"), "div { color: red; }", "");
185 
186         expandExpectedAlertsVariables(URL_FIRST);
187         loadPageVerifyTitle2(html);
188     }
189 
190     /**
191      * Minimal test for addRule / insertRule.
192      * @throws Exception if an error occurs
193      */
194     @Test
195     @Alerts({"1", "false", "-1", "div", "color: red;", "2"})
196     public void addRule() throws Exception {
197         final String html = DOCTYPE_HTML
198             + "<html>\n"
199             + "<head>\n"
200             + "<script>\n"
201             + LOG_TITLE_FUNCTION
202             + "  function doTest() {\n"
203             + "    var f = document.getElementById('myStyle');\n"
204             + "    var s = f.sheet ? f.sheet : f.styleSheet;\n"
205             + "    var rules = s.cssRules || s.rules;\n"
206             + "    log(rules.length);\n"
207             + "    log(s.addRule == undefined);\n"
208             + "    if (s.addRule) {\n"
209             + "      log(s.addRule('div', 'color: red;'));\n"
210             + "      log(rules[rules.length - 1].selectorText);\n"
211             + "      log(rules[rules.length - 1].style.cssText);\n"
212             + "    }\n"
213             + "    log(rules.length);\n"
214             + "  }\n"
215             + "</script>\n"
216             + "<style id='myStyle'>p { vertical-align:top }</style>\n"
217             + "</head>\n"
218             + "<body onload='doTest()'>\n"
219             + "</body></html>";
220 
221         loadPageVerifyTitle2(html);
222     }
223 
224     /**
225      * @throws Exception if an error occurs
226      */
227     @Test
228     @Alerts({"2", "-1", "div", "", "3"})
229     public void addRuleInvalidRule() throws Exception {
230         final String html = DOCTYPE_HTML
231                 + "<html>\n"
232                 + "<head>\n"
233                 + "<script>\n"
234                 + LOG_TITLE_FUNCTION
235                 + "  function doTest() {\n"
236                 + "    var f = document.getElementById('myStyle');\n"
237                 + "    var s = f.sheet ? f.sheet : f.styleSheet;\n"
238                 + "    var rules = s.cssRules || s.rules;\n"
239                 + "    log(rules.length);\n"
240                 + "    if (s.addRule) {\n"
241                 + "      log(s.addRule('div', 'invalid'));\n"
242                 + "      log(rules[rules.length - 1].selectorText);\n"
243                 + "      log(rules[rules.length - 1].style.cssText);\n"
244                 + "    }\n"
245                 + "    log(rules.length);\n"
246                 + "  }\n"
247                 + "  </script>\n"
248                 + "  <style id='myStyle'>p { vertical-align: top } h1 { color: blue; }</style>\n"
249                 + "</head>\n"
250                 + "<body onload='doTest()'>\n"
251                 + "</body></html>";
252 
253         loadPageVerifyTitle2(html);
254     }
255 
256     /**
257      * Test that exception handling in addRule.
258      * @throws Exception if an error occurs
259      */
260     @Test
261     @Alerts("SyntaxError/DOMException")
262     public void addInvalidRule() throws Exception {
263         final String html = DOCTYPE_HTML
264             + "<html><head>\n"
265             + "<script>\n"
266             + LOG_TITLE_FUNCTION
267             + "function doTest() {\n"
268             + "  var f = document.getElementById('myStyle');\n"
269             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
270             + "  var rules = s.cssRules || s.rules;\n"
271             + "  try {\n"
272             + "    if (s.addRule)\n"
273             + "      s.addRule('.testStyle1;', '', 0);\n"
274             + "    log('added');\n"
275             + "  } catch(e) { logEx(e); }\n"
276             + "}</script>\n"
277             + "<style id='myStyle'></style>\n"
278             + "</head><body onload='doTest()'>\n"
279             + "</body></html>";
280 
281         loadPageVerifyTitle2(html);
282     }
283 
284     /**
285      * Minimal test for insertRule.
286      * @throws Exception if an error occurs
287      */
288     @Test
289     @Alerts({"1", "false", "0", "div", "color: red;", "2"})
290     public void insertRule() throws Exception {
291         final String html = DOCTYPE_HTML
292             + "<html>\n"
293             + "<head>\n"
294             + "<script>\n"
295             + LOG_TITLE_FUNCTION
296             + "  function doTest() {\n"
297             + "    var f = document.getElementById('myStyle');\n"
298             + "    var s = f.sheet ? f.sheet : f.styleSheet;\n"
299             + "    var rules = s.cssRules || s.rules;\n"
300             + "    log(rules.length);\n"
301             + "    log(s.insertRule == undefined);\n"
302             + "    if (s.insertRule) {\n"
303             + "      log(s.insertRule('div { color: red; }', 0));\n"
304             + "      log(rules[0].selectorText);\n"
305             + "      log(rules[0].style.cssText);\n"
306             + "    }\n"
307             + "    log(rules.length);\n"
308             + "  }\n"
309             + "</script>\n"
310             + "<style id='myStyle'>p { vertical-align:top }</style>\n"
311             + "</head>\n"
312             + "<body onload='doTest()'>\n"
313             + "</body></html>";
314 
315         loadPageVerifyTitle2(html);
316     }
317 
318     /**
319      * @throws Exception if an error occurs
320      */
321     @Test
322     @Alerts({"1", "false", "0", "div", "", "2"})
323     public void insertRuleInvalidRule() throws Exception {
324         final String html = DOCTYPE_HTML
325             + "<html>\n"
326             + "<head>\n"
327             + "<script>\n"
328             + LOG_TITLE_FUNCTION
329             + "  function doTest() {\n"
330             + "    var f = document.getElementById('myStyle');\n"
331             + "    var s = f.sheet ? f.sheet : f.styleSheet;\n"
332             + "    var rules = s.cssRules || s.rules;\n"
333             + "    log(rules.length);\n"
334             + "    log(s.insertRule == undefined);\n"
335             + "    if (s.insertRule) {\n"
336             + "      log(s.insertRule('div {invalid}', 0));\n"
337             + "      log(rules[0].selectorText);\n"
338             + "      log(rules[0].style.cssText);\n"
339             + "    }\n"
340             + "    log(rules.length);\n"
341             + "  }\n"
342             + "</script>\n"
343             + "<style id='myStyle'>p { vertical-align:top }</style>\n"
344             + "</head>\n"
345             + "<body onload='doTest()'>\n"
346             + "</body></html>";
347 
348         loadPageVerifyTitle2(html);
349     }
350 
351     /**
352      * Test that exception handling in insertRule.
353      * @throws Exception if an error occurs
354      */
355     @Test
356     @Alerts("SyntaxError/DOMException")
357     public void insertInvalidRule() throws Exception {
358         final String html = DOCTYPE_HTML
359             + "<html>\n"
360             + "<head>\n"
361             + "<script>\n"
362             + LOG_TITLE_FUNCTION
363             + "function doTest() {\n"
364             + "  var f = document.getElementById('myStyle');\n"
365             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
366             + "  var rules = s.cssRules || s.rules;\n"
367             + "  try {\n"
368             + "    if (s.insertRule)\n"
369             + "      s.insertRule('.testStyle1', 0);\n"
370             + "    log('inserted');\n"
371             + "  } catch(e) { logEx(e); }\n"
372             + "}</script>\n"
373             + "<style id='myStyle'></style>\n"
374             + "</head><body onload='doTest()'>\n"
375             + "</body></html>";
376 
377         loadPageVerifyTitle2(html);
378     }
379 
380     /**
381      * Minimal test for removeRule / deleteRule.
382      * @throws Exception if an error occurs
383      */
384     @Test
385     @Alerts({"2", "false", "false", "undefined", "1", "div", "color: red;"})
386     public void removeRule_deleteRule() throws Exception {
387         final String html = DOCTYPE_HTML
388             + "<html><head><script>\n"
389             + LOG_TITLE_FUNCTION
390             + "function doTest() {\n"
391             + "  var f = document.getElementById('myStyle');\n"
392             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
393             + "  var rules = s.cssRules || s.rules;\n"
394             + "  log(rules.length);\n"
395             + "  log(s.deleteRule == undefined);\n"
396             + "  log(s.removeRule == undefined);\n"
397             + "  if (s.deleteRule)\n"
398             + "    log(s.deleteRule(0));\n"
399             + "  else\n"
400             + "    log(s.removeRule(0));\n"
401             + "  log(rules.length);\n"
402             + "  log(rules[0].selectorText);\n"
403             + "  log(rules[0].style.cssText);\n"
404             + "}</script>\n"
405             + "<style id='myStyle'>p { vertical-align:top } div { color: red; }</style>\n"
406             + "</head><body onload='doTest()'>\n"
407             + "</body></html>";
408 
409         loadPageVerifyTitle2(html);
410     }
411 
412     /**
413      * Test exception handling in deletRule / removeRule.
414      * @throws Exception if an error occurs
415      */
416     @Test
417     @Alerts("IndexSizeError/DOMException")
418     public void deleteRuleInvalidParam() throws Exception {
419         final String html = DOCTYPE_HTML
420             + "<html>\n"
421             + "<head>\n"
422             + "<script>\n"
423             + LOG_TITLE_FUNCTION
424             + "function doTest() {\n"
425             + "  var f = document.getElementById('myStyle');\n"
426             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
427             + "  var rules = s.cssRules || s.rules;\n"
428             + "  try {\n"
429             + "    if (s.deleteRule)\n"
430             + "      s.deleteRule(19);\n"
431             + "    else\n"
432             + "      s.removeRule(19);\n"
433             + "    log('deleted');\n"
434             + "  } catch(e) { logEx(e); }\n"
435             + "}</script>\n"
436             + "<style id='myStyle'></style>\n"
437             + "</head><body onload='doTest()'>\n"
438             + "</body></html>";
439 
440         loadPageVerifyTitle2(html);
441     }
442 
443     /**
444      * @throws Exception if an error occurs
445      */
446     @Test
447     @Alerts({"2", "1", "div", "color: red;"})
448     public void deleteRuleIgnored() throws Exception {
449         final String html = DOCTYPE_HTML
450             + "<html>\n"
451             + "<head>\n"
452             + "<script>\n"
453             + LOG_TITLE_FUNCTION
454             + "function doTest() {\n"
455             + "  var f = document.getElementById('myStyle');\n"
456             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
457             + "  var rules = s.cssRules || s.rules;\n"
458             + "  log(rules.length);\n"
459             + "  try {\n"
460             + "    if (s.deleteRule)\n"
461             + "      s.deleteRule(0);\n"
462             + "    else\n"
463             + "      s.removeRule(0);\n"
464             + "    log(rules.length);\n"
465             + "    log(rules[0].selectorText);\n"
466             + "    log(rules[0].style.cssText);\n"
467             + "  } catch(err) { logEx(e); }\n"
468             + "}</script>\n"
469             + "<style id='myStyle'>\n"
470             + "  p { vertical-align:top }\n"
471             + "  @unknown div { color: red; }\n"
472             + "  div { color: red; }\n"
473             + "</style>\n"
474             + "</head><body onload='doTest()'>\n"
475             + "</body></html>";
476 
477         loadPageVerifyTitle2(html);
478     }
479 
480     /**
481      * @throws Exception if an error occurs
482      */
483     @Test
484     @Alerts({"2", "1", "p", "vertical-align: top;"})
485     public void deleteRuleIgnoredLast() throws Exception {
486         final String html = DOCTYPE_HTML
487             + "<html>\n"
488             + "<head>\n"
489             + "<script>\n"
490             + LOG_TITLE_FUNCTION
491             + "function doTest() {\n"
492             + "  var f = document.getElementById('myStyle');\n"
493             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
494             + "  var rules = s.cssRules || s.rules;\n"
495             + "  log(rules.length);\n"
496             + "  try {\n"
497             + "    if (s.deleteRule)\n"
498             + "      s.deleteRule(1);\n"
499             + "    else\n"
500             + "      s.removeRule(1);\n"
501             + "    log(rules.length);\n"
502             + "    log(rules[0].selectorText);\n"
503             + "    log(rules[0].style.cssText);\n"
504             + "  } catch(err) { logEx(e); }\n"
505             + "}</script>\n"
506             + "<style id='myStyle'>\n"
507             + "  p { vertical-align:top }\n"
508             + "  @unknown div { color: red; }\n"
509             + "  div { color: red; }\n"
510             + "</style>\n"
511             + "</head><body onload='doTest()'>\n"
512             + "</body></html>";
513 
514         loadPageVerifyTitle2(html);
515     }
516 
517     /**
518      * Test that CSSParser can handle leading whitespace in insertRule.
519      * @throws Exception if an error occurs
520      */
521     @Test
522     @Alerts({"2", ".testStyleDef", "height: 42px;", ".testStyle", "width: 24px;"})
523     public void insertRuleLeadingWhitespace() throws Exception {
524         final String html = DOCTYPE_HTML
525             + "<html><head><script>\n"
526             + LOG_TITLE_FUNCTION
527             + "function doTest() {\n"
528             + "  var f = document.getElementById('myStyle');\n"
529             + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
530             + "  var rules = s.cssRules || s.rules;\n"
531             + "  if (s.insertRule) {\n"
532             + "    s.insertRule('.testStyle { width: 24px; }', 0);\n"
533             + "    s.insertRule(' .testStyleDef { height: 42px; }', 0);\n"
534             + "    log(rules.length);\n"
535             + "    log(rules[0].selectorText);\n"
536             + "    log(rules[0].style.cssText);\n"
537             + "    log(rules[1].selectorText);\n"
538             + "    log(rules[1].style.cssText);\n"
539             + "  }\n"
540             + "}</script>\n"
541             + "<style id='myStyle'></style>\n"
542             + "</head><body onload='doTest()'>\n"
543             + "</body></html>";
544 
545         loadPageVerifyTitle2(html);
546     }
547 
548     /**
549      * @throws Exception on test failure
550      */
551     @Test
552     @Alerts({"false", "false", "true", "true", "false"})
553     public void langCondition() throws Exception {
554         final String htmlSnippet = "<div id='elt2' lang='en'></div>\n"
555                 + "  <div id='elt3' lang='en-GB'></div>\n"
556                 + "  <div id='elt4' lang='english'></div>\n";
557         doTest(":lang(en)", htmlSnippet);
558     }
559 
560     /**
561      * @throws Exception on test failure
562      */
563     @Test
564     @Alerts({"false", "false", "true", "false", "true"})
565     public void langConditionParent() throws Exception {
566         final String htmlSnippet =
567                 "<div id='elt2' lang='en'>\n"
568                 + "  <div id='elt3' lang='de'></div>\n"
569                 + "  <div id='elt4' ></div>\n"
570                 + "</div>\n";
571         doTest(":lang(en)", htmlSnippet);
572     }
573 
574     /**
575      * @throws Exception on test failure
576      */
577     @Test
578     @Alerts({"true", "false"})
579     public void css2_root() throws Exception {
580         doTest(":root", "");
581     }
582 
583     /**
584      * CSS3 pseudo selector :not is not yet supported.
585      * @throws Exception on test failure
586      */
587     @Test
588     @Alerts({"true", "true", "false"})
589     public void css3_not() throws Exception {
590         doTest(":not(span)", "<span id='elt2'></span>");
591     }
592 
593     /**
594      * @throws Exception on test failure
595      */
596     @Test
597     @Alerts({"false", "false", "true", "false", "true", "true", "true", "true"})
598     public void css3_enabled() throws Exception {
599         final String htmlSnippet = "<input id='elt2'>\n"
600             + "<input id='elt3' disabled>\n"
601             + "<input id='elt4' type='checkbox'>\n"
602             + "<button id='elt5' ></button>\n"
603             + "<select id='elt6' ></select>\n"
604             + "<textarea id='elt7' ></textarea>\n";
605         doTest(":enabled", htmlSnippet);
606     }
607 
608     /**
609      * @throws Exception on test failure
610      */
611     @Test
612     @Alerts({"false", "false", "true", "false", "true", "true", "true", "true"})
613     public void css3_disabled() throws Exception {
614         final String htmlSnippet = "<input id='elt2' disabled>\n"
615             + "<input id='elt3'>\n"
616             + "<input id='elt4' type='checkbox' disabled>\n"
617             + "<button id='elt5' disabled></button>\n"
618             + "<select id='elt6' disabled></select>\n"
619             + "<textarea id='elt7' disabled></textarea>\n";
620         doTest(":disabled", htmlSnippet);
621     }
622 
623     /**
624      * @throws Exception on test failure
625      */
626     @Test
627     @Alerts({"false", "false", "false", "false", "true", "false", "true", "false"})
628     public void css3_checked() throws Exception {
629         final String htmlSnippet = "  <input id='elt2'>\n"
630             + "  <input id='elt3' checked>\n"
631             + "  <input id='elt4' type='checkbox' checked>\n"
632             + "  <input id='elt5' type='checkbox'>\n"
633             + "  <input id='elt6' type='radio' checked>\n"
634             + "  <input id='elt7' type='radio'>\n";
635         doTest(":checked", htmlSnippet);
636     }
637 
638     /**
639      * @throws Exception on test failure
640      */
641     @Test
642     @Alerts({"false", "false", "true", "false", "false", "false", "true", "true", "false", "false"})
643     public void css3_required() throws Exception {
644         final String htmlSnippet =
645             "  <input id='elt2' required>\n"
646             + "  <input id='elt3' type='text'>\n"
647             + "  <select id='elt4'></select>\n"
648             + "  <textarea id='elt5'></textarea>\n"
649             + "  <textarea id='elt6' required=false></textarea>\n"
650             + "  <textarea id='elt7' required=true></textarea>\n"
651             + "  <div id='elt8'></div>\n"
652             + "  <div id='elt9' required=true></div>\n";
653         doTest(":required", htmlSnippet);
654     }
655 
656     /**
657      * @throws Exception on test failure
658      */
659     @Test
660     @Alerts({"false", "false", "false", "true", "true", "true", "false", "false", "false", "false"})
661     public void css3_optional() throws Exception {
662         final String htmlSnippet =
663             "  <input id='elt2' required>\n"
664             + "  <input id='elt3' type='text'>\n"
665             + "  <select id='elt4'></select>\n"
666             + "  <textarea id='elt5'></textarea>\n"
667             + "  <textarea id='elt6' required=false></textarea>\n"
668             + "  <textarea id='elt7' required=true></textarea>\n"
669             + "  <div id='elt8'></div>\n"
670             + "  <div id='elt9' required=true></div>\n";
671         doTest(":optional", htmlSnippet);
672     }
673 
674     private void doTest(final String cssSelector, final String htmlSnippet) throws Exception {
675         final String html = DOCTYPE_HTML
676                 + "<html id='elt0'><head>\n"
677                 + "<style>\n"
678                 + cssSelector + " { z-index: 10 }\n"
679                 + "</style>\n"
680                 + "<script>\n"
681                 + LOG_TITLE_FUNCTION
682                 + "  function test() {\n"
683                 + "    var getStyle = function(e) {\n"
684                 + "      return window.getComputedStyle(e, '');\n"
685                 + "    };\n"
686                 + "    var i = 0;\n"
687                 + "    while (true) {\n"
688                 + "      var elt = document.getElementById('elt' + i++);\n"
689                 + "      if (!elt) return;\n"
690                 + "      log(getStyle(elt).zIndex == 10);\n"
691                 + "    }\n"
692                 + "  }\n"
693                 + "</script>\n"
694                 + "</head><body onload='test()'>\n"
695                 + "  <div id='elt1'></div>\n"
696                 + htmlSnippet
697                 + "</body></html>";
698         loadPageVerifyTitle2(html);
699     }
700 
701     /**
702      * Test for handling priority !important.
703      * @see <a href="http://sf.net/support/tracker.php?aid=2880057">Bug 2880057</a>
704      * @throws Exception if an error occurs
705      */
706     @Test
707     @Alerts("width=100")
708     public void important() throws Exception {
709         final String html = DOCTYPE_HTML
710             + "<html>\n"
711             + "<head>\n"
712             + "<script>\n"
713             + LOG_TITLE_FUNCTION
714             + "function doTest() {\n"
715             + "  var e = document.getElementById('style1');\n"
716             + "  log('width=' + e.clientWidth);\n"
717             + "}\n"
718             + "</script>\n"
719             + "<style>\n"
720             + "#style1 {left: 25px; width: 100px !important;}\n"
721             + "#style1 {position: absolute; left: 100px; width: 50px; height: 50px;}\n"
722             + "</style>\n"
723             + "</head><body onload='doTest()'>\n"
724             + "<div id='style1'>Hello</div>\n"
725             + "</body></html>";
726 
727         loadPageVerifyTitle2(html);
728     }
729 
730     /**
731      * Test for handling/ignoring @font-face.
732      * see bug 2984265
733      * @throws Exception if an error occurs
734      */
735     @Test
736     @Alerts("none")
737     public void fontFace() throws Exception {
738         final String html = DOCTYPE_HTML
739             + "<html>\n"
740             + "<head>\n"
741             + "<script>\n"
742             + LOG_TITLE_FUNCTION
743             + "function doTest() {\n"
744             + "  var e = document.getElementById('div1');\n"
745             + "  var s = window.getComputedStyle(e, '');\n"
746             + "  log(s.display);\n"
747             + "}\n"
748             + "</script>\n"
749             + "<style>\n"
750             + "  @font-face { font-family: YanoneKaffeesatz; src: url(/YanoneKaffeesatz-Regular.otf); }\n"
751             + "  body { font-family: YanoneKaffeesatz; }\n"
752             + "  div { display: none; }\n"
753             + "</style>\n"
754             + "</head><body onload='doTest()'>\n"
755             + "<div id='div1'>invisible</div>\n"
756             + "visible\n"
757             + "</body></html>";
758 
759         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
760 
761         loadPageVerifyTitle2(html);
762     }
763 
764     /**
765      * Test that the rule with higher specificity wins.
766      * @throws Exception on test failure
767      */
768     @Test
769     @Alerts("60")
770     public void rulePriority_specificity() throws Exception {
771         final String html = DOCTYPE_HTML
772             + "<html><head>\n"
773             + "<style>\n"
774             + "div { z-index: 60 }\n"
775             + "* { z-index: 10 }\n"
776             + "</style></head>\n"
777             + "<body>\n"
778             + "<div id='it'>hello</div>\n"
779             + "<script>\n"
780             + LOG_TITLE_FUNCTION
781             + "  var getStyle = function(e) {\n"
782             + "    return window.getComputedStyle(e, '');\n"
783             + "  };\n"
784             + "  log(getStyle(document.getElementById('it')).zIndex);\n"
785             + "</script>\n"
786             + "</body></html>";
787 
788         loadPageVerifyTitle2(html);
789     }
790 
791     /**
792      * Test that the rule with higher specificity wins. More complete case.
793      * @throws Exception on test failure
794      */
795     @Test
796     @Alerts("60")
797     public void rulePriority_specificity2() throws Exception {
798         final String html = DOCTYPE_HTML
799             + "<html><head>\n"
800             + "<style>\n"
801             + ".classA .classB .classC { z-index: 60 }\n"
802             + ".classA .classC { z-index: 10 }\n"
803             + "</style></head>\n"
804             + "<body>\n"
805             + "<div class='classA'>\n"
806             + "<div class='classB'>\n"
807             + "<div id='it' class='classC'>hello</div>\n"
808             + "</div>\n"
809             + "</div>\n"
810             + "<script>\n"
811             + LOG_TITLE_FUNCTION
812             + "  var getStyle = function(e) {\n"
813             + "    return window.getComputedStyle(e, '');\n"
814             + "  };\n"
815             + "  log(getStyle(document.getElementById('it')).zIndex);\n"
816             + "</script>\n"
817             + "</body></html>";
818 
819         loadPageVerifyTitle2(html);
820     }
821 
822     /**
823      * Test that the last one wins when selectors have the same specificity.
824      * @throws Exception on test failure
825      */
826     @Test
827     @Alerts({"10", "10"})
828     public void rulePriority_position() throws Exception {
829         final String html = DOCTYPE_HTML
830             + "<html><head>\n"
831             + "<style>\n"
832             + ".classA { z-index: 60 }\n"
833             + ".classB { z-index: 10 }\n"
834             + "</style></head>\n"
835             + "<body>\n"
836             + "<div id='it1' class='classA classB'>hello</div>\n"
837             + "<div id='it2' class='classA classB'>hello</div>\n"
838             + "<script>\n"
839             + LOG_TITLE_FUNCTION
840             + "  var getStyle = function(e) {\n"
841             + "    return window.getComputedStyle(e, '');\n"
842             + "  };\n"
843             + "  log(getStyle(document.getElementById('it1')).zIndex);\n"
844             + "  log(getStyle(document.getElementById('it2')).zIndex);\n"
845             + "</script>\n"
846             + "</body></html>";
847 
848         loadPageVerifyTitle2(html);
849     }
850 
851     /**
852      * @throws Exception if an error occurs
853      */
854     @Test
855     @Alerts({"none", "1"})
856     public void mediaOnStyleTag_noMedia() throws Exception {
857         mediaOnStyleTag("");
858     }
859 
860     /**
861      * @throws Exception if an error occurs
862      */
863     @Test
864     @Alerts({"none", "1"})
865     public void mediaOnStyleTag_whitespace() throws Exception {
866         mediaOnStyleTag(" ");
867     }
868 
869     /**
870      * @throws Exception if an error occurs
871      */
872     @Test
873     @Alerts({"none", "1"})
874     public void mediaOnStyleTag_all() throws Exception {
875         mediaOnStyleTag("all");
876     }
877 
878     /**
879      * @throws Exception if an error occurs
880      */
881     @Test
882     @Alerts({"none", "1"})
883     public void mediaOnStyleTag_screen() throws Exception {
884         mediaOnStyleTag("screen");
885     }
886 
887     /**
888      * @throws Exception if an error occurs
889      */
890     @Test
891     @Alerts({"block", "1"})
892     public void mediaOnStyleTag_print() throws Exception {
893         mediaOnStyleTag("print");
894     }
895 
896     /**
897      * @throws Exception if an error occurs
898      */
899     @Test
900     @Alerts({"none", "1"})
901     public void mediaOnStyleTag_print_not() throws Exception {
902         mediaOnStyleTag("not print");
903     }
904 
905     /**
906      * @throws Exception if an error occurs
907      */
908     @Test
909     @Alerts({"none", "1"})
910     public void mediaOnStyleTag_multipleWithScreen() throws Exception {
911         mediaOnStyleTag("print, screen, tv");
912     }
913 
914     /**
915      * @throws Exception if an error occurs
916      */
917     @Test
918     @Alerts({"block", "1"})
919     public void mediaOnStyleTag_multipleWithoutScreen() throws Exception {
920         mediaOnStyleTag("print, projection, tv");
921     }
922 
923     private void mediaOnStyleTag(final String media) throws Exception {
924         final String html = DOCTYPE_HTML
925             + "<html><head>\n"
926             + "<style media='" + media + "'> div { display: none }</style>\n"
927             + "</head><body>\n"
928             + "<div id='d'>hello</div>\n"
929             + "<script>\n"
930             + LOG_TITLE_FUNCTION
931             + "  var getStyle = function(e) {\n"
932             + "    return window.getComputedStyle(e, '');\n"
933             + "  };\n"
934             + "  log(getStyle(document.getElementById('d')).display);\n"
935             + "  log(document.styleSheets.length);\n"
936             + "</script></body></html>";
937         loadPageVerifyTitle2(html);
938     }
939 
940     /**
941      * @throws Exception if an error occurs
942      */
943     @Test
944     @Alerts({"none", "1"})
945     public void mediaOnLinkTag_noMedia() throws Exception {
946         mediaOnLinkTag("");
947     }
948 
949     /**
950      * @throws Exception if an error occurs
951      */
952     @Test
953     @Alerts({"none", "1"})
954     public void mediaOnLinkTag_whitespace() throws Exception {
955         mediaOnLinkTag(" ");
956     }
957 
958     /**
959      * @throws Exception if an error occurs
960      */
961     @Test
962     @Alerts({"none", "1"})
963     public void mediaOnLinkTag_all() throws Exception {
964         mediaOnLinkTag("all");
965     }
966 
967     /**
968      * @throws Exception if an error occurs
969      */
970     @Test
971     @Alerts({"none", "1"})
972     public void mediaOnLinkTag_screen() throws Exception {
973         mediaOnLinkTag("screen");
974     }
975 
976     /**
977      * @throws Exception if an error occurs
978      */
979     @Test
980     @Alerts({"block", "0"})
981     public void mediaOnLinkTag_notScreen() throws Exception {
982         mediaOnLinkTag("print");
983     }
984 
985     /**
986      * @throws Exception if an error occurs
987      */
988     @Test
989     @Alerts({"none", "1"})
990     public void mediaOnLinkTag_multipleWithScreen() throws Exception {
991         mediaOnLinkTag("print, screen, tv");
992     }
993 
994     /**
995      * @throws Exception if an error occurs
996      */
997     @Test
998     @Alerts({"block", "0"})
999     public void mediaOnLinkTag_multipleWithoutScreen() throws Exception {
1000         mediaOnLinkTag("print, projection, tv");
1001     }
1002 
1003     private void mediaOnLinkTag(final String media) throws Exception {
1004         final String html = DOCTYPE_HTML
1005             + "<html><head>\n"
1006             + "<link rel='stylesheet' media='" + media + "' href='" + URL_SECOND + "'></link>\n"
1007             + "</head><body>\n"
1008             + "<div id='d'>hello</div>\n"
1009             + "<script>\n"
1010             + LOG_TITLE_FUNCTION
1011             + "  var getStyle = function(e) {\n"
1012             + "    return window.getComputedStyle(e, '');\n"
1013             + "  };\n"
1014             + "  log(getStyle(document.getElementById('d')).display);\n"
1015             + "  log(document.styleSheets.length);\n"
1016             + "</script></body></html>";
1017 
1018         getMockWebConnection().setResponse(URL_SECOND, "div { display: none }", MimeType.TEXT_CSS);
1019         loadPageVerifyTitle2(html);
1020     }
1021 
1022     /**
1023      * @throws Exception if an error occurs
1024      */
1025     @Test
1026     @Alerts({"none", "1"})
1027     public void mediaRule_screen() throws Exception {
1028         mediaRule("screen");
1029     }
1030 
1031     /**
1032      * @throws Exception if an error occurs
1033      */
1034     @Test
1035     @Alerts({"block", "1"})
1036     public void mediaRule_notScreen() throws Exception {
1037         mediaRule("print");
1038     }
1039 
1040     /**
1041      * @throws Exception if an error occurs
1042      */
1043     @Test
1044     @Alerts({"none", "1"})
1045     public void mediaRule_multipleWithScreen() throws Exception {
1046         mediaRule("print, screen, tv");
1047     }
1048 
1049     /**
1050      * @throws Exception if an error occurs
1051      */
1052     @Test
1053     @Alerts({"block", "1"})
1054     public void mediaRule_multipleWithoutScreen() throws Exception {
1055         mediaRule("print, projection, tv");
1056     }
1057 
1058     /**
1059      * @throws Exception if an error occurs
1060      */
1061     @Test
1062     @Alerts({"block", "1"})
1063     public void mediaRule_max_width() throws Exception {
1064         mediaRule("screen and (max-width: 123px)");
1065     }
1066 
1067     /**
1068      * @throws Exception if an error occurs
1069      */
1070     @Test
1071     @Alerts({"none", "1"})
1072     public void mediaRule_max_width_match() throws Exception {
1073         mediaRule("screen and (max-width: 10000px)");
1074     }
1075 
1076     /**
1077      * @throws Exception if an error occurs
1078      */
1079     @Test
1080     @Alerts({"block", "1"})
1081     public void mediaRule_max_width_invalid() throws Exception {
1082         mediaRule("screen and (max-width: 5kilo)");
1083     }
1084 
1085     /**
1086      * @throws Exception if an error occurs
1087      */
1088     @Test
1089     @Alerts({"block", "1"})
1090     public void mediaRule_max_width_without_unit() throws Exception {
1091         mediaRule("screen and (max-width: 10000)");
1092     }
1093 
1094     /**
1095      * @throws Exception if an error occurs
1096      */
1097     @Test
1098     @Alerts({"block", "1"})
1099     public void mediaRule_max_width_without_value() throws Exception {
1100         mediaRule("screen and (max-width)");
1101         mediaRule("screen and (max-width:)");
1102     }
1103 
1104     /**
1105      * @throws Exception if an error occurs
1106      */
1107     @Test
1108     @Alerts({"block", "1"})
1109     public void mediaRule_min_width() throws Exception {
1110         mediaRule("screen and (min-width: 10000px)");
1111     }
1112 
1113     /**
1114      * @throws Exception if an error occurs
1115      */
1116     @Test
1117     @Alerts({"none", "1"})
1118     public void mediaRule_min_width_match() throws Exception {
1119         mediaRule("screen and (min-width: 123px)");
1120     }
1121 
1122     /**
1123      * @throws Exception if an error occurs
1124      */
1125     @Test
1126     @Alerts({"block", "1"})
1127     public void mediaRule_min_width_invalid() throws Exception {
1128         mediaRule("screen and (min-width: 5kilo)");
1129     }
1130 
1131     /**
1132      * @throws Exception if an error occurs
1133      */
1134     @Test
1135     @Alerts({"block", "1"})
1136     public void mediaRule_min_width_without_unit() throws Exception {
1137         mediaRule("screen and (min-width: 123)");
1138     }
1139 
1140     /**
1141      * @throws Exception if an error occurs
1142      */
1143     @Test
1144     @Alerts({"block", "1"})
1145     public void mediaRule_min_width_without_value() throws Exception {
1146         mediaRule("screen and (min-width)");
1147         mediaRule("screen and (min-width:)");
1148     }
1149 
1150     /**
1151      * @throws Exception if an error occurs
1152      */
1153     @Test
1154     @Alerts({"block", "1"})
1155     public void mediaRule_max_device_width() throws Exception {
1156         mediaRule("screen and (max-device-width: 123px)");
1157     }
1158 
1159     /**
1160      * @throws Exception if an error occurs
1161      */
1162     @Test
1163     @Alerts({"none", "1"})
1164     public void mediaRule_max_device_width_match() throws Exception {
1165         mediaRule("screen and (max-device-width: 10000px)");
1166     }
1167 
1168     /**
1169      * @throws Exception if an error occurs
1170      */
1171     @Test
1172     @Alerts({"block", "1"})
1173     public void mediaRule_max_device_width_invalid() throws Exception {
1174         mediaRule("screen and (max-device-width: 5kilo)");
1175     }
1176 
1177     /**
1178      * @throws Exception if an error occurs
1179      */
1180     @Test
1181     @Alerts({"block", "1"})
1182     public void mediaRule_max_device_width_without_unit() throws Exception {
1183         mediaRule("screen and (max-device-width: 10000)");
1184     }
1185 
1186     /**
1187      * @throws Exception if an error occurs
1188      */
1189     @Test
1190     @Alerts({"block", "1"})
1191     public void mediaRule_max_device_width_without_value() throws Exception {
1192         mediaRule("screen and (max-device-width)");
1193         mediaRule("screen and (max-device-width:)");
1194     }
1195 
1196     /**
1197      * @throws Exception if an error occurs
1198      */
1199     @Test
1200     @Alerts({"block", "1"})
1201     public void mediaRule_min_device_width() throws Exception {
1202         mediaRule("screen and (min-device-width: 10000px)");
1203     }
1204 
1205     /**
1206      * @throws Exception if an error occurs
1207      */
1208     @Test
1209     @Alerts({"none", "1"})
1210     public void mediaRule_min_device_width_match() throws Exception {
1211         mediaRule("screen and (min-device-width: 123px)");
1212     }
1213 
1214     /**
1215      * @throws Exception if an error occurs
1216      */
1217     @Test
1218     @Alerts({"block", "1"})
1219     public void mediaRule_min_device_width_invalid() throws Exception {
1220         mediaRule("screen and (min-device-width: 5kilo)");
1221     }
1222 
1223     /**
1224      * @throws Exception if an error occurs
1225      */
1226     @Test
1227     @Alerts({"block", "1"})
1228     public void mediaRule_min_device_width_without_unit() throws Exception {
1229         mediaRule("screen and (min-device-width: 123)");
1230     }
1231 
1232     /**
1233      * @throws Exception if an error occurs
1234      */
1235     @Test
1236     @Alerts({"block", "1"})
1237     public void mediaRule_min_device_width_without_value() throws Exception {
1238         mediaRule("screen and (min-device-width)");
1239         mediaRule("screen and (min-device-width:)");
1240     }
1241 
1242     /**
1243      * @throws Exception if an error occurs
1244      */
1245     @Test
1246     @Alerts({"block", "1"})
1247     public void mediaRule_max_height() throws Exception {
1248         mediaRule("screen and (max-height: 123px)");
1249     }
1250 
1251     /**
1252      * @throws Exception if an error occurs
1253      */
1254     @Test
1255     @Alerts({"none", "1"})
1256     public void mediaRule_max_height_match() throws Exception {
1257         mediaRule("screen and (max-height: 10000px)");
1258     }
1259 
1260     /**
1261      * @throws Exception if an error occurs
1262      */
1263     @Test
1264     @Alerts({"block", "1"})
1265     public void mediaRule_max_height_invalid() throws Exception {
1266         mediaRule("screen and (max-height: 5kilo)");
1267     }
1268 
1269     /**
1270      * @throws Exception if an error occurs
1271      */
1272     @Test
1273     @Alerts({"block", "1"})
1274     public void mediaRule_max_height_without_unit() throws Exception {
1275         mediaRule("screen and (max-height: 10000)");
1276     }
1277 
1278     /**
1279      * @throws Exception if an error occurs
1280      */
1281     @Test
1282     @Alerts({"block", "1"})
1283     public void mediaRule_max_height_without_value() throws Exception {
1284         mediaRule("screen and (max-height)");
1285         mediaRule("screen and (max-height:)");
1286     }
1287 
1288     /**
1289      * @throws Exception if an error occurs
1290      */
1291     @Test
1292     @Alerts({"block", "1"})
1293     public void mediaRule_min_height() throws Exception {
1294         mediaRule("screen and (min-height: 10000px)");
1295     }
1296 
1297     /**
1298      * @throws Exception if an error occurs
1299      */
1300     @Test
1301     @Alerts({"none", "1"})
1302     public void mediaRule_min_height_match() throws Exception {
1303         mediaRule("screen and (min-height: 123px)");
1304     }
1305 
1306     /**
1307      * @throws Exception if an error occurs
1308      */
1309     @Test
1310     @Alerts({"block", "1"})
1311     public void mediaRule_min_height_invalid() throws Exception {
1312         mediaRule("screen and (min-height: 5kilo)");
1313     }
1314 
1315     /**
1316      * @throws Exception if an error occurs
1317      */
1318     @Test
1319     @Alerts({"block", "1"})
1320     public void mediaRule_min_height_without_unit() throws Exception {
1321         mediaRule("screen and (min-height: 123)");
1322     }
1323 
1324     /**
1325      * @throws Exception if an error occurs
1326      */
1327     @Test
1328     @Alerts({"block", "1"})
1329     public void mediaRule_min_height_without_value() throws Exception {
1330         mediaRule("screen and (min-height)");
1331         mediaRule("screen and (min-height:)");
1332     }
1333 
1334     /**
1335      * @throws Exception if an error occurs
1336      */
1337     @Test
1338     @Alerts({"block", "1"})
1339     public void mediaRule_max_device_height() throws Exception {
1340         mediaRule("screen and (max-device-height: 123px)");
1341     }
1342 
1343     /**
1344      * @throws Exception if an error occurs
1345      */
1346     @Test
1347     @Alerts({"none", "1"})
1348     public void mediaRule_max_device_height_match() throws Exception {
1349         mediaRule("screen and (max-device-height: 10000px)");
1350     }
1351 
1352     /**
1353      * @throws Exception if an error occurs
1354      */
1355     @Test
1356     @Alerts({"block", "1"})
1357     public void mediaRule_max_device_height_invalid() throws Exception {
1358         mediaRule("screen and (max-device-height: 5kilo)");
1359     }
1360 
1361     /**
1362      * @throws Exception if an error occurs
1363      */
1364     @Test
1365     @Alerts({"block", "1"})
1366     public void mediaRule_max_device_height_without_unit() throws Exception {
1367         mediaRule("screen and (max-device-height: 10000)");
1368     }
1369 
1370     /**
1371      * @throws Exception if an error occurs
1372      */
1373     @Test
1374     @Alerts({"block", "1"})
1375     public void mediaRule_max_device_height_without_value() throws Exception {
1376         mediaRule("screen and (max-device-height)");
1377         mediaRule("screen and (max-device-height:)");
1378     }
1379 
1380     /**
1381      * @throws Exception if an error occurs
1382      */
1383     @Test
1384     @Alerts({"block", "1"})
1385     public void mediaRule_min_device_height() throws Exception {
1386         mediaRule("screen and (min-device-height: 10000px)");
1387     }
1388 
1389     /**
1390      * @throws Exception if an error occurs
1391      */
1392     @Test
1393     @Alerts({"none", "1"})
1394     public void mediaRule_min_device_height_match() throws Exception {
1395         mediaRule("screen and (min-device-height: 123px)");
1396     }
1397 
1398     /**
1399      * @throws Exception if an error occurs
1400      */
1401     @Test
1402     @Alerts({"block", "1"})
1403     public void mediaRule_min_device_height_invalid() throws Exception {
1404         mediaRule("screen and (min-device-height: 5kilo)");
1405     }
1406 
1407     /**
1408      * @throws Exception if an error occurs
1409      */
1410     @Test
1411     @Alerts({"block", "1"})
1412     public void mediaRule_min_device_height_without_unit() throws Exception {
1413         mediaRule("screen and (min-device-height: 123)");
1414     }
1415 
1416     /**
1417      * @throws Exception if an error occurs
1418      */
1419     @Test
1420     @Alerts({"block", "1"})
1421     public void mediaRule_min_device_height_without_value() throws Exception {
1422         mediaRule("screen and (min-device-height)");
1423         mediaRule("screen and (min-device-height:)");
1424     }
1425 
1426     /**
1427      * @throws Exception if an error occurs
1428      */
1429     @Test
1430     @Alerts({"block", "1"})
1431     public void mediaRule_resolution() throws Exception {
1432         mediaRule("screen and (resolution: 4dpi)");
1433     }
1434 
1435     /**
1436      * @throws Exception if an error occurs
1437      */
1438     @Test
1439     @Alerts({"none", "1"})
1440     public void mediaRule_resolution_match() throws Exception {
1441         mediaRule("screen and (resolution: 96dpi)");
1442     }
1443 
1444     /**
1445      * @throws Exception if an error occurs
1446      */
1447     @Test
1448     @Alerts({"block", "1"})
1449     public void mediaRule_resolution_invalid() throws Exception {
1450         mediaRule("screen and (resolution: 5kilo)");
1451     }
1452 
1453     /**
1454      * @throws Exception if an error occurs
1455      */
1456     @Test
1457     @Alerts({"block", "1"})
1458     public void mediaRule_resolution_without_unit() throws Exception {
1459         mediaRule("screen and (resolution: 96)");
1460     }
1461 
1462     /**
1463      * @throws Exception if an error occurs
1464      */
1465     @Test
1466     @Alerts({"none", "1"})
1467     public void mediaRule_resolution_without_value() throws Exception {
1468         mediaRule("screen and (resolution)");
1469     }
1470 
1471     /**
1472      * @throws Exception if an error occurs
1473      */
1474     @Test
1475     @Alerts({"block", "1"})
1476     public void mediaRule_resolution_without_value_empty() throws Exception {
1477         mediaRule("screen and (resolution:)");
1478     }
1479 
1480     /**
1481      * @throws Exception if an error occurs
1482      */
1483     @Test
1484     @Alerts({"block", "1"})
1485     public void mediaRule_max_resolution() throws Exception {
1486         mediaRule("screen and (max-resolution: 90dpi)");
1487     }
1488 
1489     /**
1490      * @throws Exception if an error occurs
1491      */
1492     @Test
1493     @Alerts({"none", "1"})
1494     public void mediaRule_max_resolution_match() throws Exception {
1495         mediaRule("screen and (max-resolution: 10000dpi)");
1496     }
1497 
1498     /**
1499      * @throws Exception if an error occurs
1500      */
1501     @Test
1502     @Alerts({"block", "1"})
1503     public void mediaRule_max_resolution_invalid() throws Exception {
1504         mediaRule("screen and (max-resolution: 5kilo)");
1505     }
1506 
1507     /**
1508      * @throws Exception if an error occurs
1509      */
1510     @Test
1511     @Alerts({"block", "1"})
1512     public void mediaRule_max_resolution_without_unit() throws Exception {
1513         mediaRule("screen and (max-resolution: 10000)");
1514     }
1515 
1516     /**
1517      * @throws Exception if an error occurs
1518      */
1519     @Test
1520     @Alerts({"block", "1"})
1521     public void mediaRule_max_resolution_without_value() throws Exception {
1522         mediaRule("screen and (max-resolution)");
1523         mediaRule("screen and (max-resolution:)");
1524     }
1525 
1526     /**
1527      * @throws Exception if an error occurs
1528      */
1529     @Test
1530     @Alerts({"block", "1"})
1531     public void mediaRule_min_resolution() throws Exception {
1532         mediaRule("screen and (min-resolution: 10000dpi)");
1533     }
1534 
1535     /**
1536      * @throws Exception if an error occurs
1537      */
1538     @Test
1539     @Alerts({"none", "1"})
1540     public void mediaRule_min_resolution_match() throws Exception {
1541         mediaRule("screen and (min-resolution: 10dpi)");
1542     }
1543 
1544     /**
1545      * @throws Exception if an error occurs
1546      */
1547     @Test
1548     @Alerts({"block", "1"})
1549     public void mediaRule_min_resolution_invalid() throws Exception {
1550         mediaRule("screen and (min-resolution: 5kilo)");
1551     }
1552 
1553     /**
1554      * @throws Exception if an error occurs
1555      */
1556     @Test
1557     @Alerts({"block", "1"})
1558     public void mediaRule_min_resolution_without_unit() throws Exception {
1559         mediaRule("screen and (min-resolution: 10)");
1560     }
1561 
1562     /**
1563      * @throws Exception if an error occurs
1564      */
1565     @Test
1566     @Alerts({"block", "1"})
1567     public void mediaRule_min_resolution_without_value() throws Exception {
1568         mediaRule("screen and (min-resolution)");
1569         mediaRule("screen and (min-resolution:)");
1570     }
1571 
1572     /**
1573      * @throws Exception if an error occurs
1574      */
1575     @Test
1576     @Alerts({"block", "1"})
1577     public void mediaRule_portrait() throws Exception {
1578         mediaRule("screen and (orientation: portrait)");
1579     }
1580 
1581     /**
1582      * @throws Exception if an error occurs
1583      */
1584     @Test
1585     @Alerts({"none", "1"})
1586     public void mediaRule_portrait_not() throws Exception {
1587         mediaRule("not screen and (orientation: portrait)");
1588     }
1589 
1590     /**
1591      * @throws Exception if an error occurs
1592      */
1593     @Test
1594     @Alerts({"none", "1"})
1595     public void mediaRule_landscape() throws Exception {
1596         mediaRule("screen and (orientation: landscape)");
1597     }
1598 
1599     /**
1600      * @throws Exception if an error occurs
1601      */
1602     @Test
1603     @Alerts({"block", "1"})
1604     public void mediaRule_landscape_not() throws Exception {
1605         mediaRule("not screen and (orientation: landscape)");
1606     }
1607 
1608     /**
1609      * @throws Exception if an error occurs
1610      */
1611     @Test
1612     @Alerts({"block", "1"})
1613     public void mediaRule_invalidOrientation() throws Exception {
1614         mediaRule("screen and (orientation: unknown)");
1615     }
1616 
1617     /**
1618      * @throws Exception if an error occurs
1619      */
1620     @Test
1621     @Alerts({"none", "1"})
1622     public void mediaRule_orientation_without_value() throws Exception {
1623         mediaRule("screen and (orientation)");
1624     }
1625 
1626     /**
1627      * @throws Exception if an error occurs
1628      */
1629     @Test
1630     @Alerts({"block", "1"})
1631     public void mediaRule_orientation_without_value_empty() throws Exception {
1632         mediaRule("screen and (orientation:)");
1633     }
1634 
1635     private void mediaRule(final String media) throws Exception {
1636         final String html = DOCTYPE_HTML
1637             + "<html>\n"
1638             + "<head>\n"
1639             + "  <style> @media " + media + " { div { display: none } }</style>\n"
1640             + "</head>\n"
1641             + "<body>\n"
1642             + "  <div id='d'>hello</div>\n"
1643             + "  <script>\n"
1644             + LOG_TITLE_FUNCTION
1645             + "    var getStyle = function(e) {\n"
1646             + "      return window.getComputedStyle(e, '');\n"
1647             + "    };\n"
1648             + "    log(getStyle(document.getElementById('d')).display);\n"
1649             + "    log(document.styleSheets.length);\n"
1650             + "  </script>\n"
1651             + "</body></html>";
1652         loadPageVerifyTitle2(html);
1653     }
1654 
1655     /**
1656      * @throws Exception if an error occurs
1657      */
1658     @Test
1659     @Alerts("rgb(255, 0, 0)")
1660     public void veryBig() throws Exception {
1661         final WebDriver driver = getWebDriver();
1662 
1663         int maxInMemory = 0;
1664         if (driver instanceof HtmlUnitDriver) {
1665             final WebClient webClient = getWebClient();
1666             maxInMemory = webClient.getOptions().getMaxInMemory();
1667         }
1668 
1669         final String html = DOCTYPE_HTML
1670             + "<html>\n"
1671             + "  <head>\n"
1672             + "    <link href='" + URL_FIRST + "style.css' rel='stylesheet'></link>\n"
1673             + "  </head>\n"
1674             + "  <body>\n"
1675             + "    <a href='second.html'>second page</a>\n"
1676             + "  </body>\n"
1677             + "</html>";
1678 
1679         final String html2 = "<html>\n"
1680                 + "  <head>\n"
1681                 + "    <link href='" + URL_FIRST + "style.css' rel='stylesheet'></link>\n"
1682                 + "  </head>\n"
1683                 + "  <body class='someRed'>\n"
1684                 + "    <script>\n"
1685                 + "      var getStyle = function(e) {\n"
1686                 + "        return window.getComputedStyle(e, '');\n"
1687                 + "      };\n"
1688                 + "      alert(getStyle(document.body).color);\n"
1689                 + "    </script>\n"
1690                 + "  </body>\n"
1691                 + "</html>";
1692 
1693         final MockWebConnection conn = getMockWebConnection();
1694         final List<NameValuePair> headers2 = new ArrayList<>();
1695         headers2.add(new NameValuePair("Last-Modified", "Sun, 15 Jul 2007 20:46:27 GMT"));
1696         final String bigContent = ".someRed { color: red; }" + StringUtils.repeat(' ', maxInMemory);
1697         conn.setResponse(new URL(URL_FIRST, "style2.css"), bigContent, 200, "OK", MimeType.TEXT_CSS, headers2);
1698         conn.setResponse(new URL(URL_FIRST, "second.html"), html2);
1699 
1700         final List<NameValuePair> headers1 = new ArrayList<>();
1701         headers1.add(new NameValuePair("Location", "style2.css"));
1702         conn.setResponse(new URL(URL_FIRST, "style.css"), "", 302, "Moved", MimeType.TEXT_CSS, headers1);
1703 
1704         loadPage2(html, new URL(URL_FIRST, "test.html"));
1705         driver.findElement(By.linkText("second page")).click();
1706         verifyAlerts(driver, getExpectedAlerts());
1707     }
1708 
1709     /**
1710      * Test that calling insertRule before retrieving the rules works.
1711      * @throws Exception if an error occurs
1712      */
1713     @Test
1714     @Alerts("inserted")
1715     public void insertRuleWithoutGetRules() throws Exception {
1716         final String html = DOCTYPE_HTML
1717                 + "<html>\n"
1718                 + "<head>\n"
1719                 + "<script>\n"
1720                 + LOG_TITLE_FUNCTION
1721                 + "function doTest() {\n"
1722                 + "  var f = document.getElementById('myStyle');\n"
1723                 + "  var s = f.sheet ? f.sheet : f.styleSheet;\n"
1724                 + "  try {\n"
1725                 + "    if (s.insertRule) {\n"
1726                 + "      s.insertRule('.testStyle1 { color: red; }', 0);\n"
1727                 + "    } else {\n"
1728                 + "      s.addRule('.testStyle1', 'color: red;', 0);\n"
1729                 + "    }\n"
1730                 + "    log('inserted');\n"
1731                 + "  } catch(err) { logEx(e); }\n"
1732                 + "}</script>\n"
1733                 + "<style id='myStyle'></style>\n"
1734                 + "</head>\n"
1735                 + "<body onload='doTest()'>\n"
1736                 + "</body></html>";
1737 
1738         loadPageVerifyTitle2(html);
1739     }
1740 
1741     /**
1742      * @throws Exception if the test fails
1743      */
1744     @Test
1745     public void isDisplayed() throws Exception {
1746         final String html = "<!DOCTYPE html>\n"
1747                 + "<head>\n"
1748                 + "<style>\n"
1749                 + "  .tab div {\n"
1750                 + "    display: none;\n"
1751                 + "  }\n"
1752                 + "\n"
1753                 + "  .tab div:target {\n"
1754                 + "    display: block;\n"
1755                 + "  }\n"
1756                 + "</style></head><body>\n"
1757                 + "<div class='tab'>\n"
1758                 + "  <div id='anchor'>\n"
1759                 + "    <p>Content</p>\n"
1760                 + "  </div>\n"
1761                 + "</div>\n"
1762                 + "</body></html>";
1763         getMockWebConnection().setDefaultResponse(html);
1764         final WebDriver webDriver = loadPage2(html);
1765         assertFalse(webDriver.findElement(By.id("anchor")).isDisplayed());
1766         webDriver.get(URL_FIRST + "#anchor");
1767         assertTrue(webDriver.findElement(By.id("anchor")).isDisplayed());
1768     }
1769 
1770     /**
1771      * @throws Exception if the test fails
1772      */
1773     @Test
1774     public void indexLowercaseElement() throws Exception {
1775         final String html = "<!DOCTYPE html>\n"
1776                 + "<head>\n"
1777                 + "<style>\n"
1778                 + "  div { display: none; }\n"
1779                 + "</style>"
1780                 + "</head>\n"
1781                 + "<body>\n"
1782                 + "  <div id='di'>\n"
1783                 + "    <p>Content</p>\n"
1784                 + "  </div>\n"
1785                 + "</body></html>";
1786 
1787         final WebDriver webDriver = loadPage2(html);
1788         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1789     }
1790 
1791     /**
1792      * @throws Exception if the test fails
1793      */
1794     @Test
1795     public void indexUppercaseElement() throws Exception {
1796         final String html = "<!DOCTYPE html>\n"
1797                 + "<head>\n"
1798                 + "<style>\n"
1799                 + "  div { display: none; }\n"
1800                 + "</style>"
1801                 + "</head>\n"
1802                 + "<body>\n"
1803                 + "  <DIV id='di'>\n"
1804                 + "    <p>Content</p>\n"
1805                 + "  </DIV>\n"
1806                 + "</body></html>";
1807 
1808         final WebDriver webDriver = loadPage2(html);
1809         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1810     }
1811 
1812     /**
1813      * @throws Exception if the test fails
1814      */
1815     @Test
1816     public void indexUppercaseRule() throws Exception {
1817         final String html = "<!DOCTYPE html>\n"
1818                 + "<head>\n"
1819                 + "<style>\n"
1820                 + "  DIV { display: none; }\n"
1821                 + "</style>"
1822                 + "</head>\n"
1823                 + "<body>\n"
1824                 + "  <div id='di'>\n"
1825                 + "    <p>Content</p>\n"
1826                 + "  </div>\n"
1827                 + "</body></html>";
1828 
1829         final WebDriver webDriver = loadPage2(html);
1830         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1831     }
1832 
1833     /**
1834      * @throws Exception if the test fails
1835      */
1836     @Test
1837     public void indexLowercaseClass() throws Exception {
1838         final String html = "<!DOCTYPE html>\n"
1839                 + "<head>\n"
1840                 + "<style>\n"
1841                 + "  .cls { display: none; }\n"
1842                 + "</style>"
1843                 + "</head>\n"
1844                 + "<body>\n"
1845                 + "  <div id='di' class='cls'>\n"
1846                 + "    <p>Content</p>\n"
1847                 + "  </div>\n"
1848                 + "</body></html>";
1849 
1850         final WebDriver webDriver = loadPage2(html);
1851         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1852     }
1853 
1854     /**
1855      * @throws Exception if the test fails
1856      */
1857     @Test
1858     public void indexUppercaseElementClass() throws Exception {
1859         final String html = "<!DOCTYPE html>\n"
1860                 + "<head>\n"
1861                 + "<style>\n"
1862                 + "  .cls { display: none; }\n"
1863                 + "</style>"
1864                 + "</head>\n"
1865                 + "<body>\n"
1866                 + "  <div id='di' class='CLS'>\n"
1867                 + "    <p>Content</p>\n"
1868                 + "  </div>\n"
1869                 + "</body></html>";
1870 
1871         final WebDriver webDriver = loadPage2(html);
1872         assertTrue(webDriver.findElement(By.id("di")).isDisplayed());
1873     }
1874 
1875     /**
1876      * @throws Exception if the test fails
1877      */
1878     @Test
1879     public void indexUppercaseRuleClass() throws Exception {
1880         final String html = "<!DOCTYPE html>\n"
1881                 + "<head>\n"
1882                 + "<style>\n"
1883                 + "  .CLS { display: none; }\n"
1884                 + "</style>"
1885                 + "</head>\n"
1886                 + "<body>\n"
1887                 + "  <div id='di' class='cls'>\n"
1888                 + "    <p>Content</p>\n"
1889                 + "  </div>\n"
1890                 + "</body></html>";
1891 
1892         final WebDriver webDriver = loadPage2(html);
1893         assertTrue(webDriver.findElement(By.id("di")).isDisplayed());
1894     }
1895 
1896     /**
1897      * @throws Exception if the test fails
1898      */
1899     @Test
1900     public void indexUppercaseClass() throws Exception {
1901         final String html = "<!DOCTYPE html>\n"
1902                 + "<head>\n"
1903                 + "<style>\n"
1904                 + "  .CLS { display: none; }\n"
1905                 + "</style>"
1906                 + "</head>\n"
1907                 + "<body>\n"
1908                 + "  <div id='di' class='CLS'>\n"
1909                 + "    <p>Content</p>\n"
1910                 + "  </div>\n"
1911                 + "</body></html>";
1912 
1913         final WebDriver webDriver = loadPage2(html);
1914         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1915     }
1916 
1917     /**
1918      * @throws Exception if the test fails
1919      */
1920     @Test
1921     public void indexLowercase2Class() throws Exception {
1922         final String html = "<!DOCTYPE html>\n"
1923                 + "<head>\n"
1924                 + "<style>\n"
1925                 + "  div.cls { display: none; }\n"
1926                 + "</style>"
1927                 + "</head>\n"
1928                 + "<body>\n"
1929                 + "  <div id='di' class='cls'>\n"
1930                 + "    <p>Content</p>\n"
1931                 + "  </div>\n"
1932                 + "</body></html>";
1933 
1934         final WebDriver webDriver = loadPage2(html);
1935         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1936     }
1937 
1938     /**
1939      * @throws Exception if the test fails
1940      */
1941     @Test
1942     public void indexUppercase2ElementClass() throws Exception {
1943         final String html = "<!DOCTYPE html>\n"
1944                 + "<head>\n"
1945                 + "<style>\n"
1946                 + "  div.cls { display: none; }\n"
1947                 + "</style>"
1948                 + "</head>\n"
1949                 + "<body>\n"
1950                 + "  <DIV id='di' class='CLS'>\n"
1951                 + "    <p>Content</p>\n"
1952                 + "  </DIV>\n"
1953                 + "</body></html>";
1954 
1955         final WebDriver webDriver = loadPage2(html);
1956         assertTrue(webDriver.findElement(By.id("di")).isDisplayed());
1957     }
1958 
1959     /**
1960      * @throws Exception if the test fails
1961      */
1962     @Test
1963     public void indexUppercase2RuleClass() throws Exception {
1964         final String html = "<!DOCTYPE html>\n"
1965                 + "<head>\n"
1966                 + "<style>\n"
1967                 + "  div.CLS { display: none; }\n"
1968                 + "</style>"
1969                 + "</head>\n"
1970                 + "<body>\n"
1971                 + "  <diV id='di' class='cls'>\n"
1972                 + "    <p>Content</p>\n"
1973                 + "  </diV>\n"
1974                 + "</body></html>";
1975 
1976         final WebDriver webDriver = loadPage2(html);
1977         assertTrue(webDriver.findElement(By.id("di")).isDisplayed());
1978     }
1979 
1980     /**
1981      * @throws Exception if the test fails
1982      */
1983     @Test
1984     public void indexUppercase2Class() throws Exception {
1985         final String html = "<!DOCTYPE html>\n"
1986                 + "<head>\n"
1987                 + "<style>\n"
1988                 + "  DiV.CLS { display: none; }\n"
1989                 + "</style>"
1990                 + "</head>\n"
1991                 + "<body>\n"
1992                 + "  <div id='di' class='CLS'>\n"
1993                 + "    <p>Content</p>\n"
1994                 + "  </div>\n"
1995                 + "</body></html>";
1996 
1997         final WebDriver webDriver = loadPage2(html);
1998         assertFalse(webDriver.findElement(By.id("di")).isDisplayed());
1999     }
2000 
2001     /**
2002      * Test for #1300.
2003      * @throws Exception if the test fails
2004      */
2005     @Test
2006     @Alerts("undefined")
2007     public void brokenExternalCSS() throws Exception {
2008         final String html = DOCTYPE_HTML
2009             + "<html><head>\n"
2010             + "<link rel='stylesheet' type='text/css' href='" + URL_SECOND + "'/>\n"
2011             + "</head>\n"
2012             + "<body>\n"
2013             + "<script>\n"
2014             + LOG_TITLE_FUNCTION
2015             + "  log(document.body.currentStyle);\n"
2016             + "</script>\n"
2017             + "</body>\n"
2018             + "</html>";
2019 
2020         getMockWebConnection().setResponse(URL_SECOND, "body { font-weight: 900\\9; }");
2021         loadPageVerifyTitle2(html);
2022     }
2023 
2024     /**
2025      * Test for #941.
2026      * @throws Exception if the test fails
2027      */
2028     @Test
2029     @Alerts({"true", "false"})
2030     public void widthHeightPercent() throws Exception {
2031         widthHeightPercent(DOCTYPE_HTML);
2032     }
2033 
2034     /**
2035      * Test for #941.
2036      * @throws Exception if the test fails
2037      */
2038     @Test
2039     @Alerts({"true", "true"})
2040     public void widthHeightPercentQuirks() throws Exception {
2041         widthHeightPercent("");
2042     }
2043 
2044     private void widthHeightPercent(final String doctype) throws Exception {
2045         final String html = doctype
2046             + "<html>\n"
2047             + "  <head>"
2048             + "    <style>#testDiv { width: 50%; height: 50%; background-color: blue; }</style>\n"
2049             + "  </head>"
2050             + "  <body>\n"
2051             + "    <div id='testDiv'>Test Div</div>\n"
2052 
2053             + "<script>\n"
2054             + LOG_TITLE_FUNCTION
2055             + "  let elem = document.getElementById('testDiv');\n"
2056             + "  let sty = window.getComputedStyle(elem, null);\n"
2057             + "  let w = (window.innerWidth / 2) - parseInt(sty.width, 10);\n"
2058             + "  log(10 > w);\n"
2059             + "  let h = (window.innerHeight / 2) - parseInt(sty.height, 10);\n"
2060             + "  log(10 > h);\n"
2061             + "</script>\n"
2062 
2063             + "  </body>\n"
2064             + "</html>";
2065 
2066         loadPageVerifyTitle2(html);
2067     }
2068 
2069     /**
2070      * Test for #942.
2071      * @throws Exception if the test fails
2072      */
2073     @Test
2074     @Alerts(CHROME = "break at: 10 664.25 / 621",
2075             EDGE = "break at: 10 664.25 / 630",
2076             FF = "break at: 10 675.2000122070312 / 675",
2077             FF_ESR = "break at: 11 734.63330078125 / 677")
2078     @HtmlUnitNYI(CHROME = "break at: 16 637 / 605",
2079             EDGE = "break at: 16 637 / 605",
2080             FF = "break at: 15 616 / 605",
2081             FF_ESR = "break at: 15 616 / 605")
2082     public void endlessLoop() throws Exception {
2083         final String html = DOCTYPE_HTML
2084             + "<html>\n"
2085             + "  <head>"
2086             + "  </head>"
2087             + "  <body>\n"
2088             + "    <h1>Scroll me</h1>\n"
2089 
2090             + "<script>\n"
2091             + LOG_TITLE_FUNCTION
2092 
2093             + "  var lastBottom = 0;\n"
2094             + "  for (let i = 0; i < 70; i++) {\n"
2095             + "    let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;\n"
2096             + "    let stop = document.documentElement.clientHeight;"
2097             + "    if (windowRelativeBottom > stop) {\n"
2098             + "      log('break at: ' + i + ' ' + windowRelativeBottom + ' / ' + stop);\n"
2099             + "      break;\n"
2100             + "    }\n"
2101             + "    if (lastBottom >= windowRelativeBottom) {\n"
2102             + "      log('error at: ' + i + ' ' + windowRelativeBottom + ' / ' + lastBottom);\n"
2103             + "      break;\n"
2104             + "    }\n"
2105             + "    lastBottom = windowRelativeBottom;\n"
2106 
2107             + "    document.body.insertAdjacentHTML('beforeend', '<h1>H 1</h1>');\n"
2108             + "  }\n"
2109             + "</script>\n"
2110 
2111             + "  </body>\n"
2112             + "</html>";
2113 
2114         loadPageVerifyTitle2(html);
2115     }
2116 }