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.html;
16  
17  import java.nio.charset.StandardCharsets;
18  
19  import org.htmlunit.WebDriverTestCase;
20  import org.htmlunit.junit.BrowserRunner;
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.htmlunit.util.MimeType;
23  import org.junit.Test;
24  import org.junit.runner.RunWith;
25  import org.openqa.selenium.WebDriver;
26  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
27  
28  /**
29   * Tests for {@link HTMLStyleElement}.
30   *
31   * @author Marc Guillemot
32   * @author Ronald Brill
33   * @author Frank Danek
34   */
35  @RunWith(BrowserRunner.class)
36  public class HTMLStyleElementTest extends WebDriverTestCase {
37  
38      /**
39       * @throws Exception if the test fails
40       */
41      @Test
42      @Alerts({"[object HTMLStyleElement]", "[object CSSStyleSheet]", "undefined"})
43      public void stylesheet() throws Exception {
44          final String html = DOCTYPE_HTML
45              + "<html><head><script>\n"
46              + LOG_TITLE_FUNCTION
47              + "function doTest() {\n"
48              + "  var f = document.getElementById('myStyle');\n"
49              + "  log(f);\n"
50              + "  log(f.sheet);\n"
51              + "  log(f.styleSheet);\n"
52              + "}</script>\n"
53              + "<style id='myStyle'>p: vertical-align:top</style>\n"
54              + "</head><body onload='doTest()'>\n"
55              + "</body></html>";
56  
57          loadPageVerifyTitle2(html);
58      }
59  
60      /**
61       * As of HtmlUnit-2.5 only the first child node of a STYLE was parsed.
62       * @throws Exception if the test fails
63       */
64      @Test
65      @Alerts("2")
66      public void styleChildren() throws Exception {
67          final String html = DOCTYPE_HTML
68              + "<html><head><script>\n"
69              + LOG_TITLE_FUNCTION
70              + "function doTest() {\n"
71              + "  var doc = document;\n"
72              + "  var style = doc.createElement('style');\n"
73              + "  doc.documentElement.firstChild.appendChild(style);\n"
74              + "  style.appendChild(doc.createTextNode('* { z-index: 0; }\\\n'));\n"
75              + "  style.appendChild(doc.createTextNode('DIV { z-index: 10; position: absolute; }\\\n'));\n"
76              + "  if (doc.styleSheets[0].cssRules)\n"
77              + "    rules = doc.styleSheets[0].cssRules;\n"
78              + "  else\n"
79              + "    rules = doc.styleSheets[0].rules;\n"
80              + "  log(rules.length);\n"
81              + "}</script>\n"
82              + "</head><body onload='doTest()'>\n"
83              + "</body></html>";
84  
85          loadPageVerifyTitle2(html);
86      }
87  
88      /**
89       * @throws Exception if the test fails
90       */
91      @Test
92      @Alerts({".a > .t { }", ".b > .t { }", ".c > .t { }"})
93      public void innerHtml() throws Exception {
94          final String html = DOCTYPE_HTML
95              + "<html><head>\n"
96  
97              + "<style id='style_none'>.a > .t { }</style>\n"
98              + "<style type='text/test' id='style_text'>.b > .t { }</style>\n"
99              + "<style type='text/html' id='style_html'>.c > .t { }</style>\n"
100 
101             + "<script>\n"
102             + LOG_TITLE_FUNCTION
103             + "function doTest() {\n"
104             + "  style = document.getElementById('style_none');\n"
105             + "  log(style.innerHTML);\n"
106             + "  style = document.getElementById('style_text');\n"
107             + "  log(style.innerHTML);\n"
108             + "  style = document.getElementById('style_html');\n"
109             + "  log(style.innerHTML);\n"
110             + "}\n"
111             + "</script>\n"
112             + "</head><body onload='doTest()'>\n"
113             + "</body></html>";
114 
115         loadPageVerifyTitle2(html);
116     }
117 
118     /**
119      * @throws Exception if the test fails
120      */
121     @Test
122     @Alerts({"", "text/test", "text/css"})
123     public void type() throws Exception {
124         final String html = DOCTYPE_HTML
125             + "<html><head>\n"
126 
127             + "<style id='style_none'>my { }</style>\n"
128             + "<style type='text/test' id='style_text'>my { }</style>\n"
129             + "<style type='text/css' id='style_css'>my { }</style>\n"
130 
131             + "<script>\n"
132             + LOG_TITLE_FUNCTION
133             + "function doTest() {\n"
134             + "  style = document.getElementById('style_none');\n"
135             + "  log(style.type);\n"
136             + "  style = document.getElementById('style_text');\n"
137             + "  log(style.type);\n"
138             + "  style = document.getElementById('style_css');\n"
139             + "  log(style.type);\n"
140             + "}\n"
141             + "</script>\n"
142             + "</head><body onload='doTest()'>\n"
143             + "</body></html>";
144 
145         loadPageVerifyTitle2(html);
146     }
147 
148     /**
149      * @throws Exception if the test fails
150      */
151     @Test
152     @Alerts({"", "all", "screen, print,test"})
153     public void media() throws Exception {
154         final String html = DOCTYPE_HTML
155             + "<html><head>\n"
156 
157             + "<style id='style_none'>my { }</style>\n"
158             + "<style media='all' id='style_all'>my { }</style>\n"
159             + "<style media='screen, print,test' id='style_some'>my { }</style>\n"
160 
161             + "<script>\n"
162             + LOG_TITLE_FUNCTION
163             + "function doTest() {\n"
164             + "  style = document.getElementById('style_none');\n"
165             + "  log(style.media);\n"
166             + "  style = document.getElementById('style_all');\n"
167             + "  log(style.media);\n"
168             + "  style = document.getElementById('style_some');\n"
169             + "  log(style.media);\n"
170             + "}\n"
171             + "</script>\n"
172             + "</head><body onload='doTest()'>\n"
173             + "</body></html>";
174 
175         loadPageVerifyTitle2(html);
176     }
177 
178     /**
179      * @throws Exception if the test fails
180      */
181     @Test
182     @Alerts({"all", "", "screen:screen", "priNT", "screen, print"})
183     public void media_setter() throws Exception {
184         final String html = DOCTYPE_HTML
185             + "<html><head>\n"
186 
187             + "<style id='myStyle' media='all'>my { }</style>\n"
188 
189             + "<script>\n"
190             + LOG_TITLE_FUNCTION
191             + "function doTest() {\n"
192             + "  style = document.getElementById('myStyle');\n"
193 
194             + "  log(style.media);\n"
195 
196             + "  style.media = '';\n"
197             + "  log(style.media);\n"
198 
199             + "  style.media = 'screen';\n"
200             + "  log(style.media + ':' + style.attributes['media'].value);\n"
201 
202             + "  style.media = 'priNT';\n"
203             + "  log(style.media);\n"
204 
205             + "  style.media = 'screen, print';\n"
206             + "  log(style.media);\n"
207 
208             + "}\n"
209             + "</script>\n"
210             + "</head><body onload='doTest()'>\n"
211             + "</body></html>";
212 
213         loadPageVerifyTitle2(html);
214     }
215 
216     /**
217      * @throws Exception if the test fails
218      */
219     @Test
220     @Alerts({"undefined", "undefined"})
221     public void scoped() throws Exception {
222         final String html = DOCTYPE_HTML
223             + "<html><head>\n"
224 
225             + "<style id='style_none'>my { }</style>\n"
226 
227             + "<script>\n"
228             + LOG_TITLE_FUNCTION
229             + "function doTest() {\n"
230             + "  style = document.getElementById('style_none');\n"
231             + "  log(style.scoped);\n"
232             + "  style = document.getElementById('style_scoped');\n"
233             + "  log(style.scoped);\n"
234             + "}\n"
235             + "</script>\n"
236             + "</head>\n"
237             + "<body onload='doTest()'>\n"
238             + "  <style id='style_scoped' scoped>my { }</style>\n"
239             + "</body></html>";
240 
241         loadPageVerifyTitle2(html);
242     }
243 
244     /**
245      * @throws Exception if the test fails
246      */
247     @Test
248     @Alerts({"undefined", "true", "false"})
249     public void scoped_setter() throws Exception {
250         final String html = DOCTYPE_HTML
251             + "<html><head>\n"
252 
253             + "<style id='myStyle' media='all'>my { }</style>\n"
254 
255             + "<script>\n"
256             + LOG_TITLE_FUNCTION
257             + "function doTest() {\n"
258             + "  style = document.getElementById('myStyle');\n"
259 
260             + "  log(style.scoped);\n"
261 
262             + "  style.scoped = true;\n"
263             + "  log(style.scoped);\n"
264 
265             + "  style.media = false;\n"
266             + "  log(style.media);\n"
267             + "}\n"
268             + "</script>\n"
269             + "</head><body onload='doTest()'>\n"
270             + "</body></html>";
271 
272         loadPageVerifyTitle2(html);
273     }
274 
275     /**
276      * @throws Exception if the test fails
277      */
278     @Test
279     @Alerts({"", "text/css"})
280     public void type_setter() throws Exception {
281         final String html = DOCTYPE_HTML
282             + "<html><head>\n"
283             + "<style id='style_none'></style>\n"
284 
285             + "<script>\n"
286             + LOG_TITLE_FUNCTION
287             + "function doTest() {\n"
288             + "  style = document.getElementById('style_none');\n"
289             + "  log(style.type);\n"
290             + "  style.type = 'text/css';\n"
291             + "  log(style.type);\n"
292             + "}\n"
293             + "</script>\n"
294             + "</head><body onload='doTest()'>\n"
295             + "</body></html>";
296 
297         loadPageVerifyTitle2(html);
298     }
299 
300     /**
301      * @throws Exception if the test fails
302      */
303     @Test
304     @Alerts({"rgb(0, 128, 0)", "false", "rgb(0, 0, 0)"})
305     public void disabled() throws Exception {
306         final String html = DOCTYPE_HTML
307             + "<html><head>\n"
308             + "<style id='myStyle'> .abc { color: green; }</style>\n"
309 
310             + "<script>\n"
311             + LOG_TITLE_FUNCTION
312             + "function doTest() {\n"
313             + "  var div = document.getElementById('myDiv');\n"
314             + "  var style = document.getElementById('myStyle');\n"
315             + "  log(window.getComputedStyle(div, '').color);\n"
316             + "  log(style.disabled);\n"
317             + "  style.disabled = true;\n"
318             + "  log(window.getComputedStyle(div, '').color);\n"
319             + "}\n"
320             + "</script>\n"
321             + "</head><body onload='doTest()'>\n"
322             + "  <div id='myDiv' class='abc'>abcd</div>\n"
323             + "</body></html>";
324 
325         loadPageVerifyTitle2(html);
326     }
327 
328     /**
329      * @throws Exception if the test fails
330      */
331     @Test
332     @Alerts({"rgb(0, 0, 0)", "rgb(0, 128, 0)", "rgb(0, 0, 255)"})
333     public void styleInCdataXHtml() throws Exception {
334         final String html =
335             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
336             + "<!DOCTYPE html PUBLIC \n"
337             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
338             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
339             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
340             + "<head>\n"
341             + "  <style>\n"
342             + "    //<![CDATA[\n"
343             + "      #one {color: red;}\n"
344             + "    //]]>\n"
345             + "  </style>\n"
346             + "  <style>/*<![CDATA[*/ #two {color: green;} /*]]>*/</style>\n"
347             + "  <style>\n"
348             + "    <![CDATA[\n"
349             + "      #three {color: blue;}\n"
350             + "    ]]>\n"
351             + "  </style>\n"
352             + "  <script>\n"
353 
354             // do not use LOG_TITLE_FUNCTION here
355             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
356             + "    function doTest() {\n"
357             + "      var div = document.getElementById('one');\n"
358             + "      log(window.getComputedStyle(div, null).color);\n"
359             + "      div = document.getElementById('two');\n"
360             + "      log(window.getComputedStyle(div, null).color);\n"
361             + "      div = document.getElementById('three');\n"
362             + "      log(window.getComputedStyle(div, null).color);\n"
363             + "    }\n"
364             + "  </script>\n"
365             + "</head>\n"
366             + "<body onload='doTest()'>\n"
367             + "  <div id='one'>one</div>\n"
368             + "  <div id='two'>two</div>\n"
369             + "  <div id='three'>three</div>\n"
370             + "</body></html>";
371 
372         if (getWebDriver() instanceof HtmlUnitDriver) {
373             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
374         }
375         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.APPLICATION_XHTML, StandardCharsets.UTF_8);
376         verifyTitle2(driver, getExpectedAlerts());
377     }
378 
379     /**
380      * @throws Exception if the test fails
381      */
382     @Test
383     @Alerts({"rgb(0, 0, 0)", "rgb(0, 128, 0)", "rgb(0, 0, 255)"})
384     public void scriptInCdataXml() throws Exception {
385         final String html =
386             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
387             + "<!DOCTYPE html PUBLIC \n"
388             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
389             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
390             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
391             + "<head>\n"
392             + "  <style>\n"
393             + "    //<![CDATA[\n"
394             + "      #one {color: red;}\n"
395             + "    //]]>\n"
396             + "  </style>\n"
397             + "  <style>/*<![CDATA[*/ #two {color: green;} /*]]>*/</style>\n"
398             + "  <style>\n"
399             + "    <![CDATA[\n"
400             + "      #three {color: blue;}\n"
401             + "    ]]>\n"
402             + "  </style>\n"
403             + "  <script>\n"
404 
405             // do not use LOG_TITLE_FUNCTION here
406             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
407             + "    function doTest() {\n"
408             + "      var div = document.getElementById('one');\n"
409             + "      log(window.getComputedStyle(div, null).color);\n"
410             + "      div = document.getElementById('two');\n"
411             + "      log(window.getComputedStyle(div, null).color);\n"
412             + "      div = document.getElementById('three');\n"
413             + "      log(window.getComputedStyle(div, null).color);\n"
414             + "    }\n"
415             + "  </script>\n"
416             + "</head>\n"
417             + "<body onload='doTest()'>\n"
418             + "  <div id='one'>one</div>\n"
419             + "  <div id='two'>two</div>\n"
420             + "  <div id='three'>three</div>\n"
421             + "</body></html>";
422 
423         if (getWebDriver() instanceof HtmlUnitDriver) {
424             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
425         }
426         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.TEXT_XML, StandardCharsets.UTF_8);
427         verifyTitle2(driver, getExpectedAlerts());
428     }
429 
430     /**
431      * @throws Exception if the test fails
432      */
433     @Test
434     @Alerts({"rgb(0, 0, 0)", "rgb(0, 128, 0)", "rgb(0, 0, 0)"})
435     public void scriptInCdataHtml() throws Exception {
436         final String html = DOCTYPE_HTML
437             + "<html>\n"
438             + "<head>\n"
439             + "  <style>\n"
440             + "    //<![CDATA[\n"
441             + "      #one {color: red;}\n"
442             + "    //]]>\n"
443             + "  </style>\n"
444             + "  <style>/*<![CDATA[*/ #two {color: green;} /*]]>*/</style>\n"
445             + "  <style>\n"
446             + "    <![CDATA[\n"
447             + "      #three {color: blue;}\n"
448             + "    ]]>\n"
449             + "  </style>\n"
450             + "  <script>\n"
451             + LOG_TITLE_FUNCTION
452             + "    function doTest() {\n"
453             + "      var div = document.getElementById('one');\n"
454             + "      log(window.getComputedStyle(div, null).color);\n"
455             + "      div = document.getElementById('two');\n"
456             + "      log(window.getComputedStyle(div, null).color);\n"
457             + "      div = document.getElementById('three');\n"
458             + "      log(window.getComputedStyle(div, null).color);\n"
459             + "    }\n"
460             + "  </script>\n"
461             + "</head>\n"
462             + "<body onload='doTest()'>\n"
463             + "  <div id='one'>one</div>\n"
464             + "  <div id='two'>two</div>\n"
465             + "  <div id='three'>three</div>\n"
466             + "</body></html>";
467 
468         if (getWebDriver() instanceof HtmlUnitDriver) {
469             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
470         }
471         loadPageVerifyTitle2(html);
472     }
473 
474     /**
475      * @throws Exception if the test fails
476      */
477     @Test
478     @Alerts({"#id { color: red }", ":before { content: \"</> HtmlUnit\" }"})
479     public void innerHtml1() throws Exception {
480         final String html = DOCTYPE_HTML
481             + "<html>\n"
482             + "  <head>\n"
483             + "    <style>#id { color: red }</style>\n"
484             + "    <script>\n"
485             + LOG_TEXTAREA_FUNCTION
486             + "      function test() {\n"
487             + "        var style = document.getElementsByTagName('style')[0];\n"
488             + "        log(style.innerHTML);\n"
489             + "        style.innerHTML = ':before { content: \"</> HtmlUnit\" }';\n"
490             + "        log(style.innerHTML);\n"
491             + "      }\n"
492             + "    </script>\n"
493             + "  </head>\n"
494             + "  <body onload='test()'>\n"
495             + LOG_TEXTAREA
496             + "  </body>\n"
497             + "</html>";
498 
499         loadPageVerifyTextArea2(html);
500     }
501 
502     /**
503      * @throws Exception if the test fails
504      */
505     @Test
506     @Alerts({"#id { color: red }", ":before { content: \"<span>Html</span>Unit\" }"})
507     public void innerHtmlTag() throws Exception {
508         final String html = DOCTYPE_HTML
509             + "<html>\n"
510             + "  <head>\n"
511             + "    <style>#id { color: red }</style>\n"
512             + "    <script>\n"
513             + LOG_TEXTAREA_FUNCTION
514             + "      function test() {\n"
515             + "        var style = document.getElementsByTagName('style')[0];\n"
516             + "        log(style.innerHTML);\n"
517             + "        style.innerHTML = ':before { content: \"<span>Html</span>Unit\" }';\n"
518             + "        log(style.innerHTML);\n"
519             + "      }\n"
520             + "    </script>\n"
521             + "  </head>\n"
522             + "  <body onload='test()'>\n"
523             + LOG_TEXTAREA
524             + "  </body>\n"
525             + "</html>";
526 
527         loadPageVerifyTextArea2(html);
528     }
529 
530     /**
531      * @throws Exception if the test fails
532      */
533     @Test
534     @Alerts({"", ":before { content: \"&lt;/> HtmlUnit\" }"})
535     public void innerHtmlEscaping() throws Exception {
536         final String html = DOCTYPE_HTML
537             + "<html>\n"
538             + "  <head>\n"
539             + "    <style></style>\n"
540             + "    <script>\n"
541             + LOG_TEXTAREA_FUNCTION
542             + "      function test() {\n"
543             + "        var style = document.getElementsByTagName('style')[0];\n"
544             + "        log(style.innerHTML);\n"
545             + "        style.innerHTML = ':before { content: \"&lt;/> HtmlUnit\" }';\n"
546             + "        log(style.innerHTML);\n"
547             + "      }\n"
548             + "    </script>\n"
549             + "  </head>\n"
550             + "  <body onload='test()'>\n"
551             + LOG_TEXTAREA
552             + "  </body>\n"
553             + "</html>";
554 
555         loadPageVerifyTextArea2(html);
556     }
557 }