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