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.util.ArrayList;
18  import java.util.List;
19  
20  import org.htmlunit.HttpHeader;
21  import org.htmlunit.WebDriverTestCase;
22  import org.htmlunit.junit.annotation.Alerts;
23  import org.htmlunit.junit.annotation.HtmlUnitNYI;
24  import org.htmlunit.util.MimeType;
25  import org.htmlunit.util.NameValuePair;
26  import org.junit.jupiter.api.Test;
27  
28  /**
29   * Unit tests for {@link StyleSheetList}.
30   *
31   * @author Daniel Gredler
32   * @author Ahmed Ashour
33   * @author Marc Guillemot
34   * @author Ronald Brill
35   * @author Frank Danek
36   * @author Carsten Steul
37   */
38  public class StyleSheetListTest extends WebDriverTestCase {
39  
40      /**
41       * @throws Exception if an error occurs
42       */
43      @Test
44      @Alerts("4")
45      public void length() throws Exception {
46          final String html = DOCTYPE_HTML
47              + "<html>\n"
48              + "  <head>\n"
49              + "    <link href='style1.css'></link>\n"
50              + "    <link href='style2.css' rel='stylesheet'></link>\n"
51              + "    <link href='style3.css' type='text/css'></link>\n"
52              + "    <link href='style4.css' rel='stylesheet' type='text/css'></link>\n"
53              + "    <style>div.x { color: red; }</style>\n"
54              + "    <script>\n"
55              + LOG_TITLE_FUNCTION
56              + "    </script></head>\n"
57              + "  </head>\n"
58              + "  <body onload='log(document.styleSheets.length)'>\n"
59              + "    <style>div.y { color: green; }</style>\n"
60              + "  </body>\n"
61              + "</html>";
62          getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
63  
64          loadPageVerifyTitle2(html);
65      }
66  
67      /**
68       * @throws Exception if an error occurs
69       */
70      @Test
71      @Alerts({"rgb(255, 0, 0)", "rgb(255, 0, 0)"})
72      public void getComputedStyle_Link() throws Exception {
73          final String html = DOCTYPE_HTML
74              + "<html>\n"
75              + "  <head>\n"
76              + "    <link rel='stylesheet' type='text/css' href='" + URL_SECOND + "'/>\n"
77              + "    <script>\n"
78              + LOG_TITLE_FUNCTION
79              + "      function test() {\n"
80              + "        var div = document.getElementById('myDiv');\n"
81              + "        try {\n"
82              + "          log(window.getComputedStyle(div, null).color);\n"
83              + "          var div2 = document.getElementById('myDiv2');\n"
84              + "          log(window.getComputedStyle(div2, null).color);\n"
85              + "        } catch(e) { logEx(e); }\n"
86              + "      }\n"
87              + "    </script>\n"
88              + "  </head>\n"
89              + "  <body onload='test()'>\n"
90              + "    <div id='myDiv'></div>\n"
91              + "    <div id='myDiv2'></div>\n"
92              + "  </body>\n"
93              + "</html>";
94  
95          final String css = "div {color:red}";
96  
97          getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
98          loadPageVerifyTitle2(html);
99      }
100 
101     /**
102      * @throws Exception if an error occurs
103      */
104     @Test
105     @Alerts({"0", "undefined", "undefined", "undefined"})
106     public void arrayIndexOutOfBoundAccess() throws Exception {
107         final String html = DOCTYPE_HTML
108             + "<html>\n"
109             + "  <head>\n"
110             + "    <script>\n"
111             + LOG_TITLE_FUNCTION
112             + "      function test() {\n"
113             + "        log(document.styleSheets.length);\n"
114 
115             + "        try {\n"
116             + "          log(document.styleSheets[0]);\n"
117             + "        } catch(e) { logEx(e); }\n"
118 
119             + "        try {\n"
120             + "          log(document.styleSheets[46]);\n"
121             + "        } catch(e) { logEx(e); }\n"
122 
123             + "        try {\n"
124             + "          log(document.styleSheets[-2]);\n"
125             + "        } catch(e) { logEx(e); }\n"
126             + "      }\n"
127             + "    </script>\n"
128             + "  </head>\n"
129             + "  <body onload='test()'>\n"
130             + "  </body>\n"
131             + "</html>";
132 
133         loadPageVerifyTitle2(html);
134     }
135 
136     /**
137      * Test for a stylesheet link which points to a non-existent file (bug #685).
138      * @throws Exception if an error occurs
139      */
140     @Test
141     @Alerts({"1", "[object CSSStyleSheet]", "[object CSSStyleSheet]"})
142     public void nonExistentStylesheet() throws Exception {
143         final String html = DOCTYPE_HTML
144             + "<html>\n"
145             + "  <head>\n"
146             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
147             + "    <script>\n"
148             + LOG_TITLE_FUNCTION
149             + "      function test() {\n"
150             + "        log(document.styleSheets.length);\n"
151             + "        log(document.styleSheets.item(0));\n"
152             + "        log(document.styleSheets[0]);\n"
153             + "      }\n"
154             + "    </script>\n"
155             + "  </head>\n"
156             + "  <body onload='test()'>abc</body>\n"
157             + "</html>";
158 
159         getMockWebConnection().setDefaultResponse("Not Found", 404, "Not Found", MimeType.TEXT_HTML);
160         loadPageVerifyTitle2(html);
161     }
162 
163     /**
164      * Test for a stylesheet link which points to a broken gzip encoded file (Bug #1434).
165      * @throws Exception if an error occurs
166      */
167     @Test
168     @Alerts({"1", "[object CSSStyleSheet]", "[object CSSStyleSheet]"})
169     public void emptyGZipEncodedStylesheet() throws Exception {
170         final String html = DOCTYPE_HTML
171             + "<html>\n"
172             + "  <head>\n"
173             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
174             + "    <script>\n"
175             + LOG_TITLE_FUNCTION
176             + "      function test() {\n"
177             + "        log(document.styleSheets.length);\n"
178             + "        log(document.styleSheets.item(0));\n"
179             + "        log(document.styleSheets[0]);\n"
180             + "      }\n"
181             + "    </script>\n"
182             + "  </head>\n"
183             + "  <body onload='test()'>abc</body>\n"
184             + "</html>";
185 
186         final String css = "";
187 
188         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
189         final List<NameValuePair> headers = new ArrayList<>();
190         headers.add(new NameValuePair(HttpHeader.CONTENT_LENGTH, "0"));
191         headers.add(new NameValuePair("Content-Encoding", "gzip"));
192         getMockWebConnection().setDefaultResponse(css, 200, "OK", MimeType.TEXT_CSS, headers);
193 
194         loadPageVerifyTitle2(html);
195     }
196 
197     /**
198      * Test for a stylesheet link which points to a broken gzip encoded file (Bug #1389).
199      * @throws Exception if an error occurs
200      */
201     @Test
202     @Alerts({"1", "[object CSSStyleSheet]", "[object CSSStyleSheet]"})
203     public void brokenGZipEncodedStylesheet() throws Exception {
204         final String html = DOCTYPE_HTML
205             + "<html>\n"
206             + "  <head>\n"
207             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
208             + "    <script>\n"
209             + LOG_TITLE_FUNCTION
210             + "      function test() {\n"
211             + "        log(document.styleSheets.length);\n"
212             + "        log(document.styleSheets.item(0));\n"
213             + "        log(document.styleSheets[0]);\n"
214             + "      }\n"
215             + "    </script>\n"
216             + "  </head>\n"
217             + "  <body onload='test()'>abc</body>\n"
218             + "</html>";
219 
220         final String css = "div {color:red}";
221 
222         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
223         final List<NameValuePair> headers = new ArrayList<>();
224         headers.add(new NameValuePair("Content-Encoding", "gzip"));
225         getMockWebConnection().setDefaultResponse(css, 200, "OK", MimeType.TEXT_CSS, headers);
226 
227         loadPageVerifyTitle2(html);
228     }
229 
230     /**
231      * @throws Exception if an error occurs
232      */
233     @Test
234     @Alerts({"1", "1"})
235     @HtmlUnitNYI(CHROME = {"1", "2"},
236             EDGE = {"1", "2"},
237             FF = {"1", "2"},
238             FF_ESR = {"1", "2"})
239     public void dynamicAddedStyleSheet() throws Exception {
240         final String html = DOCTYPE_HTML
241             + "<html>\n"
242             + "  <head>\n"
243             + "    <link rel='stylesheet' type='text/css' href='" + URL_SECOND + "'/>\n"
244             + "    <script>\n"
245             + LOG_TITLE_FUNCTION
246             + "      function test() {\n"
247             + "        log(document.styleSheets.length);\n"
248 
249             + "        var linkTag = document.createElement ('link');\n"
250             + "        linkTag.href = 'new.css';\n"
251             + "        linkTag.rel = 'stylesheet';\n"
252             + "        var head = document.getElementsByTagName ('head')[0];\n"
253             + "        head.appendChild (linkTag);\n"
254 
255             + "        log(document.styleSheets.length);\n"
256             + "      }\n"
257             + "    </script>\n"
258             + "  </head>\n"
259             + "  <body onload='test()'>\n"
260             + "    <div id='myDiv'></div>\n"
261             + "    <div id='myDiv2'></div>\n"
262             + "  </body>\n"
263             + "</html>";
264 
265         final String css = "div {color:red}";
266         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
267 
268         loadPageVerifyTitle2(html);
269     }
270 
271     /**
272      * @throws Exception if an error occurs
273      */
274     @Test
275     @Alerts({"1", "false", "true", "false", "false"})
276     public void in() throws Exception {
277         final String html = DOCTYPE_HTML
278             + "<html>\n"
279             + "  <head>\n"
280             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
281             + "    <script>\n"
282             + LOG_TITLE_FUNCTION
283             + "      function test() {\n"
284             + "        var sheets = document.styleSheets;\n"
285             + "        log(sheets.length);\n"
286             + "        log(-1 in sheets);\n"
287             + "        log(0 in sheets);\n"
288             + "        log(1 in sheets);\n"
289             + "        log(42 in sheets);\n"
290             + "      }\n"
291             + "    </script>\n"
292             + "  </head>\n"
293             + "  <body onload='test()'>abc</body>\n"
294             + "</html>";
295 
296         final String css = "div {color:red}";
297         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
298 
299         loadPageVerifyTitle2(html);
300     }
301 
302 
303     /**
304      * @throws Exception if an error occurs
305      */
306     @Test
307     @Alerts({"1", "undefined", "[object CSSStyleSheet]", "undefined", "undefined"})
308     public void index() throws Exception {
309         final String html = DOCTYPE_HTML
310             + "<html>\n"
311             + "  <head>\n"
312             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
313             + "    <script>\n"
314             + LOG_TITLE_FUNCTION
315             + "      function test() {\n"
316             + "        var sheets = document.styleSheets;\n"
317             + "        log(sheets.length);\n"
318             + "        log(sheets[-1]);\n"
319             + "        log(sheets[0]);\n"
320             + "        log(sheets[1]);\n"
321             + "        log(sheets[42]);\n"
322             + "      }\n"
323             + "    </script>\n"
324             + "  </head>\n"
325             + "  <body onload='test()'>abc</body>\n"
326             + "</html>";
327 
328         final String css = "div {color:red}";
329         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
330 
331         loadPageVerifyTitle2(html);
332     }
333 
334 
335     /**
336      * @throws Exception if an error occurs
337      */
338     @Test
339     @Alerts({"1", "null", "[object CSSStyleSheet]", "null", "null"})
340     public void item() throws Exception {
341         final String html = DOCTYPE_HTML
342             + "<html>\n"
343             + "  <head>\n"
344             + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
345             + "    <script>\n"
346             + LOG_TITLE_FUNCTION
347             + "      function test() {\n"
348             + "        var sheets = document.styleSheets;\n"
349             + "        log(sheets.length);\n"
350             + "        log(sheets.item(-1));\n"
351             + "        log(sheets.item(0));\n"
352             + "        log(sheets.item(1));\n"
353             + "        log(sheets.item(42));\n"
354             + "      }\n"
355             + "    </script>\n"
356             + "  </head>\n"
357             + "  <body onload='test()'>abc</body>\n"
358             + "</html>";
359 
360         final String css = "div {color:red}";
361         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
362 
363         loadPageVerifyTitle2(html);
364     }
365 
366     /**
367      * @throws Exception if an error occurs
368      */
369     @Test
370     @Alerts({"true", "false", "false"})
371     public void equivalentValues() throws Exception {
372         final String html = DOCTYPE_HTML
373               + "<html>\n"
374               + "  <head>\n"
375               + "    <link rel='stylesheet' type='text/css' href='foo.css'/>\n"
376               + "    <script>\n"
377               + LOG_TITLE_FUNCTION
378               + "      function test() {\n"
379               + "        var sheets = document.styleSheets;\n"
380               + "        log(sheets == document.styleSheets);\n"
381               + "        log(sheets == null);\n"
382               + "        log(null == sheets);\n"
383               + "      }\n"
384               + "    </script>\n"
385               + "  </head>\n"
386               + "  <body onload='test()'>abc</body>\n"
387               + "</html>";
388 
389         final String css = "div {color:red}";
390         getMockWebConnection().setDefaultResponse(css, MimeType.TEXT_CSS);
391 
392         loadPageVerifyTitle2(html);
393     }
394 }