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 org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.htmlunit.junit.annotation.HtmlUnitNYI;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for {@link CSSPageRule}.
24   *
25   * @author Frank Danek
26   * @author Ronald Brill
27   */
28  public class CSSPageRuleTest extends WebDriverTestCase {
29  
30      /**
31       * @throws Exception if an error occurs
32       */
33      @Test
34      @Alerts("TypeError")
35      public void ctor() throws Exception {
36          final String html = DOCTYPE_HTML
37              + "<html><body>\n"
38              + LOG_TEXTAREA
39              + "<script>\n"
40              + LOG_TEXTAREA_FUNCTION
41              + "try {\n"
42              + "  var rule = new CSSPageRule();\n"
43              + "  log(rule);\n"
44              + "} catch(e) { logEx(e); }\n"
45              + "</script></body></html>";
46  
47          loadPageVerifyTextArea2(html);
48      }
49  
50      /**
51       * @throws Exception if an error occurs
52       */
53      @Test
54      @Alerts({"[object CSSPageRule]", "[object CSSPageRule]"})
55      public void scriptableToString() throws Exception {
56          final String html = DOCTYPE_HTML
57              + "<html><body>\n"
58  
59              + "<style>\n"
60              + "  @page { margin: 1cm; };\n"
61              + "</style>\n"
62  
63              + "<script>\n"
64              + LOG_TITLE_FUNCTION
65              + "  var styleSheet = document.styleSheets[0];\n"
66              + "  var rule = styleSheet.cssRules[0];\n"
67              + "  log(Object.prototype.toString.call(rule));\n"
68              + "  log(rule);\n"
69              + "</script>\n"
70  
71              + "</body></html>";
72  
73          loadPageVerifyTitle2(html);
74      }
75  
76      /**
77       * @throws Exception if an error occurs
78       */
79      @Test
80      @Alerts("@page { margin: 1cm; }")
81      public void cssText() throws Exception {
82          final String html = DOCTYPE_HTML
83              + "<html><body>\n"
84  
85              + LOG_TEXTAREA
86  
87              + "<style>\n"
88              + "  @page { margin: 1cm; }\n"
89              + "</style>\n"
90  
91              + "<script>\n"
92              + LOG_TEXTAREA_FUNCTION
93              + "  var styleSheet = document.styleSheets[0];\n"
94              + "  var rule = styleSheet.cssRules[0];\n"
95              + "  log(rule.cssText);\n"
96              + "</script>\n"
97  
98              + "</body></html>";
99  
100         loadPageVerifyTextArea2(html);
101     }
102 
103     /**
104      * @throws Exception if an error occurs
105      */
106     @Test
107     @Alerts("@page { }")
108     public void cssTextEmpty() throws Exception {
109         final String html = DOCTYPE_HTML
110             + "<html><body>\n"
111 
112             + LOG_TEXTAREA
113 
114             + "<style>\n"
115             + "  @page { }\n"
116             + "</style>\n"
117 
118             + "<script>\n"
119             + LOG_TEXTAREA_FUNCTION
120             + "  var styleSheet = document.styleSheets[0];\n"
121             + "  var rule = styleSheet.cssRules[0];\n"
122             + "  log(rule.cssText);\n"
123             + "</script>\n"
124 
125             + "</body></html>";
126 
127         loadPageVerifyTextArea2(html);
128     }
129 
130     /**
131      * @throws Exception if an error occurs
132      */
133     @Test
134     @Alerts("@page { margin-left: 4cm; margin-right: 3cm; }")
135     public void cssTextMultipleRules() throws Exception {
136         final String html = DOCTYPE_HTML
137             + "<html><body>\n"
138 
139             + LOG_TEXTAREA
140 
141             + "<style>\n"
142             + "  @page {   margin-left:4cm;margin-right:  3cm; }\n"
143             + "</style>\n"
144 
145             + "<script>\n"
146             + LOG_TEXTAREA_FUNCTION
147             + "  var styleSheet = document.styleSheets[0];\n"
148             + "  var rule = styleSheet.cssRules[0];\n"
149             + "  log(rule.cssText);\n"
150             + "</script>\n"
151 
152             + "</body></html>";
153 
154         loadPageVerifyTextArea2(html);
155     }
156 
157     /**
158      * @throws Exception if an error occurs
159      */
160     @Test
161     @Alerts("@page { margin: 1cm; }")
162     public void cssTextSet() throws Exception {
163         final String html = DOCTYPE_HTML
164             + "<html><body>\n"
165 
166             + LOG_TEXTAREA
167 
168             + "<style>\n"
169             + "  @page { margin: 1cm; }\n"
170             + "</style>\n"
171 
172             + "<script>\n"
173             + LOG_TEXTAREA_FUNCTION
174             + "  var styleSheet = document.styleSheets[0];\n"
175             + "  var rule = styleSheet.cssRules[0];\n"
176             + "  try {"
177             + "    rule.cssText = '@page { margin: 2cm; }';\n"
178             + "    log(rule.cssText);\n"
179             + "  } catch(e) {\n"
180             + "    logEx(e);\n"
181             + "  }\n"
182             + "</script>\n"
183 
184             + "</body></html>";
185 
186         loadPageVerifyTextArea2(html);
187     }
188 
189     /**
190      * @throws Exception if an error occurs
191      */
192     @Test
193     @Alerts("null")
194     public void parentRule() throws Exception {
195         final String html = DOCTYPE_HTML
196             + "<html><body>\n"
197 
198             + "<style>\n"
199             + "  @page { margin: 1cm; }\n"
200             + "</style>\n"
201 
202             + "<script>\n"
203             + LOG_TITLE_FUNCTION
204             + "  var styleSheet = document.styleSheets[0];\n"
205             + "  var rule = styleSheet.cssRules[0];\n"
206             + "  log(rule.parentRule);\n"
207             + "</script>\n"
208 
209             + "</body></html>";
210 
211         loadPageVerifyTitle2(html);
212     }
213 
214     /**
215      * @throws Exception if an error occurs
216      */
217     @Test
218     @Alerts("null")
219     public void parentRuleSet() throws Exception {
220         final String html = DOCTYPE_HTML
221             + "<html><body>\n"
222 
223             + "<style>\n"
224             + "  @page { margin: 1cm; }\n"
225             + "</style>\n"
226 
227             + "<script>\n"
228             + LOG_TITLE_FUNCTION
229             + "  var styleSheet = document.styleSheets[0];\n"
230             + "  var rule = styleSheet.cssRules[0];\n"
231             + "  try {"
232             + "    rule.parentRule = rule;\n"
233             + "    log(rule.parentRule);\n"
234             + "  } catch(e) {\n"
235             + "    logEx(e);\n"
236             + "  }\n"
237             + "</script>\n"
238 
239             + "</body></html>";
240 
241         loadPageVerifyTitle2(html);
242     }
243 
244     /**
245      * @throws Exception if an error occurs
246      */
247     @Test
248     @Alerts("[object CSSStyleSheet]")
249     public void parentStyleSheet() throws Exception {
250         final String html = DOCTYPE_HTML
251             + "<html><body>\n"
252 
253             + "<style>\n"
254             + "  @page { margin: 1cm; }\n"
255             + "</style>\n"
256 
257             + "<script>\n"
258             + LOG_TITLE_FUNCTION
259             + "  var styleSheet = document.styleSheets[0];\n"
260             + "  var rule = styleSheet.cssRules[0];\n"
261             + "  log(rule.parentStyleSheet);\n"
262             + "</script>\n"
263 
264             + "</body></html>";
265 
266         loadPageVerifyTitle2(html);
267     }
268 
269     /**
270      * @throws Exception if an error occurs
271      */
272     @Test
273     @Alerts("[object CSSStyleSheet]")
274     public void parentStyleSheetSet() throws Exception {
275         final String html = DOCTYPE_HTML
276             + "<html><body>\n"
277 
278             + "<style>\n"
279             + "  @page { margin: 1cm; }\n"
280             + "</style>\n"
281 
282             + "<script>\n"
283             + LOG_TITLE_FUNCTION
284             + "  var styleSheet = document.styleSheets[0];\n"
285             + "  var rule = styleSheet.cssRules[0];\n"
286             + "  try {"
287             + "    rule.parentStyleSheet = null;\n"
288             + "    log(rule.parentStyleSheet);\n"
289             + "  } catch(e) {\n"
290             + "    logEx(e);\n"
291             + "  }\n"
292             + "</script>\n"
293 
294             + "</body></html>";
295 
296         loadPageVerifyTitle2(html);
297     }
298 
299     /**
300      * @throws Exception if an error occurs
301      */
302     @Test
303     @Alerts("")
304     public void selectorTextEmpty() throws Exception {
305         final String html = DOCTYPE_HTML
306             + "<html><body>\n"
307 
308             + "<style>\n"
309             + "  @page { margin: 1cm; }\n"
310             + "</style>\n"
311 
312             + "<script>\n"
313             + LOG_TITLE_FUNCTION
314             + "  var styleSheet = document.styleSheets[0];\n"
315             + "  var rule = styleSheet.cssRules[0];\n"
316             + "  try {"
317             + "    log(rule.selectorText);\n"
318             + "  } catch(e) {\n"
319             + "    logEx(e);\n"
320             + "  }\n"
321             + "</script>\n"
322 
323             + "</body></html>";
324 
325         loadPageVerifyTitle2(html);
326     }
327 
328     /**
329      * @throws Exception if an error occurs
330      */
331     @Test
332     @Alerts(":first")
333     public void selectorText() throws Exception {
334         final String html = DOCTYPE_HTML
335             + "<html><body>\n"
336 
337             + "<style>\n"
338             + "  @page :first { margin: 1cm; }\n"
339             + "</style>\n"
340 
341             + "<script>\n"
342             + LOG_TITLE_FUNCTION
343             + "  var styleSheet = document.styleSheets[0];\n"
344             + "  var rule = styleSheet.cssRules[0];\n"
345             + "  try {"
346             + "    log(rule.selectorText);\n"
347             + "  } catch(e) {\n"
348             + "    logEx(e);\n"
349             + "  }\n"
350             + "</script>\n"
351 
352             + "</body></html>";
353 
354         loadPageVerifyTitle2(html);
355     }
356 
357     /**
358      * @throws Exception if an error occurs
359      */
360     @Test
361     @Alerts(":first")
362     public void selectorTextCaseInsensitive() throws Exception {
363         final String html = DOCTYPE_HTML
364             + "<html><body>\n"
365 
366             + "<style>\n"
367             + "  @page :FiRsT { margin: 1cm; }\n"
368             + "</style>\n"
369 
370             + "<script>\n"
371             + LOG_TITLE_FUNCTION
372             + "  var styleSheet = document.styleSheets[0];\n"
373             + "  var rule = styleSheet.cssRules[0];\n"
374             + "  try {"
375             + "    log(rule.selectorText);\n"
376             + "  } catch(e) {\n"
377             + "    logEx(e);\n"
378             + "  }\n"
379             + "</script>\n"
380 
381             + "</body></html>";
382 
383         loadPageVerifyTitle2(html);
384     }
385 
386     /**
387      * @throws Exception if an error occurs
388      */
389     @Test
390     @Alerts({":first", ":left"})
391     public void selectorTextSet() throws Exception {
392         final String html = DOCTYPE_HTML
393             + "<html><body>\n"
394 
395             + "<style>\n"
396             + "  @page :first { margin: 1cm; }\n"
397             + "</style>\n"
398 
399             + "<script>\n"
400             + LOG_TITLE_FUNCTION
401             + "  var styleSheet = document.styleSheets[0];\n"
402             + "  var rule = styleSheet.cssRules[0];\n"
403             + "  try {"
404             + "    log(rule.selectorText);\n"
405             + "    rule.selectorText = ':left';\n"
406             + "    log(rule.selectorText);\n"
407             + "  } catch(e) {\n"
408             + "    logEx(e);\n"
409             + "  }\n"
410             + "</script>\n"
411 
412             + "</body></html>";
413 
414         loadPageVerifyTitle2(html);
415     }
416 
417     /**
418      * @throws Exception if an error occurs
419      */
420     @Test
421     @Alerts({":first", "null"})
422     public void selectorTextSetNull() throws Exception {
423         final String html = DOCTYPE_HTML
424             + "<html><body>\n"
425 
426             + "<style>\n"
427             + "  @page :first { margin: 1cm; }\n"
428             + "</style>\n"
429 
430             + "<script>\n"
431             + LOG_TITLE_FUNCTION
432             + "  var styleSheet = document.styleSheets[0];\n"
433             + "  var rule = styleSheet.cssRules[0];\n"
434             + "  try {"
435             + "    log(rule.selectorText);\n"
436             + "    rule.selectorText = null;\n"
437             + "    log(rule.selectorText);\n"
438             + "  } catch(e) {\n"
439             + "    logEx(e);\n"
440             + "  }\n"
441             + "</script>\n"
442 
443             + "</body></html>";
444 
445         loadPageVerifyTitle2(html);
446     }
447 
448     /**
449      * @throws Exception if an error occurs
450      */
451     @Test
452     @Alerts({":first", ""})
453     public void selectorTextSetEmpty() throws Exception {
454         final String html = DOCTYPE_HTML
455             + "<html><body>\n"
456 
457             + "<style>\n"
458             + "  @page :first { margin: 1cm; }\n"
459             + "</style>\n"
460 
461             + "<script>\n"
462             + LOG_TITLE_FUNCTION
463             + "  var styleSheet = document.styleSheets[0];\n"
464             + "  var rule = styleSheet.cssRules[0];\n"
465             + "  try {"
466             + "    log(rule.selectorText);\n"
467             + "    rule.selectorText = '';\n"
468             + "    log(rule.selectorText);\n"
469             + "  } catch(e) {\n"
470             + "    logEx(e);\n"
471             + "  }\n"
472             + "</script>\n"
473 
474             + "</body></html>";
475 
476         loadPageVerifyTitle2(html);
477     }
478 
479     /**
480      * @throws Exception if an error occurs
481      */
482     @Test
483     @Alerts({":first", ":first"})
484     public void selectorTextSetInvalid() throws Exception {
485         final String html = DOCTYPE_HTML
486             + "<html><body>\n"
487 
488             + "<style>\n"
489             + "  @page :first { margin: 1cm; }\n"
490             + "</style>\n"
491 
492             + "<script>\n"
493             + LOG_TITLE_FUNCTION
494             + "  var styleSheet = document.styleSheets[0];\n"
495             + "  var rule = styleSheet.cssRules[0];\n"
496             + "  try {"
497             + "    log(rule.selectorText);\n"
498             + "    rule.selectorText = ':grey';\n"
499             + "    log(rule.selectorText);\n"
500             + "  } catch(e) {\n"
501             + "    logEx(e);\n"
502             + "  }\n"
503             + "</script>\n"
504 
505             + "</body></html>";
506 
507         loadPageVerifyTitle2(html);
508     }
509 
510     /**
511      * @throws Exception if an error occurs
512      */
513     @Test
514     @Alerts({":first", ":left"})
515     public void selectorTextSetCaseInsensitive() throws Exception {
516         final String html = DOCTYPE_HTML
517             + "<html><body>\n"
518 
519             + "<style>\n"
520             + "  @page :first { margin: 1cm; }\n"
521             + "</style>\n"
522 
523             + "<script>\n"
524             + LOG_TITLE_FUNCTION
525             + "  var styleSheet = document.styleSheets[0];\n"
526             + "  var rule = styleSheet.cssRules[0];\n"
527             + "  try {"
528             + "    log(rule.selectorText);\n"
529             + "    rule.selectorText = ':LeFt';\n"
530             + "    log(rule.selectorText);\n"
531             + "  } catch(e) {\n"
532             + "    logEx(e);\n"
533             + "  }\n"
534             + "</script>\n"
535 
536             + "</body></html>";
537 
538         loadPageVerifyTitle2(html);
539     }
540 
541     /**
542      * @throws Exception if an error occurs
543      */
544     @Test
545     @Alerts(DEFAULT = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]", "4", "[object CSSPageRule]",
546                        "margin: 1cm;",
547                        "string margin-top",
548                        "string margin-right",
549                        "string margin-bottom",
550                        "string margin-left"},
551             FF = {"[object CSSPageDescriptors]", "[object CSSPageDescriptors]", "4", "[object CSSPageRule]",
552                   "margin: 1cm;",
553                   "string margin-top",
554                   "string margin-right",
555                   "string margin-bottom",
556                   "string margin-left"},
557             FF_ESR = {"[object CSSPageDescriptors]", "[object CSSPageDescriptors]", "4", "[object CSSPageRule]",
558                       "margin: 1cm;",
559                       "string margin-top",
560                       "string margin-right",
561                       "string margin-bottom",
562                       "string margin-left"})
563     @HtmlUnitNYI(CHROME = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]",
564                            "1", "[object CSSPageRule]", "margin: 1cm;", "string margin: 1cm"},
565             EDGE = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]",
566                     "1", "[object CSSPageRule]", "margin: 1cm;", "string margin: 1cm"},
567             FF = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]",
568                   "1", "[object CSSPageRule]", "margin: 1cm;", "string margin: 1cm"},
569             FF_ESR = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]",
570                       "1", "[object CSSPageRule]", "margin: 1cm;", "string margin: 1cm"})
571     // FIXME FF returns CSS2Properties vs. default returns CSSStyleDeclaration :(
572     public void style() throws Exception {
573         final String html = DOCTYPE_HTML
574             + "<html><body>\n"
575 
576             + "<style>\n"
577             + "  @page { margin: 1cm; }\n"
578             + "</style>\n"
579 
580             + "<script>\n"
581             + LOG_TITLE_FUNCTION
582             + "  var styleSheet = document.styleSheets[0];\n"
583             + "  var rule = styleSheet.cssRules[0];\n"
584             + "  var style = rule.style;\n"
585             + "  log(Object.prototype.toString.call(style));\n"
586             + "  log(style);\n"
587             + "  log(style.length);\n"
588             + "  log(style.parentRule);\n"
589             + "  log(style.cssText);\n"
590             + "  for (var i = 0; i < style.length; i++) {\n"
591             + "    log(typeof style.item(i) + ' ' + style.item(i));\n"
592             + "  }\n"
593             + "</script>\n"
594 
595             + "</body></html>";
596 
597         loadPageVerifyTitle2(html);
598     }
599 
600     /**
601      * @throws Exception if an error occurs
602      */
603     @Test
604     @Alerts(DEFAULT = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]", "0", "[object CSSPageRule]", ""},
605             FF = {"[object CSSPageDescriptors]", "[object CSSPageDescriptors]", "0", "[object CSSPageRule]", ""},
606             FF_ESR = {"[object CSSPageDescriptors]", "[object CSSPageDescriptors]", "0", "[object CSSPageRule]", ""})
607     @HtmlUnitNYI(FF = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]", "0", "[object CSSPageRule]", ""},
608             FF_ESR = {"[object CSSStyleDeclaration]", "[object CSSStyleDeclaration]", "0", "[object CSSPageRule]", ""})
609     public void styleEmpty() throws Exception {
610         final String html = DOCTYPE_HTML
611             + "<html><body>\n"
612 
613             + "<style>\n"
614             + "  @page { }\n"
615             + "</style>\n"
616 
617             + "<script>\n"
618             + LOG_TITLE_FUNCTION
619             + "  var styleSheet = document.styleSheets[0];\n"
620             + "  var rule = styleSheet.cssRules[0];\n"
621             + "  var style = rule.style;\n"
622             + "  log(Object.prototype.toString.call(style));\n"
623             + "  log(style);\n"
624             + "  log(style.length);\n"
625             + "  log(style.parentRule);\n"
626             + "  log(style.cssText);\n"
627             + "  for (var i = 0; i < style.length; i++) {\n"
628             + "    log(style.item(i));\n"
629             + "  }\n"
630             + "</script>\n"
631 
632             + "</body></html>";
633 
634         loadPageVerifyTitle2(html);
635     }
636 }