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;
16  
17  import java.net.URL;
18  
19  import org.htmlunit.WebDriverTestCase;
20  import org.htmlunit.junit.BrowserRunner;
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.htmlunit.junit.annotation.BuggyWebDriver;
23  import org.htmlunit.junit.annotation.HtmlUnitNYI;
24  import org.htmlunit.util.MimeType;
25  import org.junit.Test;
26  import org.junit.runner.RunWith;
27  import org.openqa.selenium.By;
28  import org.openqa.selenium.WebDriver;
29  import org.openqa.selenium.WebDriverException;
30  import org.openqa.selenium.WebElement;
31  
32  /**
33   * Same scope as {@link JavaScriptEngineTest} but extending {@link WebDriverTestCase}.
34   *
35   * @author Marc Guillemot
36   * @author Ahmed Ashour
37   * @author Frank Danek
38   * @author Ronald Brill
39   */
40  @RunWith(BrowserRunner.class)
41  public class JavaScriptEngine2Test extends WebDriverTestCase {
42  
43      /**
44       * All browsers except Opera seem to have a single JS execution thread for all windows.
45       * @throws Exception if the test fails
46       */
47      @Test
48      public void jsRunSingleThreadedBrowserWide() throws Exception {
49          final String html = DOCTYPE_HTML
50              + "<html><head><script>\n"
51              + "function test(prefix) {\n"
52              + "  parent.document.getElementById('theArea').value += prefix + ' start\\n';\n"
53              + "  var end = new Date().valueOf() + 1 * 1000;\n"
54              + "  var t = [];\n"
55              + "  while (new Date().valueOf() < end) {\n"
56              + "    var x = document.createElement('iframe');\n"
57              + "    t.push(x);\n"
58              + "  }\n"
59              + "  parent.document.getElementById('theArea').value += prefix + ' end\\n';\n"
60              + "}\n"
61              + "function checkResults() {\n"
62              + "  var value = document.getElementById('theArea').value;\n"
63              + "  var lines = value.split('\\n');\n"
64              + "  if (lines.length < 5)\n"
65              + "    setTimeout(checkResults, 100); // not yet ready, check later\n"
66              + "  value = value.replace(/frame \\d /gi, '').replace(/\\W/gi, '');\n"
67              + "  var singleThreaded = (value == 'startendstartend');\n"
68              + "  document.getElementById('result').innerHTML = (singleThreaded ? 'single threaded' : 'in parallel');\n"
69              + "}\n"
70              + "function doTest() {\n"
71              + "  parent.document.getElementById('theArea').value = '';\n"
72              + "  document.getElementById('frame1').contentWindow.setTimeout(function() {test('frame 1'); }, 10);\n"
73              + "  document.getElementById('frame2').contentWindow.setTimeout(function() {test('frame 2'); }, 10);\n"
74              + "  setTimeout(checkResults, 1000);\n"
75              + "}\n"
76              + "</script></head>\n"
77              + "<body onload='doTest()'>\n"
78              + "<iframe id='frame1' src='about:blank'></iframe>\n"
79              + "<iframe id='frame2' src='about:blank'></iframe>\n"
80              + "<textarea id='theArea' rows='5'></textarea>\n"
81              + "script execution occured: <span id='result'></span>\n"
82              + "</body></html>";
83  
84          final WebDriver driver = loadPage2(html);
85          final WebElement element = driver.findElement(By.id("result"));
86  
87          // give time to the script to execute: normally ~2 seconds when scripts are run sequentially
88          int nbWait = 0;
89          while (element.getText().isEmpty()) {
90              Thread.sleep(100);
91              if (nbWait++ > 50) {
92                  break;
93              }
94          }
95  
96          assertEquals("single threaded", element.getText());
97      }
98  
99      /**
100      * @throws Exception if the test fails
101      */
102     @Test
103     @Alerts({"true", "false", "false", "true"})
104     public void functionCaller() throws Exception {
105         final String html = DOCTYPE_HTML
106             + "<html><head>\n"
107             + "<script>\n"
108             + LOG_TITLE_FUNCTION
109             + "function myFunc() {\n"
110             + "  log(myFunc.caller == null);\n"
111             + "  log(myFunc.caller == foo);\n"
112             + "}\n"
113             + "myFunc()\n"
114             + "function foo() { myFunc() }\n"
115             + "foo()\n"
116             + "</script>\n"
117             + "</head><body></body></html>";
118 
119         loadPageVerifyTitle2(html);
120     }
121 
122     /**
123      * @throws Exception if the test fails
124      */
125     @Test
126     @Alerts({"in goo", "in hoo", "in foo"})
127     public void functionDeclaredForwardInBlock() throws Exception {
128         final String html = DOCTYPE_HTML
129             + "<html><head></head><body>\n"
130             + "<script>\n"
131             + LOG_TITLE_FUNCTION
132             + "  if (true) {\n"
133             + "    goo();\n"
134             + "    function hoo() { log('in hoo'); }\n"
135             + "    try {\n"
136             + "      hoo();\n"
137             + "      foo();\n"
138             + "    } catch(e) {\n"
139             + "      log('foo error');\n"
140             + "    }\n"
141             + "    function foo() { log('in foo'); }\n"
142             + "  }\n"
143             + "  function goo() { log('in goo'); }\n"
144             + "</script>\n"
145             + "</body></html>";
146 
147         loadPageVerifyTitle2(html);
148     }
149 
150     /**
151      * @throws Exception if the test fails
152      */
153     @Test
154     @Alerts({"undefined", "function foo() {}", "function foo() {}", "function foo() {}"})
155     @HtmlUnitNYI(CHROME = {"function foo() {}", "function foo() {}", "function foo() {}", "function foo() {}"},
156             EDGE = {"function foo() {}", "function foo() {}", "function foo() {}", "function foo() {}"},
157             FF = {"function foo() {}", "function foo() {}", "function foo() {}", "function foo() {}"},
158             FF_ESR = {"function foo() {}", "function foo() {}", "function foo() {}", "function foo() {}"})
159     public void variableNotDefined() throws Exception {
160         final String html = DOCTYPE_HTML
161             + "<html><head></head><body>\n"
162             + "<script>\n"
163             + LOG_TITLE_FUNCTION
164             + "if (true) {\n"
165             + "  try {\n"
166             + "    log(window.foo);\n"
167             + "    log(foo);\n"
168             + "  } catch(e) {\n"
169             + "    log('foo error');\n"
170             + "  }\n"
171             + "  function foo() {}\n"
172             + "  try {\n"
173             + "    log(window.foo);\n"
174             + "    log(foo);\n"
175             + "  } catch(e) {\n"
176             + "    log('foo error');\n"
177             + "  }\n"
178             + "}\n"
179             + "</script>\n"
180             + "</body></html>";
181 
182         loadPageVerifyTitle2(html);
183     }
184 
185     /**
186      * @throws Exception if the test fails
187      */
188     @Test
189     @Alerts({"undefined", "foo error", "undefined", "foo error"})
190     public void variableNotDefinedExpression() throws Exception {
191         final String html = DOCTYPE_HTML
192             + "<html><head></head><body>\n"
193             + "<script>\n"
194             + LOG_TITLE_FUNCTION
195             + "if (true) {\n"
196             + "  try {\n"
197             + "    log(window.foo);\n"
198             + "    log(foo);\n"
199             + "  } catch(e) {\n"
200             + "    log('foo error');\n"
201             + "  }\n"
202             + "  var fo = function foo() {}\n"
203             + "  try {\n"
204             + "    log(window.foo);\n"
205             + "    log(foo);\n"
206             + "  } catch(e) {\n"
207             + "    log('foo error');\n"
208             + "  }\n"
209             + "}\n"
210             + "</script>\n"
211             + "</body></html>";
212 
213         loadPageVerifyTitle2(html);
214     }
215 
216     /**
217      * @throws Exception if the test fails
218      */
219     @Test
220     @Alerts({"function Window() { [native code] }", "function Window() { [native code] }", "true",
221              "function HTMLDocument() { [native code] }", "function HTMLDocument() { [native code] }",
222              "true", "function"})
223     public void constructor() throws Exception {
224         final String html = DOCTYPE_HTML
225             + "<html><head></head><body>\n"
226             + "<script>\n"
227             + LOG_TITLE_FUNCTION
228             + "  try { log(Window); } catch(e) { log('ex window'); }\n"
229             + "  log(window.constructor);\n"
230             + "  try {\n"
231             + "    log(window.constructor === Window);\n"
232             + "  } catch(e) {\n"
233             + "    log('ex win const');\n"
234             + "  }\n"
235 
236             + "  try { log(HTMLDocument); } catch(e) { log('ex doc'); }\n"
237             + "  log(document.constructor);\n"
238             + "  try {\n"
239             + "    log(document.constructor === HTMLDocument);\n"
240             + "  } catch(e) {\n"
241             + "    log('exception doc const');\n"
242             + "  }\n"
243             + "  log(typeof new Object().constructor);\n"
244             + "</script>\n"
245             + "</body></html>";
246 
247         loadPageVerifyTitle2(html);
248     }
249 
250     /**
251      * @throws Exception if the test fails
252      */
253     @Test
254     @Alerts("ReferenceError")
255     public void packages() throws Exception {
256         object("Packages");
257     }
258 
259     /**
260      * @throws Exception if the test fails
261      */
262     @Test
263     @Alerts("ReferenceError")
264     public void java() throws Exception {
265         object("java");
266     }
267 
268     /**
269      * @throws Exception if the test fails
270      */
271     @Test
272     @Alerts("undefined")
273     public void object_getClass() throws Exception {
274         object("window.getClass");
275     }
276 
277     private void object(final String object) throws Exception {
278         final String html = DOCTYPE_HTML
279             + "<html><head></head><body>\n"
280             + "<script>\n"
281             + LOG_TITLE_FUNCTION
282             + "try {\n"
283             + "  log(" + object + ");\n"
284             + "} catch(e) {\n"
285             + "  logEx(e);\n"
286             + "}\n"
287             + "</script>\n"
288             + "</body></html>";
289 
290         loadPageVerifyTitle2(html);
291     }
292 
293     /**
294      * @throws Exception if the test fails
295      */
296     @Test
297     @Alerts({"function", "function"})
298     public void inline() throws Exception {
299         final String html = DOCTYPE_HTML
300                 + "<html><head>\n"
301                 + "<script>\n"
302                 + LOG_TITLE_FUNCTION
303                 + "log(typeof Array.prototype.filter);\n"
304                 + "  function test() {\n"
305                 + "    log(typeof Array.prototype.filter);\n"
306                 + "  }\n"
307                 + "</script></head><body onload='test()'>\n"
308                 + "</body></html>";
309 
310         loadPageVerifyTitle2(html);
311     }
312 
313     /**
314      * @throws Exception if the test fails
315      */
316     @Test
317     @Alerts("found")
318     public void enumerateMethods() throws Exception {
319         final String html = DOCTYPE_HTML
320             + "<html><head>\n"
321             + "<script>\n"
322             + LOG_TITLE_FUNCTION
323             + "  function test() {\n"
324             + "    for (var x in document) {\n"
325             + "      if (x == 'getElementById')\n"
326             + "        log('found');\n"
327             + "    }\n"
328             + "  }\n"
329             + "</script></head><body onload='test()'>\n"
330             + "</body></html>";
331 
332         loadPageVerifyTitle2(html);
333     }
334 
335     /**
336      * Unit tests for bug 2531218 reported by Rhino as
337      * <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=477604">Bug 477604 -
338      * Array.concat causes ArrayIndexOutOfBoundException with non dense array</a>.
339      * @throws Exception if the test fails
340      */
341     @Test
342     @Alerts("3")
343     public void array_concat() throws Exception {
344         final String html = DOCTYPE_HTML
345             + "<html><head>\n"
346             + "<script>\n"
347             + LOG_TITLE_FUNCTION
348             + "  function test() {\n"
349             + "    var a = [1, 2, 3];\n"
350             + "    for (var i = 10; i < 20; i++)\n"
351             + "      a[i] = 't' + i;\n"
352             + "    var b = [1, 2, 3];\n"
353             + "    b.concat(a);\n"
354             + "    log(b.length);\n"
355             + "  }\n"
356             + "</script></head><body onload='test()'>\n"
357             + "</body></html>";
358 
359         loadPageVerifyTitle2(html);
360     }
361 
362     /**
363      * @throws Exception if the test fails
364      */
365     @Test
366     @Alerts("function f() {}")
367     public void function_toStringValue() throws Exception {
368         final String html = DOCTYPE_HTML
369             + "<html><head>\n"
370             + "<script>\n"
371             + LOG_TITLE_FUNCTION
372             + "  function f() {}\n"
373             + "  function test() {\n"
374             + "    log(String(f));\n"
375             + "  }\n"
376             + "</script></head><body onload='test()'>\n"
377             + "</body></html>";
378 
379         loadPageVerifyTitle2(html);
380     }
381 
382     /**
383      * @throws Exception if the test fails
384      */
385     @Test
386     @Alerts("WebDriverException thrown")
387     @BuggyWebDriver("WebDriverException NOT thrown")
388     public void function_object_method() throws Exception {
389         final String html = DOCTYPE_HTML
390                 + "<html><head>\n"
391                 + "<script>\n"
392                 + "  try {\n"
393                 + "    log('1');\n"
394                 + "    function document.onclick() {\n"
395                 + "      log('hi');\n"
396                 + "    }\n"
397                 + "    log('2');\n"
398                 + "  } catch(e) { log(e); }\n"
399                 + "</script>\n"
400                 + "</head>\n"
401                 + "<body>\n"
402                 + "</body></html>";
403 
404         final String[] expected = getExpectedAlerts();
405 
406         try {
407             setExpectedAlerts();
408             loadPageWithAlerts2(html);
409 
410             // at the moment we do not get the syntax exception when running in selenium
411             assertEquals("WebDriverException NOT thrown", expected[0]);
412         }
413         catch (final WebDriverException e) {
414             assertEquals("WebDriverException thrown", expected[0]);
415         }
416     }
417 
418     /**
419      * @throws Exception if the test fails
420      */
421     @Test
422     @Alerts("that's it")
423     public void quoteAsUnicodeInString() throws Exception {
424         final String html = DOCTYPE_HTML
425             + "<html><head>\n"
426             + "<script>\n"
427             + LOG_TITLE_FUNCTION
428             + "log('that\\x27s it');\n"
429             + "</script></head><body>\n"
430             + "</body></html>";
431 
432         loadPageVerifyTitle2(html);
433     }
434 
435     /**
436      * @throws Exception if the test fails
437      */
438     @Test
439     @Alerts(DEFAULT = "RangeError",
440             FF = "InternalError/InternalError",
441             FF_ESR = "InternalError/InternalError")
442     @HtmlUnitNYI(CHROME = "InternalError/InternalError",
443             EDGE = "InternalError/InternalError")
444     public void recursion() throws Exception {
445         final String html = DOCTYPE_HTML
446             + "<html><head><script>\n"
447             + "  function recurse(c) {\n"
448             + LOG_TITLE_FUNCTION
449             + "    try {\n"
450             + "      recurse(c++);\n"
451             + "    } catch(e) { logEx(e); }\n"
452             + "  }\n"
453             + "</script></head>\n"
454             + "<body onload='recurse(1)'>\n"
455             + "</body></html>";
456 
457         loadPageVerifyTitle2(html);
458     }
459 
460     /**
461      * String value of native functions starts with \n on IE.
462      * @throws Exception if the test fails
463      */
464     @Test
465     @Alerts({"0", "false", "0"})
466     public void nativeFunction_toStringValue() throws Exception {
467         final String html = DOCTYPE_HTML
468             + "<html><head>\n"
469             + "<script>\n"
470             + LOG_TITLE_FUNCTION
471             + "  function test() {\n"
472             + "    log(String(window.alert).indexOf('function'));\n"
473             + "    log(String(window.alert).charAt(0) == '\\n');\n"
474             + "    log(String(document.getElementById).indexOf('function'));\n"
475             + "  }\n"
476             + "</script></head><body onload='test()'>\n"
477             + "</body></html>";
478 
479         loadPageVerifyTitle2(html);
480     }
481 
482     /**
483      * Regression test for bug <a href="https://sf.net/tracker/?func=detail&atid=448266&aid=1609944&group_id=47038">
484      * https://sf.net/tracker/?func=detail&amp;atid=448266&amp;aid=1609944&amp;group_id=47038</a>.
485      * @throws Exception if the test fails
486      */
487     @Test
488     @Alerts("0")
489     @HtmlUnitNYI(CHROME = "1",
490             EDGE = "1",
491             FF = "1",
492             FF_ESR = "1")
493     public void onloadJavascriptFunction() throws Exception {
494         final String html = DOCTYPE_HTML
495             + "<html><head>\n"
496             + "<script>\n"
497             + "function onload() { alert('foo'); }\n"
498             + "</script></head>\n"
499             + "<body>\n"
500             + "</body></html>";
501 
502         final WebDriver driver = loadPage2(html);
503         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getCollectedAlerts(driver, 1).size());
504     }
505 
506     /**
507      * @throws Exception if the test fails
508      */
509     @Test
510     @Alerts("foo")
511     public void alert() throws Exception {
512         final String html = DOCTYPE_HTML
513             + "<html><head><title>foo</title><script>\n"
514             + "  alert('foo');\n"
515             + "</script></head><body>\n"
516             + "<p>hello world</p>\n"
517             + "<form name='form1'>\n"
518             + "  <input type='text' name='textfield1' id='textfield1' value='foo' />\n"
519             + "  <input type='text' name='textfield2' id='textfield2'/>\n"
520             + "</form>\n"
521             + "</body></html>";
522 
523         loadPageWithAlerts2(html);
524     }
525 
526     /**
527      * Checks that a dynamically compiled function works in the scope of its birth.
528      * @throws Exception if the test fails
529      */
530     @Test
531     @Alerts("foo")
532     public void scopeOfNewFunction() throws Exception {
533         final String html = DOCTYPE_HTML
534             + "<html><head><script>\n"
535             + LOG_TITLE_FUNCTION
536             + "  var f = new Function('log(\"foo\")');\n"
537             + "  f();\n"
538             + "</script></head><body>\n"
539             + "</body></html>";
540 
541         loadPageVerifyTitle2(html);
542     }
543 
544     /**
545      * @throws Exception if the test fails
546      */
547     @Test
548     @Alerts("foo")
549     public void scopeOfNestedNewFunction() throws Exception {
550         final String html = DOCTYPE_HTML
551             + "<html><head>\n"
552             + "<script>\n"
553             + LOG_TITLE_FUNCTION
554             + "  var foo = 'foo';\n"
555             + "  var f1 = new Function('f = new Function(\"log(foo)\"); f()');\n"
556             + "  f1();\n"
557             + "</script>\n"
558             + "</head>\n"
559             + "<body>\n"
560             + "</body></html>";
561 
562         loadPageVerifyTitle2(html);
563     }
564 
565     /**
566      * Sets value on input expects a string. If you pass in a value that isn't a string
567      * this used to blow up.
568      * @throws Exception if the test fails
569      */
570     @Test
571     @Alerts("1")
572     public void setValuesThatAreNotStrings() throws Exception {
573         final String html = DOCTYPE_HTML
574             + "<html><head>\n"
575             + "<script>\n"
576             + LOG_TITLE_FUNCTION
577             + "function doTest() {\n"
578             + "  document.form1.textfield1.value = 1;\n"
579             + "  log(document.form1.textfield1.value);\n"
580             + "}\n"
581             + "</script></head><body onload='doTest()'>\n"
582             + "<p>hello world</p>\n"
583             + "<form name='form1'>\n"
584             + "  <input type='text' name='textfield1' id='textfield1' value='foo' />\n"
585             + "  <input type='text' name='textfield2' id='textfield2'/>\n"
586             + "</form>\n"
587             + "</body></html>";
588 
589         loadPageVerifyTitle2(html);
590     }
591 
592     /**
593      * @throws Exception if the test fails
594      */
595     @Test
596     @Alerts("foo")
597     public void javaScriptWrappedInHtmlComments() throws Exception {
598         final String html = DOCTYPE_HTML
599             + "<html><head>\n"
600             + "<script language='javascript'><!--\n"
601             + LOG_TITLE_FUNCTION
602             + "function doTest() {\n"
603             + "  log('foo');\n"
604             + "}\n"
605             + "-->\n</script></head>\n"
606             + "<body onload='doTest()'></body></html>";
607 
608         loadPageVerifyTitle2(html);
609     }
610 
611     /**
612      * @throws Exception if the test fails
613      */
614     @Test
615     @Alerts("1")
616     public void javaScriptWrappedInHtmlComments2() throws Exception {
617         final String html = DOCTYPE_HTML
618             + "<html><head>\n"
619             + "<script>\n"
620             + LOG_TITLE_FUNCTION
621             + "</script>\n"
622             + "<script><!--\n"
623             + " log('1');\n"
624             + "--></script>\n"
625             + "</head>\n"
626             + "<body>\n"
627             + "</body></html>";
628 
629         loadPageVerifyTitle2(html);
630     }
631 
632     /**
633      * @throws Exception if the test fails
634      */
635     @Test
636     @Alerts("1")
637     public void javaScriptWrappedInHtmlComments_commentOnOpeningLine() throws Exception {
638         final String html = DOCTYPE_HTML
639             + "<html><head>\n"
640             + "<script language='javascript'><!-- Some comment here\n"
641             + LOG_TITLE_FUNCTION
642             + "function doTest() {\n"
643             + "  log('1');\n"
644             + "}\n"
645             + "-->\n</script></head>\n"
646             + "<body onload='doTest()'></body></html>";
647 
648         loadPageVerifyTitle2(html);
649     }
650 
651     /**
652      * Regression test for bug 1714762.
653      * @throws Exception if the test fails
654      */
655     @Test
656     public void javaScriptWrappedInHtmlComments_commentNotClosed() throws Exception {
657         final String html = DOCTYPE_HTML
658             + "<html><head><title>foo</title>\n"
659             + "<script language='javascript'><!-- log(1);</script>\n"
660             + "<script language='javascript'><!-- </script>\n"
661             + "</head>\n"
662             + "<body></body></html>";
663 
664         loadPageWithAlerts2(html);
665     }
666 
667     /**
668      * @throws Exception if the test fails
669      */
670     @Test
671     @Alerts("undefined")
672     public void javaScriptWrappedInHtmlComments_allOnOneLine() throws Exception {
673         final String html = DOCTYPE_HTML
674             + "<html>\n"
675             + "  <head>\n"
676             + "    <title>test</title>\n"
677             + "    <script>var test;</script>\n"
678             + "    <!-- var test should be undefined since it's on first line -->\n"
679             + "    <!-- but there should be no index out of bounds exception  -->\n"
680             + "    <script> <!-- test = 'abc'; // --> </script>\n"
681             + "  </head>\n"
682             + "  <body onload='alert(test)'>\n"
683             + "  </body>\n"
684             + "</html>";
685 
686         loadPageWithAlerts2(html);
687     }
688 
689     /**
690      * @throws Exception if the test fails
691      */
692     @Test
693     @Alerts("test")
694     public void eventHandlerWithComment() throws Exception {
695         final String html = DOCTYPE_HTML + "<html><body onLoad='alert(\"test\"); // xxx'></body></html>";
696         loadPageWithAlerts2(html);
697     }
698 
699     /**
700      * @throws Exception if the test fails
701      */
702     @Test
703     @Alerts({"2", "3"})
704     public void comment() throws Exception {
705         final String html = DOCTYPE_HTML
706             + "<html><head>\n"
707             + "  <script>\n"
708             + LOG_TITLE_FUNCTION
709             + "    </script>\n"
710             + "<script><!-- log(1);\n"
711             + " log(2);\n"
712             + "log(3)//--></script>\n"
713             + "</head>\n"
714             + "<body>\n"
715             + "</body></html>";
716 
717         loadPageVerifyTitle2(html);
718     }
719 
720     /**
721      * @throws Exception if the test fails
722      */
723     @Test
724     @Alerts({"rstlne-rstlne-rstlne", "rstlno-rstlne-rstlne",
725              "rstlna-rstlne-rstlne", "rstlne-rstlne-rstlne",
726              "rstlni-rstlni-rstlni", "rstlna-rstlna-rstlna"})
727     public void regExpSupport() throws Exception {
728         final String html = DOCTYPE_HTML
729             + "<html>\n"
730             + "  <head>\n"
731             + "    <script id='a'>\n"
732             + LOG_TITLE_FUNCTION
733             + "       var s = new String('rstlne-rstlne-rstlne');\n"
734             + "       log(s);\n"
735             + "       s = s.replace('e', 'o');\n"
736             + "       log(s);\n"
737             + "       s = s.replace(/o/, 'a');\n"
738             + "       log(s);\n"
739             + "       s = s.replace(new RegExp('a'), 'e');\n"
740             + "       log(s);\n"
741             + "       s = s.replace(new RegExp('e', 'g'), 'i');\n"
742             + "       log(s);\n"
743             + "       s = s.replace(/i/g, 'a');\n"
744             + "       log(s);\n"
745             + "    </script>\n"
746             + "  </head>\n"
747             + "  <body>abc</body>\n"
748             + "</html>";
749 
750         loadPageVerifyTitle2(html);
751     }
752 
753     /**
754      * Test ECMA reserved keywords... that are accepted by "normal" browsers
755      * @throws Exception if the test fails
756      */
757     @Test
758     @Alerts("123")
759     public void ecmaReservedKeywords() throws Exception {
760         final String html = DOCTYPE_HTML
761             + "<html><head>\n"
762             + "<script>\n"
763             + LOG_TITLE_FUNCTION
764             + "  var o = {float: 123};\n"
765             + "  log(o.float);\n"
766             + "</script></head><body>\n"
767             + "</body></html>";
768 
769         loadPageVerifyTitle2(html);
770     }
771 
772     /**
773      * @throws Exception if the test fails
774      */
775     @Test
776     @Alerts("[object Window]")
777     public void boundFunction() throws Exception {
778         final String html = DOCTYPE_HTML
779                 + "<html><head><script>\n"
780                 + LOG_TITLE_FUNCTION
781                 + "  function test() {\n"
782                 + "    if (focusMe.bind) {\n"
783                 + "      var boundFunction = focusMe.bind(null);\n"
784                 + "      document.getElementById('myId').addEventListener('focus', boundFunction, true);\n"
785                 + "    }\n"
786                 + "  }\n"
787                 + "  function focusMe() {\n"
788                 + "    log(this);\n"
789                 + "  }\n"
790                 + "</script></head>\n"
791                 + "<body onload='test()'>\n"
792                 + "  <button id='myId'>Click me</button>\n"
793                 + "</body></html>";
794 
795         final WebDriver driver = loadPage2(html);
796         final String[] expectedAlerts = getExpectedAlerts();
797 
798         driver.findElement(By.id("myId")).click();
799         verifyTitle2(driver, expectedAlerts);
800     }
801 
802     /**
803      * @throws Exception if the test fails
804      */
805     @Test
806     @Alerts({"t=undefined", "inside"})
807     public void functionHasNameOfVar() throws Exception {
808         final String html = DOCTYPE_HTML
809                 + "<html><head>\n"
810                 + "<script>\n"
811                 + LOG_TITLE_FUNCTION
812                 + "  function test() {\n"
813                 + "    log('t=' + t);\n"
814                 + "    var t = 42;\n"
815                 + "    ! function t() { log('inside'); } ();\n"
816                 + "  }\n"
817                 + "</script>\n"
818                 + "</head>\n"
819                 + "<body onload='test()'>\n"
820                 + "</body></html>";
821 
822         loadPageVerifyTitle2(html);
823     }
824 
825     /**
826      * @throws Exception if the test fails
827      */
828     @Test
829     @Alerts({"outer abc = 1", "inner abc = function"})
830     public void functionHasNameOfVarStrictMode() throws Exception {
831         final String html = DOCTYPE_HTML
832                 + "<html><head>\n"
833                 + "<script>\n"
834                 + "  'use strict';\n"
835                 + LOG_TITLE_FUNCTION
836                 + "  var abc = 1;\n"
837                 + "  var foo = function abc() { log('inner abc = ' + typeof abc); }\n"
838                 + "  log('outer abc = ' + abc);\n"
839                 + "  foo()\n"
840                 + "</script>\n"
841                 + "</head>\n"
842                 + "<body>\n"
843                 + "</body></html>";
844 
845         loadPageVerifyTitle2(html);
846     }
847 
848     /**
849      * @throws Exception if the test fails
850      */
851     @Test
852     @Alerts({"a", "b"})
853     public void innerFunctionWithSameName() throws Exception {
854         final String html = DOCTYPE_HTML
855                 + "<html><head>\n"
856                 + "<script>\n"
857                 + LOG_TITLE_FUNCTION
858                 + "  var a = function () {\n"
859                 + "    var x = (function x () { log('a') });\n"
860                 + "    return function () { x() };\n"
861                 + "  }();\n"
862 
863                 + "  var b = function () {\n"
864                 + "    var x = (function x () { log('b') });\n"
865                 + "    return function () { x() };\n"
866                 + "  }();\n"
867 
868                 + "  a();\n"
869                 + "  b();\n"
870                 + "</script>\n"
871                 + "</head>\n"
872                 + "<body>\n"
873                 + "</body></html>";
874 
875         loadPageVerifyTitle2(html);
876     }
877 
878     /**
879      * @throws Exception if the test fails
880      */
881     @Test
882     @Alerts("a")
883     public void innerFunctionWithSameNameAsOutsideStrict() throws Exception {
884         final String html = DOCTYPE_HTML
885                 + "<html><head>\n"
886                 + "<script>\n"
887                 + "  'use strict';\n"
888                 + LOG_TITLE_FUNCTION
889                 + "  var a = function () {\n"
890                 + "    var x = (function x () { log('a') });\n"
891                 + "    return function () { x() };\n"
892                 + "  }();\n"
893 
894                 + "  var x = function () { log('x') };\n"
895 
896                 + "  a();\n"
897                 + "</script>\n"
898                 + "</head>\n"
899                 + "<body>\n"
900                 + "</body></html>";
901 
902         loadPageVerifyTitle2(html);
903     }
904 
905     /**
906      * @throws Exception if the test fails
907      */
908     @Test
909     @Alerts({"functionfunc(){log(norm(func));}", "outer"})
910     public void secondFunctionWithSameNameStrict() throws Exception {
911         final String html = DOCTYPE_HTML
912                 + "<html><head>\n"
913                 + "<script>\n"
914                 + "  'use strict';\n"
915                 + LOG_TITLE_FUNCTION
916                 + "  function norm(foo) { return ('' + foo).replace(/(\\s)/gm,'') }\n"
917 
918                 + "  function func () { log('outer'); }\n"
919 
920                 + "  var x = function func() { log(norm(func)); }\n"
921 
922                 + "  x();\n"
923                 + "  func();\n"
924                 + "</script>\n"
925                 + "</head>\n"
926                 + "<body>\n"
927                 + "</body></html>";
928 
929         loadPageVerifyTitle2(html);
930     }
931 
932     /**
933      * @throws Exception if the test fails
934      */
935     @Test
936     @Alerts({"f1", "f2", "f3", "!f4", "f5", "!f6", "!f7", "!f8", "f10", "f11", "f12", "!f10", "f11", "f12", "f13"})
937     @HtmlUnitNYI(CHROME = {"f1", "f2", "f3", "!f4", "f5", "!f6", "!f7", "!f8",
938                            "f10", "f11", "f12", "f10", "f11", "f12", "f13"},
939             EDGE = {"f1", "f2", "f3", "!f4", "f5", "!f6", "!f7", "!f8",
940                     "f10", "f11", "f12", "f10", "f11", "f12", "f13"},
941             FF = {"f1", "f2", "f3", "!f4", "f5", "!f6", "!f7", "!f8", "f10", "f11", "f12", "f10", "f11", "f12", "f13"},
942             FF_ESR = {"f1", "f2", "f3", "!f4", "f5", "!f6", "!f7", "!f8",
943                       "f10", "f11", "f12", "f10", "f11", "f12", "f13"})
944     public void functioNamesExceptionsStrict() throws Exception {
945         final String html = DOCTYPE_HTML
946                 + "<html><head>\n"
947                 + "<script>\n"
948                 + "  'use strict';\n"
949                 + LOG_TITLE_FUNCTION
950 
951                 + "  function f1() {"
952                 + "    log('f1');"
953                 + "    function f9() { log('f9'); }"
954                 + "  }\n"
955 
956                 + "  var f2 = function () { log('f2'); }\n"
957                 + "  var f3 = function f4() { log('f3'); }\n"
958                 + "  var f5 = function f5() { log('f5'); }\n"
959 
960                 + "  !function f6() { log('f6'); };\n"
961                 + "  (function f7() { log('f7'); });\n"
962 
963                 + "  void function f8() { log('f8'); }\n"
964 
965                 + "  try { f1() } catch(e) { log('!f1'); }"
966                 + "  try { f2() } catch(e) { log('!f2'); }"
967                 + "  try { f3() } catch(e) { log('!f3'); }"
968                 + "  try { f4() } catch(e) { log('!f4'); }"
969                 + "  try { f5() } catch(e) { log('!f5'); }"
970                 + "  try { f6() } catch(e) { log('!f6'); }"
971                 + "  try { f7() } catch(e) { log('!f7'); }"
972                 + "  try { f8() } catch(e) { log('!f8'); }"
973 
974                 + "  {\n"
975                 + "    function f10() { log('f10'); }\n"
976                 + "    var f11 = function () { log('f11'); }\n"
977                 + "    var f12 = function f12() { log('f12'); }\n"
978                 + "    f10();\n"
979                 + "    f11();\n"
980                 + "    f12();\n"
981                 + "  }\n"
982 
983                 + "  try { f10() } catch(e) { log('!f10'); }"
984                 + "  try { f11() } catch(e) { log('!f11'); }"
985                 + "  try { f12() } catch(e) { log('!f12'); }"
986 
987                 + "  function f13() { log('f13') } + 1;"
988                 + "  try { f13() } catch(e) { log('!f13'); }"
989 
990                 + "</script>\n"
991                 + "</head>\n"
992                 + "<body>\n"
993                 + "</body></html>";
994 
995         loadPageVerifyTitle2(html);
996     }
997 
998     /**
999      * @throws Exception if the test fails
1000      */
1001     @Test
1002     @Alerts("false")
1003     public void ctorBooleanDocumentAll() throws Exception {
1004         final String html = DOCTYPE_HTML
1005             + "<html><head>\n"
1006             + "<script>\n"
1007             + LOG_TITLE_FUNCTION
1008             + "function test() {\n"
1009             + "  log(Boolean(document.all))\n"
1010             + "}\n"
1011             + "</script></head>\n"
1012             + "<body onload='test()'>\n"
1013             + "</body></html>";
1014 
1015         loadPageVerifyTitle2(html);
1016     }
1017 
1018     /**
1019      * @throws Exception if the test fails
1020      */
1021     @Test
1022     @Alerts("false")
1023     public void falsyDocumentAll() throws Exception {
1024         final String html = DOCTYPE_HTML
1025             + "<html><head>\n"
1026             + "<script>\n"
1027             + LOG_TITLE_FUNCTION
1028             + "function test() {\n"
1029             + "  if (document.all) log('true'); else log('false');\n"
1030             + "}\n"
1031             + "</script></head>\n"
1032             + "<body onload='test()'>\n"
1033             + "</body></html>";
1034 
1035         loadPageVerifyTitle2(html);
1036     }
1037 
1038     /**
1039      * @throws Exception if the test fails
1040      */
1041     @Test
1042     @Alerts("[object HTMLAllCollection]")
1043     public void falsyAndDocumentAll() throws Exception {
1044         final String html = DOCTYPE_HTML
1045             + "<html><head>\n"
1046             + "<script>\n"
1047             + LOG_TITLE_FUNCTION
1048             + "function test() {\n"
1049             + "  var res = document.all && 'Html';\n"
1050             + "  log(res);\n"
1051             + "}\n"
1052             + "</script></head>\n"
1053             + "<body onload='test()'>\n"
1054             + "</body></html>";
1055 
1056         loadPageVerifyTitle2(html);
1057     }
1058 
1059     /**
1060      * @throws Exception if the test fails
1061      */
1062     @Test
1063     @Alerts("ReferenceError")
1064     public void javaNotAccessable() throws Exception {
1065         final String html = DOCTYPE_HTML
1066                 + "<html><head>\n"
1067                 + "<script>\n"
1068                 + LOG_TITLE_FUNCTION
1069                 + "function test() {\n"
1070                 + "  try {\n"
1071                 + "    log(java.lang.Math.PI);\n"
1072                 + "  } catch(e) { logEx(e); }\n"
1073                 + "}\n"
1074                 + "</script>\n"
1075                 + "</head>\n"
1076                 + "<body onload='test()'>\n"
1077                 + "</body></html>";
1078 
1079         loadPageVerifyTitle2(html);
1080     }
1081 
1082     /**
1083      * @throws Exception if the test fails
1084      */
1085     @Test
1086     @Alerts("Received: from worker - exception")
1087     public void javaNotAccessableFromWorker() throws Exception {
1088         final String html = DOCTYPE_HTML
1089             + "<html><body>\n"
1090             + "<script async>\n"
1091             + LOG_TITLE_FUNCTION
1092             + "try {\n"
1093             + "  var myWorker = new Worker('worker.js');\n"
1094             + "  myWorker.onmessage = function(e) {\n"
1095             + "    log('Received: ' + e.data);\n"
1096             + "  };\n"
1097             + "} catch(e) { logEx(e); }\n"
1098             + "</script></body></html>\n";
1099 
1100         final String workerJs = "var pi = 'from worker';\n"
1101                 + "try {\n"
1102                 + "  pi = pi + ' - ' + java.lang.Math.PI\n"
1103                 + "} catch(e) { pi = pi + ' - ' + 'exception'; }\n"
1104                 + "postMessage(pi);\n";
1105 
1106         getMockWebConnection().setResponse(new URL(URL_FIRST, "worker.js"), workerJs, MimeType.TEXT_JAVASCRIPT);
1107 
1108         loadPage2(html);
1109         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
1110     }
1111 
1112     /**
1113      * @throws Exception if the test fails
1114      */
1115     @Test
1116     @Alerts({"#0", "#1", "2"})
1117     public void constInLoop() throws Exception {
1118         final String html = DOCTYPE_HTML
1119                 + "<html><head>\n"
1120                 + "<script>\n"
1121                 + LOG_TITLE_FUNCTION
1122                 + "function test() {\n"
1123                 + "  var i;\n"
1124                 + "  for (i = 0; i < 2; i++) {\n"
1125                 + "    const x = '#' + i;\n"
1126                 + "    log(x);\n"
1127                 + "  }\n"
1128                 + "  log(i);\n"
1129                 + "}\n"
1130                 + "</script>\n"
1131                 + "</head>\n"
1132                 + "<body onload='test()'>\n"
1133                 + "</body></html>";
1134 
1135         loadPageVerifyTitle2(html);
1136     }
1137 
1138     /**
1139      * @throws Exception if the test fails
1140      */
1141     @Test
1142     @Alerts({"1", "2"})
1143     public void constInOfLoop() throws Exception {
1144         final String html = DOCTYPE_HTML
1145                 + "<html><head>\n"
1146                 + "<script>\n"
1147                 + LOG_TITLE_FUNCTION
1148                 + "function test() {\n"
1149                 + "  var arr = [1, 2];\n"
1150                 + "  for(const elem of arr) {\n"
1151                 + "    log(elem);\n"
1152                 + "  }\n"
1153                 + "}\n"
1154                 + "</script>\n"
1155                 + "</head>\n"
1156                 + "<body onload='test()'>\n"
1157                 + "</body></html>";
1158 
1159         loadPageVerifyTitle2(html);
1160     }
1161 
1162     /**
1163      * @throws Exception if the test fails
1164      */
1165     @Test
1166     @Alerts("seven")
1167     public void constInIfElse() throws Exception {
1168         final String html = DOCTYPE_HTML
1169                 + "<html><head>\n"
1170                 + "<script>\n"
1171                 + LOG_TITLE_FUNCTION
1172                 + "function test() {\n"
1173                 + "  let abcd = '1234';"
1174                 + "  if('abcd' === abcd) {\n"
1175                 + "    const constant = 7;\n"
1176                 + "    log(constant);\n"
1177                 + "  } else {\n"
1178                 + "    const constant = 'seven';\n"
1179                 + "    log(constant);\n"
1180                 + "  }\n"
1181                 + "}\n"
1182                 + "</script>\n"
1183                 + "</head>\n"
1184                 + "<body onload='test()'>\n"
1185                 + "</body></html>";
1186 
1187         loadPageVerifyTitle2(html);
1188     }
1189 
1190     /**
1191      * @throws Exception if the test fails
1192      */
1193     @Test
1194     @Alerts({"1 ready", "2 ready", "3 ready", "4 ready",
1195         "5 ready", "6 ready", "7 ready", "8 ready", "9 ready", "10 ready"})
1196     public void ensureOrder() throws Exception {
1197         final String html = DOCTYPE_HTML
1198             + "<html><body>"
1199             + "<script>\n"
1200             + LOG_TITLE_FUNCTION
1201             + "  function timeoutFunction(nr) {\n"
1202             + "    return function () {\n"
1203             + "      log(nr + ' ready');\n"
1204             + "    }\n"
1205             + "  }\n"
1206 
1207             + "  for (let i = 1; i <= 10; i++) {\n"
1208             + "    setTimeout(timeoutFunction(i));\n"
1209             + "  }\n"
1210             + "</script></body></html>";
1211 
1212         final WebDriver driver = loadPage2(html);
1213         Thread.sleep(DEFAULT_WAIT_TIME.toMillis());
1214         verifyTitle2(driver, getExpectedAlerts());
1215     }
1216 
1217     /**
1218      * @throws Exception if the test fails
1219      */
1220     @Test
1221     @Alerts({"false", "aa", "0", "aabbc", "false", "bb", "2", "aabbc", "true", "undefined"})
1222     public void matchAll() throws Exception {
1223         final String html = DOCTYPE_HTML
1224             + "<html><body>"
1225             + "<script>\n"
1226             + LOG_TITLE_FUNCTION
1227             + "const s = 'aabbc';\n"
1228             + "const re = /([a-z])\\1/g;\n"
1229             + "const matches = s.matchAll(re);\n"
1230 
1231             + "var match = matches.next();\n"
1232             + "log(match.done);\n"
1233             + "log(match.value[0]);\n"
1234             + "log(match.value.index);\n"
1235             + "log(match.value.input);\n"
1236 
1237             + "match = matches.next();\n"
1238             + "log(match.done);\n"
1239             + "log(match.value[0]);\n"
1240             + "log(match.value.index);\n"
1241             + "log(match.value.input);\n"
1242 
1243             + "match = matches.next();\n"
1244             + "log(match.done);\n"
1245             + "log(match.value);\n"
1246             + "</script></body></html>";
1247 
1248         loadPageVerifyTitle2(html);
1249     }
1250 
1251     /**
1252      * Make sure we use the TopScope, otherwise some GeneratorFunction stuff
1253      * does not work.
1254      * @throws Exception if the test fails
1255      */
1256     @Test
1257     @Alerts({"anonymous", "false", "false", "true"})
1258     @HtmlUnitNYI(CHROME = "org.htmlunit.ScriptException: TypeError: Cannot read property \"constructor\" from null",
1259             EDGE = "org.htmlunit.ScriptException: TypeError: Cannot read property \"constructor\" from null",
1260             FF = "org.htmlunit.ScriptException: TypeError: Cannot read property \"constructor\" from null",
1261             FF_ESR = "org.htmlunit.ScriptException: TypeError: Cannot read property \"constructor\" from null")
1262     public void generatorFunction() throws Exception {
1263         final String html = DOCTYPE_HTML
1264             + "<html><body>"
1265             + "<script>\n"
1266             + LOG_TITLE_FUNCTION
1267             + "var GeneratorFunction = Object.getPrototypeOf(function*() {}).constructor;\n"
1268 
1269             + "log(GeneratorFunction().name);\n"
1270             + "log(Object.getOwnPropertyDescriptor(GeneratorFunction(), 'name').enumerable);\n"
1271             + "log(Object.getOwnPropertyDescriptor(GeneratorFunction(), 'name').writable);\n"
1272             + "log(Object.getOwnPropertyDescriptor(GeneratorFunction(), 'name').configurable);\n"
1273             + "</script></body></html>";
1274 
1275         try {
1276             loadPageVerifyTitle2(html);
1277         }
1278         catch (final WebDriverException e) {
1279             assertTrue(e.getMessage(), e.getMessage().startsWith(getExpectedAlerts()[0]));
1280         }
1281     }
1282 
1283 }