View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.html;
16  
17  import java.net.URL;
18  import java.nio.charset.StandardCharsets;
19  
20  import org.htmlunit.WebDriverTestCase;
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.htmlunit.junit.annotation.HtmlUnitNYI;
23  import org.htmlunit.util.MimeType;
24  import org.junit.jupiter.api.Test;
25  import org.openqa.selenium.By;
26  import org.openqa.selenium.WebDriver;
27  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
28  
29  /**
30   * Unit tests for {@link HTMLScriptElement}.
31   * TODO: check event order with defer in real browser WITHOUT using alert(...) as it impacts ordering.
32   * Some expectations seems to be incorrect.
33   * @author Daniel Gredler
34   * @author Ahmed Ashour
35   * @author Marc Guillemot
36   * @author Frank Danek
37   * @author Ronald Brill
38   */
39  public class HTMLScriptElementTest extends WebDriverTestCase {
40  
41      /**
42       * Verifies that the <tt>onreadystatechange</tt> handler is invoked correctly.
43       * @throws Exception if an error occurs
44       */
45      @Test
46      @Alerts({"1", "2", "3", "4", "onload"})
47      public void onReadyStateChangeHandler() throws Exception {
48          final String html = DOCTYPE_HTML
49              + "<html>\n"
50              + "  <head>\n"
51              + "    <script>\n"
52              + LOG_TITLE_FUNCTION
53              + "      function test() {\n"
54              + "        var script = document.createElement('script');\n"
55              + "        script.id = 'b';\n"
56              + "        script.type = 'text/javascript';\n"
57              + "        script.onreadystatechange = null;\n"
58              + "        script.onreadystatechange = function() {\n"
59              + "          log('onreadystatechange ' + script.readyState);\n"
60              + "        }\n"
61              + "        script.onload = function() {\n"
62              + "          log('onload');\n"
63              + "        }\n"
64              + "        log('1');\n"
65              + "        script.src = 'script.js';\n"
66              + "        log('2');\n"
67              + "        document.getElementsByTagName('head')[0].appendChild(script);\n"
68              + "        log('3');\n"
69              + "      }\n"
70              + "    </script>\n"
71              + "  </head>\n"
72              + "  <body onload='test()'>\n"
73              + "  </body></html>";
74  
75          getMockWebConnection().setDefaultResponse("log('4');", MimeType.TEXT_JAVASCRIPT);
76  
77          loadPage2(html);
78          verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
79      }
80  
81      /**
82       * Test for bug
83       * <a href="https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1782719&group_id=47038">issue 514</a>.
84       * @throws Exception if the test fails
85       */
86      @Test
87      public void srcWithJavaScriptProtocol_Static() throws Exception {
88          final String html = DOCTYPE_HTML
89                  + "<html><head><script src='javascript:\"alert(1)\"'></script></head><body></body></html>";
90          loadPageWithAlerts2(html);
91      }
92  
93      /**
94       * @throws Exception if the test fails
95       */
96      @Test
97      @Alerts({"§§URL§§foo.js", "foo.js", "§§URL§§", ""})
98      public void srcPropertyShouldBeAFullUrl() throws Exception {
99          final String html = DOCTYPE_HTML
100                 + "<html>\n"
101                 + "<head>\n"
102                 + "  <script>\n"
103                 + LOG_TITLE_FUNCTION
104                 + "    function test() {\n"
105                 + "      var script = document.getElementById('my');\n"
106                 + "      log(script.src);\n"
107                 + "      log(script.getAttribute('src'));\n"
108 
109                 + "      var script2 = document.getElementById('my2');\n"
110                 + "      log(script2.src);\n"
111                 + "      log(script2.getAttribute('src'));\n"
112                 + "    }\n"
113                 + "  </script>\n"
114                 + "</head>\n"
115                 + "<body onload='test()'>\n"
116                 + "  <script id='my' src='foo.js'></script>\n"
117                 + "  <script id='my2' src=''></script>\n"
118                 + "</body></html>";
119 
120         getMockWebConnection().setDefaultResponse("", "text/javascript");
121 
122         expandExpectedAlertsVariables(URL_FIRST);
123         loadPageVerifyTitle2(html);
124     }
125 
126     /**
127      * @throws Exception if the test fails
128      */
129     @Test
130     @Alerts({"", "null", "", "null"})
131     public void srcPropertyNoSource() throws Exception {
132         final String html = DOCTYPE_HTML
133                 + "<html>\n"
134                 + "<head>\n"
135                 + "  <script>\n"
136                 + LOG_TITLE_FUNCTION
137                 + "    function test() {\n"
138                 + "      var script = document.getElementById('my');\n"
139                 + "      log(script.src);\n"
140                 + "      log(script.getAttribute('src'));\n"
141 
142                 + "      var script2 = document.createElement('script');\n"
143                 + "      log(script2.src);\n"
144                 + "      log(script2.getAttribute('src'));\n"
145                 + "    }\n"
146                 + "  </script>\n"
147                 + "</head>\n"
148                 + "<body onload='test()'>\n"
149                 + "  <script id='my'></script>\n"
150                 + "</body></html>";
151 
152         getMockWebConnection().setDefaultResponse("", "text/javascript");
153 
154         loadPageVerifyTitle2(html);
155     }
156 
157     /**
158      * Test for bug
159      * <a href="https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1782719&group_id=47038">issue 514</a>.
160      * @throws Exception if the test fails
161      */
162     @Test
163     public void srcWithJavaScriptProtocol_Dynamic() throws Exception {
164         final String html = DOCTYPE_HTML
165             + "<html><head><script>\n"
166             + LOG_TITLE_FUNCTION
167             + "  function test() {\n"
168             + "    var script=document.createElement('script');\n"
169             + "    script.src = \"javascript: 'log(1)'\";\n"
170             + "    document.getElementsByTagName('head')[0].appendChild(script);\n"
171             + "  }\n"
172             + "</script></head><body onload='test()'>\n"
173             + "</body></html>";
174 
175         loadPageVerifyTitle2(html);
176     }
177 
178     /**
179      * Test for bug 2993940.
180      * @throws Exception if the test fails
181      */
182     @Test
183     @Alerts({"start", "end"})
184     public void reexecuteModifiedScript() throws Exception {
185         final String html = DOCTYPE_HTML
186             + "<html><head></head><body>\n"
187             + "<script>\n"
188             + LOG_TITLE_FUNCTION
189             + "  log('start');\n"
190             + "  var script = document.getElementsByTagName('script')[0];\n"
191             + "  script.text = \"log('executed');\";\n"
192             + "  log('end');\n"
193             + "</script>\n"
194             + "</body></html>";
195 
196         loadPageVerifyTitle2(html);
197     }
198 
199     /**
200      * @throws Exception if the test fails
201      */
202     @Test
203     @Alerts({"hello", "hello", "world", "-"})
204     public void scriptInCdataXHtml() throws Exception {
205         final String html =
206             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
207             + "<!DOCTYPE html PUBLIC \n"
208             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
209             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
210             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
211             + "<head></head>\n"
212             + "<body>\n"
213             + "<script>\n"
214             // do not use LOG_TITLE_FUNCTION here
215             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
216             + "</script>\n"
217             + "  <script>\n"
218             + "    //<![CDATA[\n"
219             + "    log('hello');\n"
220             + "    //]]>\n"
221             + "  </script>\n"
222             + "  <script>\n"
223             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
224             + "  </script>\n"
225             + "  <script>\n"
226             + "    <![CDATA[\n"
227             + "    log('world');\n"
228             + "    ]]>\n"
229             + "  </script>\n"
230             + "  <script>log('-');</script>\n"
231             + "</body></html>";
232 
233         if (getWebDriver() instanceof HtmlUnitDriver) {
234             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
235         }
236 
237         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.APPLICATION_XHTML, StandardCharsets.UTF_8);
238         verifyTitle2(driver, getExpectedAlerts());
239     }
240 
241     /**
242      * @throws Exception if the test fails
243      */
244     @Test
245     @Alerts({"hello", "hello", "world", "-"})
246     public void scriptInCdataXml() throws Exception {
247         final String html =
248             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
249             + "<!DOCTYPE html PUBLIC \n"
250             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
251             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
252             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
253             + "<head></head>\n"
254             + "<body>\n"
255             + "<script>\n"
256             // do not use LOG_TITLE_FUNCTION here
257             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
258             + "</script>\n"
259             + "  <script>\n"
260             + "    //<![CDATA[\n"
261             + "    log('hello');\n"
262             + "    //]]>\n"
263             + "  </script>\n"
264             + "  <script>\n"
265             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
266             + "  </script>\n"
267             + "  <script>\n"
268             + "    <![CDATA[\n"
269             + "    log('world');\n"
270             + "    ]]>\n"
271             + "  </script>\n"
272             + "  <script>log('-');</script>\n"
273             + "</body></html>";
274 
275         if (getWebDriver() instanceof HtmlUnitDriver) {
276             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
277         }
278         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.TEXT_XML, StandardCharsets.UTF_8);
279         verifyTitle2(driver, getExpectedAlerts());
280     }
281 
282     /**
283      * @throws Exception if the test fails
284      */
285     @Test
286     @Alerts({"hello", "hello", "-"})
287     public void scriptInCdataHtml() throws Exception {
288         final String html = DOCTYPE_HTML
289             + "<html>\n"
290             + "<head></head>\n"
291             + "<body>\n"
292             + "<script>\n"
293             + LOG_TITLE_FUNCTION
294             + "</script>\n"
295             + "  <script>\n"
296             + "    //<![CDATA[\n"
297             + "    log('hello');\n"
298             + "    //]]>\n"
299             + "  </script>\n"
300             + "  <script>\n"
301             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
302             + "  </script>\n"
303             + "  <script>\n"
304             + "    <![CDATA[\n"
305             + "    log('world');\n"
306             + "    ]]>\n"
307             + "  </script>\n"
308             + "  <script>log('-');</script>\n"
309             + "</body></html>";
310 
311         if (getWebDriver() instanceof HtmlUnitDriver) {
312             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
313         }
314         loadPageVerifyTitle2(html);
315     }
316 
317     /**
318      * Creates a new script element and adds the source using <code>createTextNode</code> and <code>appendChild</code>.
319      * @throws Exception if the test fails
320      */
321     @Test
322     @Alerts({"start", "end"})
323     public void createElementWithCreateTextNode() throws Exception {
324         final String html = DOCTYPE_HTML
325               + "<html><head></head><body>\n"
326               + "<script>\n"
327               + LOG_TITLE_FUNCTION
328               + "  log('start');\n"
329               + "  var script = document.createElement('script');\n"
330               + "  var source = document.createTextNode(\"log('executed');\");\n"
331               + "  try {\n"
332               + "    script.appendChild(source);\n"
333               + "  } catch(e) {logEx(e); }\n"
334               + "  log('end');\n"
335               + "</script>\n"
336               + "</body></html>";
337 
338         loadPageVerifyTitle2(html);
339     }
340 
341     /**
342      * Creates a new script element and adds the source using <code>createTextNode</code> and <code>appendChild</code>.
343      * After that it appends the script element to the body.
344      * @throws Exception if the test fails
345      */
346     @Test
347     @Alerts({"start", "middle", "executed", "end"})
348     public void createElementWithCreateTextNodeAndAppend() throws Exception {
349         final String html = DOCTYPE_HTML
350               + "<html><head></head><body>\n"
351               + "<script>\n"
352               + LOG_TITLE_FUNCTION
353               + "  log('start');\n"
354               + "  var script = document.createElement('script');\n"
355               + "  var source = document.createTextNode(\"log('executed');\");\n"
356               + "  try {\n"
357               + "    script.appendChild(source);\n"
358               + "  } catch(e) {logEx(e); }\n"
359               + "  log('middle');\n"
360               + "  document.body.appendChild(script);\n"
361               + "  log('end');\n"
362               + "</script>\n"
363               + "</body></html>";
364 
365         loadPageVerifyTitle2(html);
366     }
367 
368     /**
369      * Creates a new script element and adds the source using <code>.text</code>.
370      * @throws Exception if the test fails
371      */
372     @Test
373     @Alerts({"start", "end"})
374     public void createElementWithSetText() throws Exception {
375         final String html = DOCTYPE_HTML
376               + "<html><head></head><body>\n"
377               + "<script>\n"
378               + LOG_TITLE_FUNCTION
379               + "  log('start');\n"
380               + "  var script = document.createElement('script');\n"
381               + "  script.text = \"log('executed');\";\n"
382               + "  log('end');\n"
383               + "</script>\n"
384               + "</body></html>";
385 
386         loadPageVerifyTitle2(html);
387     }
388 
389     /**
390      * Creates a new script element and adds the source using <code>.text</code>.
391      * After that it appends the script element to the body.
392      * @throws Exception if the test fails
393      */
394     @Test
395     @Alerts({"start", "middle", "executed", "end"})
396     public void createElementWithSetTextAndAppend() throws Exception {
397         final String html = DOCTYPE_HTML
398               + "<html><head></head><body>\n"
399               + "<script>\n"
400               + LOG_TITLE_FUNCTION
401               + "  log('start');\n"
402               + "  var script = document.createElement('script');\n"
403               + "  script.text = \"log('executed');\";\n"
404               + "  log('middle');\n"
405               + "  document.body.appendChild(script);\n"
406               + "  log('end');\n"
407               + "</script>\n"
408               + "</body></html>";
409 
410         loadPageVerifyTitle2(html);
411     }
412 
413     /**
414      * Creates a new script element and adds the source using <code>.src</code>.
415      * @throws Exception if the test fails
416      */
417     @Test
418     @Alerts({"start", "end"})
419     public void createElementWithSetSrc() throws Exception {
420         final String html = DOCTYPE_HTML
421               + "<html><head></head><body>\n"
422               + "<script>\n"
423               + LOG_TITLE_FUNCTION
424               + "  log('start');\n"
425               + "  var script = document.createElement('script');\n"
426               + "  script.src = \"" + URL_SECOND + "\";\n"
427               + "  log('end');\n"
428               + "</script>\n"
429               + "</body></html>";
430 
431         final String js = "log('executed');";
432         getMockWebConnection().setResponse(URL_SECOND, js);
433 
434         loadPageVerifyTitle2(html);
435     }
436 
437     /**
438      * Creates a new script element and adds the source using <code>.src</code>.
439      * After that it appends the script element to the body.
440      * @throws Exception if the test fails
441      */
442     @Test
443     @Alerts({"start", "middle", "end", "executed"})
444     public void createElementWithSetSrcAndAppend() throws Exception {
445         final String html = DOCTYPE_HTML
446               + "<html><head></head><body>\n"
447               + "<script>\n"
448               + LOG_TITLE_FUNCTION
449               + "  log('start');\n"
450               + "  var script = document.createElement('script');\n"
451               + "  script.src = \"" + URL_SECOND + "\";\n"
452               + "  log('middle');\n"
453               + "  document.body.appendChild(script);\n"
454               + "  log('end');\n"
455               + "</script>\n"
456               + "</body></html>";
457 
458         final String js = "log('executed');";
459         getMockWebConnection().setResponse(URL_SECOND, js);
460 
461         final WebDriver driver = loadPage2(html);
462         verifyTitle2(driver, getExpectedAlerts());
463     }
464 
465     /**
466      * Replaces the source of the current script element using <code>createTextNode</code> and <code>appendChild</code>.
467      * @throws Exception if the test fails
468      */
469     @Test
470     @Alerts({"start", "end"})
471     public void replaceSelfWithCreateTextNode() throws Exception {
472         final String html = DOCTYPE_HTML
473               + "<html><head></head><body>\n"
474               + "<script>\n"
475               + LOG_TITLE_FUNCTION
476               + "  log('start');\n"
477               + "  var script = document.getElementsByTagName('script')[0];\n"
478               + "  var source = document.createTextNode(\"log('executed');\");\n"
479               + "  try {\n"
480               + "    script.appendChild(source);\n"
481               + "  } catch(e) {logEx(e); }\n"
482               + "  log('end');\n"
483               + "</script>\n"
484               + "</body></html>";
485 
486         loadPageVerifyTitle2(html);
487     }
488 
489     /**
490      * Replaces the source of the current script element using <code>.text</code>.
491      * @throws Exception if the test fails
492      */
493     @Test
494     @Alerts({"start", "end"})
495     public void replaceSelfWithSetText() throws Exception {
496         // TODO this test is the same as #reexecuteModifiedScriptWhenReappending()
497         final String html = DOCTYPE_HTML
498               + "<html><head></head><body>\n"
499               + "<script>\n"
500               + LOG_TITLE_FUNCTION
501               + "  log('start');\n"
502               + "  var script = document.getElementsByTagName('script')[0];\n"
503               + "  var source = document.createTextNode(\"log('executed');\");\n"
504               + "  script.text = \"log('executed');\";\n"
505               + "  log('end');\n"
506               + "</script>\n"
507               + "</body></html>";
508 
509         loadPageVerifyTitle2(html);
510     }
511 
512     /**
513      * Replaces the source of the current script element using <code>.src</code>.
514      * @throws Exception if the test fails
515      */
516     @Test
517     @Alerts({"start", "end"})
518     public void replaceSelfWithSetSrc() throws Exception {
519         final String html = DOCTYPE_HTML
520               + "<html><head></head><body>\n"
521               + "<script>\n"
522               + LOG_TITLE_FUNCTION
523               + "  log('start');\n"
524               + "  var script = document.getElementsByTagName('script')[0];\n"
525               + "  var source = document.createTextNode(\"log('executed');\");\n"
526               + "  script.src = \"" + URL_SECOND + "\";\n"
527               + "  log('end');\n"
528               + "</script>\n"
529               + "</body></html>";
530 
531         final String js = "log('executed');";
532         getMockWebConnection().setResponse(URL_SECOND, js);
533 
534         loadPageVerifyTitle2(html);
535     }
536 
537     /**
538      * Replaces the empty source of another script element using <code>createTextNode</code> and <code>appendChild</code>.
539      * @throws Exception if the test fails
540      */
541     @Test
542     @Alerts({"start", "executed", "end"})
543     public void replaceWithCreateTextNodeEmpty() throws Exception {
544         final String html = DOCTYPE_HTML
545               + "<html><head></head><body>\n"
546               + "<script id='js1'></script>\n"
547               + "<script>\n"
548               + LOG_TITLE_FUNCTION
549               + "  log('start');\n"
550               + "  var script = document.getElementById('js1');\n"
551               + "  var source = document.createTextNode(\"log('executed');\");\n"
552               + "  try {\n"
553               + "    script.appendChild(source);\n"
554               + "  } catch(e) {logEx(e); }\n"
555               + "  log('end');\n"
556               + "</script>\n"
557               + "</body></html>";
558 
559         loadPageVerifyTitle2(html);
560     }
561 
562     /**
563      * Replaces the source containing just a blank of another script element using <code>createTextNode</code> and <code>appendChild</code>.
564      * @throws Exception if the test fails
565      */
566     @Test
567     @Alerts({"start", "end"})
568     public void replaceWithCreateTextNodeBlank() throws Exception {
569         final String html = DOCTYPE_HTML
570               + "<html><head></head><body>\n"
571               + "<script id='js1'> </script>\n"
572               + "<script>\n"
573               + LOG_TITLE_FUNCTION
574               + "  log('start');\n"
575               + "  var script = document.getElementById('js1');\n"
576               + "  var source = document.createTextNode(\"log('executed');\");\n"
577               + "  try {\n"
578               + "    script.appendChild(source);\n"
579               + "  } catch(e) {logEx(e); }\n"
580               + "  log('end');\n"
581               + "</script>\n"
582               + "</body></html>";
583 
584         loadPageVerifyTitle2(html);
585     }
586 
587     /**
588      * Replaces the source containing a script of another script element using <code>createTextNode</code> and <code>appendChild</code>.
589      * @throws Exception if the test fails
590      */
591     @Test
592     @Alerts({"script", "start", "end"})
593     public void replaceWithCreateTextNodeScript() throws Exception {
594         final String html = DOCTYPE_HTML
595               + "<html><head></head><body>\n"
596               + "<script id='js1'>\n"
597               + LOG_TITLE_FUNCTION
598               + "  log('script');\n"
599               + "</script>\n"
600               + "<script>\n"
601               + "  log('start');\n"
602               + "  var script = document.getElementById('js1');\n"
603               + "  var source = document.createTextNode(\"log('executed');\");\n"
604               + "  try {\n"
605               + "    script.appendChild(source);\n"
606               + "  } catch(e) {logEx(e); }\n"
607               + "  log('end');\n"
608               + "</script>\n"
609               + "</body></html>";
610 
611         loadPageVerifyTitle2(html);
612     }
613 
614     /**
615      * Replaces the empty source of another script element using <code>.text</code>.
616      * @throws Exception if the test fails
617      */
618     @Test
619     @Alerts({"start", "executed", "end"})
620     public void replaceWithSetTextEmpty() throws Exception {
621         final String html = DOCTYPE_HTML
622               + "<html><head></head><body>\n"
623               + "<script id='js1'></script>\n"
624               + "<script>\n"
625               + LOG_TITLE_FUNCTION
626               + "  log('start');\n"
627               + "  var script = document.getElementById('js1');\n"
628               + "  script.text = \"log('executed');\";\n"
629               + "  log('end');\n"
630               + "</script>\n"
631               + "</body></html>";
632 
633         loadPageVerifyTitle2(html);
634     }
635 
636     /**
637      * Replaces the source containing just a blank of another script element using <code>.text</code>.
638      * @throws Exception if the test fails
639      */
640     @Test
641     @Alerts({"start", "end"})
642     public void replaceWithSetTextBlank() throws Exception {
643         final String html = DOCTYPE_HTML
644               + "<html><head></head><body>\n"
645               + "<script id='js1'> </script>\n"
646               + "<script>\n"
647               + LOG_TITLE_FUNCTION
648               + "  log('start');\n"
649               + "  var script = document.getElementById('js1');\n"
650               + "  script.text = \"log('executed');\";\n"
651               + "  log('end');\n"
652               + "</script>\n"
653               + "</body></html>";
654 
655         loadPageVerifyTitle2(html);
656     }
657 
658     /**
659      * Replaces the source containing a script of another script element using <code>.text</code>.
660      * @throws Exception if the test fails
661      */
662     @Test
663     @Alerts({"script", "start", "end"})
664     public void replaceWithSetTextScript() throws Exception {
665         final String html = DOCTYPE_HTML
666               + "<html><head></head><body>\n"
667               + "<script id='js1'>\n"
668               + LOG_TITLE_FUNCTION
669               + "  log('script');\n"
670               + "</script>\n"
671               + "<script>\n"
672               + "  log('start');\n"
673               + "  var script = document.getElementById('js1');\n"
674               + "  script.text = \"log('executed');\";\n"
675               + "  log('end');\n"
676               + "</script>\n"
677               + "</body></html>";
678 
679         loadPageVerifyTitle2(html);
680     }
681 
682     /**
683      * Replaces the empty source of another script element using <code>.src</code>.
684      * @throws Exception if the test fails
685      */
686     @Test
687     @Alerts({"start", "end", "executed"})
688     public void replaceWithSetSrcEmpty() throws Exception {
689         final String html = DOCTYPE_HTML
690               + "<html><head></head><body>\n"
691               + "<script>\n"
692               + LOG_TITLE_FUNCTION
693               + "</script>\n"
694               + "<script id='js1'></script>\n"
695               + "<script>\n"
696               + "  log('start');\n"
697               + "  var script = document.getElementById('js1');\n"
698               + "  script.src = \"" + URL_SECOND + "\";\n"
699               + "  log('end');\n"
700               + "</script>\n"
701               + "</body></html>";
702 
703         final String js = "log('executed');";
704         getMockWebConnection().setResponse(URL_SECOND, js);
705 
706         loadPageVerifyTitle2(html);
707     }
708 
709     /**
710      * Replaces the source containing just a blank of another script element using <code>.src</code>.
711      * @throws Exception if the test fails
712      */
713     @Test
714     @Alerts({"start", "end"})
715     public void replaceWithSetSrcBlank() throws Exception {
716         final String html = DOCTYPE_HTML
717               + "<html><head></head><body>\n"
718               + "<script id='js1'> </script>\n"
719               + "<script>\n"
720               + LOG_TITLE_FUNCTION
721               + "  log('start');\n"
722               + "  var script = document.getElementById('js1');\n"
723               + "  script.src = \"" + URL_SECOND + "\";\n"
724               + "  log('end');\n"
725               + "</script>\n"
726               + "</body></html>";
727 
728         final String js = "log('executed');";
729         getMockWebConnection().setResponse(URL_SECOND, js);
730 
731         loadPageVerifyTitle2(html);
732     }
733 
734     /**
735      * Replaces the source containing a script of another script element using <code>.text</code>.
736      * @throws Exception if the test fails
737      */
738     @Test
739     @Alerts({"script", "start", "end"})
740     public void replaceWithSetSrcScript() throws Exception {
741         final String html = DOCTYPE_HTML
742               + "<html><head></head><body>\n"
743               + "<script id='js1'>\n"
744               + LOG_TITLE_FUNCTION
745               + "  log('script');\n"
746               + "</script>\n"
747               + "<script>\n"
748               + "  log('start');\n"
749               + "  var script = document.getElementById('js1');\n"
750               + "  script.src = \"" + URL_SECOND + "\";\n"
751               + "  log('end');\n"
752               + "</script>\n"
753               + "</body></html>";
754 
755         final String js = "log('executed');";
756         getMockWebConnection().setResponse(URL_SECOND, js);
757 
758         loadPageVerifyTitle2(html);
759     }
760 
761     /**
762      * Moves a script element from a div element to the body element using <code>appendChild</code>.
763      * @throws Exception if the test fails
764      */
765     @Test
766     @Alerts({"executed", "start", "end"})
767     public void moveWithAppend() throws Exception {
768         final String html = DOCTYPE_HTML
769               + "<html><head></head><body>\n"
770               + "<div>\n"
771               + "<script>\n"
772               + LOG_TITLE_FUNCTION
773               + "</script>\n"
774               + "<script id='js1'>log('executed');</script>\n"
775               + "<script>\n"
776               + "  log('start');\n"
777               + "  var script = document.getElementById('js1');\n"
778               + "  document.body.appendChild(script);\n"
779               + "  log('end');\n"
780               + "</script>\n"
781               + "</div>\n"
782               + "</body></html>";
783 
784         loadPageVerifyTitle2(html);
785     }
786 
787     /**
788      * Moves a script element from a div element to the body element using <code>insertBefore</code>.
789      * @throws Exception if the test fails
790      */
791     @Test
792     @Alerts({"executed", "start", "end"})
793     public void moveWithInsert() throws Exception {
794         final String html = DOCTYPE_HTML
795               + "<html><head></head><body>\n"
796               + "<div>\n"
797               + "<script id='js1'>\n"
798               + LOG_TITLE_FUNCTION
799               + "  log('executed');\n"
800               + "</script>\n"
801               + "<script>\n"
802               + "  log('start');\n"
803               + "  var script = document.getElementById('js1');\n"
804               + "  document.body.insertBefore(script, null);\n"
805               + "  log('end');\n"
806               + "</script>\n"
807               + "</div>\n"
808               + "</body></html>";
809 
810         loadPageVerifyTitle2(html);
811     }
812 
813     /**
814      * @throws Exception if the test fails
815      */
816     @Test
817     @Alerts({"script-for", "TypeError", "script-body"})
818     public void scriptForEvent() throws Exception {
819         // IE accepts it with () or without
820         scriptForEvent("onload");
821         scriptForEvent("onload()");
822     }
823 
824     private void scriptForEvent(final String eventName) throws Exception {
825         final String html = DOCTYPE_HTML
826             + "<html><head>\n"
827             + "<script>\n"
828             + LOG_TITLE_FUNCTION
829             + "</script>\n"
830             + "<script FOR='window' EVENT='" + eventName + "' LANGUAGE='javascript'>\n"
831             + "  log('script-for');\n"
832             + "  try {\n"
833             + "    document.form1.txt.value = 'hello';\n"
834             + "    log(document.form1.txt.value);\n"
835             + "  } catch(e) {logEx(e); }\n"
836             + "</script></head>\n"
837             + "<body>\n"
838             + "  <form name='form1'><input type='text' name='txt'></form>\n"
839             + "  <script>\n"
840             + "    log('script-body');\n"
841             + "  </script>\n"
842             + "</body></html>";
843 
844         loadPageVerifyTitle2(html);
845     }
846 
847     /**
848      * Verifies the correct the ordering of script element execution, deferred script element
849      * execution, script ready state changes, deferred script ready state changes, and onload
850      * handlers.
851      *
852      * @throws Exception if an error occurs
853      */
854     @Test
855     @Alerts({"3", "4", "2", "5"})
856     public void onReadyStateChange_Order() throws Exception {
857         final String html = DOCTYPE_HTML
858             + "<html>\n"
859             + "  <head>\n"
860             + "    <script>\n"
861             + LOG_TITLE_FUNCTION
862             + "    </script>\n"
863             + "    <script defer=''>log('3');</script>\n"
864             + "    <script defer onreadystatechange='if(this.readyState==\"complete\") log(\"6\");'>log('4');</script>\n"
865             + "    <script src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"1\");'></script>\n"
866             + "    <script defer='' src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"7\");'></script>\n"
867             + "    <script>log('2')</script>\n"
868             + "  </head>\n"
869             + "  <body onload='log(5)'></body>\n"
870             + "</html>";
871 
872         loadPageVerifyTitle2(html);
873     }
874 
875     /**
876      * @throws Exception if an error occurs
877      */
878     @Test
879     public void onReadyStateChange_EventAvailable() throws Exception {
880         final String html = DOCTYPE_HTML
881             + "<html><body><script>\n"
882             + LOG_TITLE_FUNCTION
883             + "var s = document.createElement('script');\n"
884             + "s.src = '//:';\n"
885             + "s.onreadystatechange = function() {log(window.event);};\n"
886             + "document.body.appendChild(s);\n"
887             + "</script></body></html>";
888 
889         loadPageVerifyTitle2(html);
890     }
891 
892     /**
893      * Verifies the correct the ordering of script element execution, deferred script element
894      * execution, script ready state changes, deferred script ready state changes, and onload
895      * handlers when the document doesn't have an explicit <tt>body</tt> element.
896      *
897      * @throws Exception if an error occurs
898      */
899     @Test
900     @Alerts({"3", "4", "2"})
901     public void onReadyStateChange_Order_NoBody() throws Exception {
902         final String html = DOCTYPE_HTML
903             + "<html>\n"
904             + "  <head>\n"
905             + "    <script>\n"
906             + LOG_TITLE_FUNCTION
907             + "    </script>\n"
908             + "    <script defer=''>log('3');</script>\n"
909             + "    <script defer='' onreadystatechange='if(this.readyState==\"complete\") log(\"5\");'>log('4');</script>\n"
910             + "    <script src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"1\");'></script>\n"
911             + "    <script defer='' src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"6\");'></script>\n"
912             + "    <script>log('2')</script>\n"
913             + "  </head>\n"
914             + "</html>";
915 
916         loadPageVerifyTitle2(html);
917     }
918 
919     /**
920      * @throws Exception if the test fails
921      */
922     @Test
923     @Alerts("1")
924     public void text() throws Exception {
925         final String html = DOCTYPE_HTML
926             + "<html>\n"
927             + "  <head>\n"
928             + "    <script>\n"
929             + LOG_TITLE_FUNCTION
930             + "      function test() {\n"
931             + "        execMe('log(1)');\n"
932             + "      }\n"
933             + "      function execMe(text) {\n"
934             + "        document.head = document.getElementsByTagName('head')[0];\n"
935             + "        var script = document.createElement('script');\n"
936             + "        script.text = text;\n"
937             + "        document.head.appendChild(script);\n"
938             + "        document.head.removeChild(script);\n"
939             + "      }\n"
940             + "    </script>\n"
941             + "  </head>\n"
942             + "  <body onload='test()'>\n"
943             + "  </body>\n"
944             + "</html>";
945 
946         loadPageVerifyTitle2(html);
947     }
948 
949     /**
950      * @throws Exception if the test fails
951      */
952     @Test
953     @Alerts("onload")
954     public void onload_after_deferReadStateComplete() throws Exception {
955         final String html = DOCTYPE_HTML
956             + "<html>\n"
957             + "  <head>\n"
958             + "    <script>\n"
959             + LOG_TITLE_FUNCTION
960             + "    </script>\n"
961             + "    <script onreadystatechange='if(this.readyState==\"complete\") log(\"defer\");' defer></script>\n"
962             + "  </head>\n"
963             + "  <body onload='log(\"onload\")'>\n"
964             + "  </body>\n"
965             + "</html>";
966 
967         loadPageVerifyTitle2(html);
968     }
969 
970     /**
971      * Regression test for bug 47038.
972      * <a href="http://sourceforge.net/tracker/?func=detail&atid=448266&aid=3403860&group_id=47038">issue</a>
973      * @throws Exception if the test fails
974      */
975     @Test
976     @Alerts({"1", "2", "3"})
977     public void scriptType() throws Exception {
978         final String html = DOCTYPE_HTML
979             + "<html>\n"
980             + "<head>\n"
981             + "<script>\n"
982             + LOG_TITLE_FUNCTION
983             + "</script>\n"
984             + "<script type='text/javascript'>log(1)</script>\n"
985             + "<script type=' text/javascript'>log(2)</script>\n"
986             + "<script type=' text/javascript '>log(3)</script>\n"
987             + "<script type=' text / javascript '>log(4)</script>\n"
988             + "</head>\n"
989             + "<body>\n"
990             + "</body></html>";
991 
992         loadPageVerifyTitle2(html);
993     }
994 
995     /**
996      * @throws Exception if the test fails
997      */
998     @Test
999     @Alerts("\\n\\s\\s<ul>{{for\\speople}}\\n\\s\\s\\s\\s<li>Name:\\s{{:name}}</li>\\n\\s\\s{{/for}}</ul>\\n")
1000     public void specialScriptType() throws Exception {
1001         final String html = DOCTYPE_HTML
1002             + "<html>\n"
1003             + "<head>\n"
1004             + "<script>\n"
1005             + LOG_TITLE_FUNCTION_NORMALIZE
1006             + "</script>\n"
1007             + "<script id='template' type='text/x-jsrender'>\n"
1008             + "  <ul>{{for people}}\n"
1009             + "    <li>Name: {{:name}}</li>\n"
1010             + "  {{/for}}</ul>\n"
1011             + "</script>\n"
1012 
1013             + "<script>\n"
1014             + "function doTest() {\n"
1015             + "  script = document.getElementById('template');\n"
1016             + "  log(script.innerHTML);\n"
1017             + "}\n"
1018             + "</script>\n"
1019 
1020             + "</head>\n"
1021             + "<body onload='doTest()'>\n"
1022             + "</body></html>";
1023 
1024         loadPageVerifyTitle2(html);
1025     }
1026 
1027     /**
1028      * Test exception throw by IE when calling <code>appendChild</code>.
1029      * @throws Exception if the test fails
1030      */
1031     @Test
1032     public void appendChild_UnexpectedCall() throws Exception {
1033         final String html = DOCTYPE_HTML
1034               + "<html><head></head><body>\n"
1035               + "<script>\n"
1036               + LOG_TITLE_FUNCTION
1037               + "  var script = document.createElement('script');\n"
1038               + "  var source = document.createTextNode(\"log('executed');\");\n"
1039               + "  try {\n"
1040               + "    script.appendChild(source);\n"
1041               + "  } catch(e) {\n"
1042               + "    log(e.message.slice(0,44));\n"
1043               + "  }\n"
1044               + "</script>\n"
1045               + "</body></html>";
1046 
1047         loadPageVerifyTitle2(html);
1048     }
1049 
1050     /**
1051      * Test exception throw by IE when calling <code>insertBefore</code>.
1052      * @throws Exception if the test fails
1053      */
1054     @Test
1055     public void insertBeforeUnexpectedCall() throws Exception {
1056         final String html = DOCTYPE_HTML
1057               + "<html><head><title>foo</title></head><body>\n"
1058               + "<script>\n"
1059               + LOG_TITLE_FUNCTION
1060               + "  var script = document.createElement('script');\n"
1061               + "  var source = document.createTextNode(\"log('executed');\");\n"
1062               + "  try {\n"
1063               + "    script.insertBefore(source, null);\n"
1064               + "  } catch(e) {\n"
1065               + "    log(e.message.slice(0,44));\n"
1066               + "  }\n"
1067               + "</script>\n"
1068               + "</body></html>";
1069 
1070         loadPageWithAlerts2(html);
1071     }
1072 
1073     /**
1074      * Firefox should not run scripts with "event" and "for" attributes.
1075      *
1076      * @throws Exception if the test fails
1077      */
1078     @Test
1079     @Alerts("onload for window")
1080     public void scriptEventFor() throws Exception {
1081         final String html = DOCTYPE_HTML
1082             + "<html>\n"
1083             + "<head>\n"
1084             + "<script>\n"
1085             + LOG_TITLE_FUNCTION
1086             + "</script>\n"
1087             + "</head><body>\n"
1088             + "  <script event='onload' for='window'>\n"
1089             + "    log('onload for window');\n"
1090             + "  </script>\n"
1091             + "  <div id='div1'>the div 1</div>\n"
1092             + "  <div id='div2'>the div 2</div>\n"
1093             + "  <script event='onclick' for='div1'>\n"
1094             + "    log('onclick for div1');\n"
1095             + "  </script>\n"
1096             + "  <script event='onclick' for='document.all.div2'>\n"
1097             + "    log('onclick for div2');\n"
1098             + "  </script>\n"
1099             + "</body></html>";
1100 
1101         final WebDriver webDriver = loadPage2(html);
1102         webDriver.findElement(By.id("div1")).click();
1103         webDriver.findElement(By.id("div2")).click();
1104 
1105         verifyTitle2(webDriver, getExpectedAlerts());
1106     }
1107 
1108     /**
1109      * @throws Exception if the test fails
1110      */
1111     @Test
1112     @Alerts({"function foo() { return a > b}", "function mce() { return a &gt; b}"})
1113     public void innerHtml() throws Exception {
1114         final String html = DOCTYPE_HTML
1115             + "<html><head>\n"
1116 
1117             + "<script id='script1'>function foo() { return a > b}</script>\n"
1118 
1119             + "<script>\n"
1120             + LOG_TITLE_FUNCTION
1121             + "function doTest() {\n"
1122             + "  script = document.getElementById('script1');\n"
1123             + "  log(script.innerHTML);\n"
1124 
1125             + "  script = document.getElementById('mce');\n"
1126             + "  log(script.innerHTML);\n"
1127 
1128             + "}\n"
1129             + "</script>\n"
1130             + "</head><body onload='doTest()'>\n"
1131             // this is done by TinyMce
1132             + "<script>document.write('<mce:script id=\"mce\">function mce() { return a > b}</mce:script>');</script>\n"
1133 
1134             + "</body></html>";
1135 
1136         loadPageVerifyTitle2(html);
1137     }
1138 
1139     /**
1140      * @throws Exception if the test fails
1141      */
1142     @Test
1143     @Alerts("\\n\\s\\s\\s\\s<script\\sid=\"testScript\">function\\sfoo()\\s{\\sreturn\\sa\\s>\\sb}</script>\\n\\s\\s")
1144     public void innerHTMLGetSet() throws Exception {
1145         final String html = DOCTYPE_HTML
1146             + "<html>\n"
1147             + "<head></head>\n"
1148             + "<body>\n"
1149 
1150             + "  <div id='tester'>\n"
1151             + "    <script id='testScript'>function foo() { return a > b}</script>\n"
1152             + "  </div>\n"
1153 
1154             + "  <script type='text/javascript'>\n"
1155             + LOG_TITLE_FUNCTION_NORMALIZE
1156             + "    var div = document.getElementById('tester');\n"
1157             + "    try {\n"
1158             + "      div.innerHTML = div.innerHTML;\n"
1159             + "    } catch(e) { logEx(e); }\n"
1160             + "    log(div.innerHTML);\n"
1161             + "  </script>\n"
1162 
1163             + "</body>\n"
1164             + "</html>\n";
1165 
1166         loadPageVerifyTitle2(html);
1167     }
1168 
1169     /**
1170      * @throws Exception if the test fails
1171      */
1172     @Test
1173     @Alerts("1 3 2")
1174     public void async() throws Exception {
1175         final String html = DOCTYPE_HTML
1176             + "<html><body>\n"
1177             + "<script src='js1.js'></script>\n"
1178             + "<script src='js2.js' async></script>\n"
1179             + "<script src='js3.js'></script>\n"
1180             + "</body></html>\n";
1181 
1182         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1183         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1184         getMockWebConnection().setResponse(new URL(URL_FIRST, "js3.js"), "document.title += ' 3';");
1185 
1186         final WebDriver driver = loadPage2(html);
1187         assertTitle(driver, getExpectedAlerts()[0]);
1188     }
1189 
1190     /**
1191      * The async attribute must not be used if the src attribute is absent (i.e. for inline scripts)
1192      * for classic scripts, in this case it would have no effect.
1193      *
1194      * @throws Exception if the test fails
1195      */
1196     @Test
1197     @Alerts("1 two 3 5 4")
1198     public void asyncWithoutSrc() throws Exception {
1199         final String html = DOCTYPE_HTML
1200             + "<html><body>\n"
1201             + "<script src='js1.js'></script>\n"
1202             + "<script async>document.title += ' two';</script>\n"
1203             + "<script src='js3.js'></script>\n"
1204             + "<script src='js4.js' async>document.title += ' four';</script>\n"
1205             + "<script src='js5.js'></script>\n"
1206             + "</body></html>\n";
1207 
1208         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1209         getMockWebConnection().setResponse(new URL(URL_FIRST, "js3.js"), "document.title += ' 3';");
1210         getMockWebConnection().setResponse(new URL(URL_FIRST, "js4.js"), "document.title += ' 4';");
1211         getMockWebConnection().setResponse(new URL(URL_FIRST, "js5.js"), "document.title += ' 5';");
1212 
1213         final WebDriver driver = loadPage2(html);
1214         assertTitle(driver, getExpectedAlerts()[0]);
1215     }
1216 
1217     /**
1218      * @throws Exception if the test fails
1219      */
1220     @Test
1221     @Alerts("2 1")
1222     @HtmlUnitNYI(CHROME = "1 2",
1223             EDGE = "1 2",
1224             FF = "1 2",
1225             FF_ESR = "1 2")
1226     public void async2() throws Exception {
1227         final String html = DOCTYPE_HTML
1228             + "<html><body>\n"
1229             + "<script>\n"
1230             + "  var s1 = document.createElement('script');\n"
1231             + "  s1.src = 'js1.js';\n"
1232             + "  s1.async = true;\n"
1233             + "  document.body.appendChild(s1);\n"
1234             + "</script>\n"
1235             + "<script src='js2.js'></script>\n"
1236             + "</body></html>\n";
1237 
1238         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1239         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1240 
1241         final WebDriver driver = loadPage2(html);
1242         assertTitle(driver, getExpectedAlerts()[0]);
1243     }
1244 
1245     /**
1246      * @throws Exception if the test fails
1247      */
1248     @Test
1249     @Alerts("0 3 2 1")
1250     @HtmlUnitNYI(CHROME = "0 3 1 2",
1251             EDGE = "0 3 1 2",
1252             FF = "0 3 1 2",
1253             FF_ESR = "0 3 1 2")
1254     public void syncLoadsAsync() throws Exception {
1255         final String html = DOCTYPE_HTML
1256             + "<html><body>\n"
1257             + "<script>\n"
1258             + "  document.title += ' 0';"
1259             + "  var s1 = document.createElement('script');\n"
1260             + "  s1.src = 'js1.js';\n"
1261             + "  s1.async = true;\n"
1262             + "  document.body.appendChild(s1);\n"
1263             + "  document.title += ' 3';"
1264             + "</script>\n"
1265             + "<script src='js2.js'></script>\n"
1266             + "</body></html>\n";
1267 
1268         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1269         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1270 
1271         final WebDriver driver = loadPage2(html);
1272         assertTitle(driver, getExpectedAlerts()[0]);
1273     }
1274 
1275     /**
1276      * @throws Exception if the test fails
1277      */
1278     @Test
1279     @Alerts(DEFAULT = "2 0 3 1",
1280             FF_ESR = "0 3 2 1")
1281     @HtmlUnitNYI(FF_ESR = "2 0 3 1")
1282     public void asyncLoadsAsync() throws Exception {
1283         final String html = DOCTYPE_HTML
1284             + "<html><body>\n"
1285             + "<script src='script.js' async></script>\n"
1286             + "<script src='js2.js'></script>\n"
1287             + "</body></html>\n";
1288 
1289         final String script =
1290                 "  document.title += ' 0';"
1291                 + "  var s1 = document.createElement('script');\n"
1292                 + "  s1.src = 'js1.js';\n"
1293                 + "  s1.async = true;\n"
1294                 + "  document.body.appendChild(s1);\n"
1295                 + "  document.title += ' 3';\n";
1296 
1297         getMockWebConnection().setResponse(new URL(URL_FIRST, "script.js"), script);
1298 
1299         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1300         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1301 
1302         final WebDriver driver = loadPage2(html);
1303         assertTitle(driver, getExpectedAlerts()[0]);
1304     }
1305 
1306     /**
1307      * @throws Exception if the test fails
1308      */
1309     @Test
1310     @Alerts({"1", "2", "3"})
1311     public void syncFromAsyncTask() throws Exception {
1312         final String html = DOCTYPE_HTML
1313             + "<html><body><script>\n"
1314             + LOG_TITLE_FUNCTION
1315             + "function addScript() {\n"
1316             + "  var script = document.createElement('script');\n"
1317             + "  script.src = 'js.js';\n"
1318             + "  document.head.appendChild(script);\n"
1319             + "  log('2');\n"
1320             + "}\n"
1321             + "setTimeout(addScript, 5);\n"
1322             + "  log('1');\n"
1323             + "</script></body></html>\n";
1324 
1325         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('3')");
1326 
1327         final WebDriver driver = loadPage2(html);
1328         verifyTitle2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts());
1329     }
1330 
1331     /**
1332      * @throws Exception if the test fails
1333      */
1334     @Test
1335     @Alerts({"1", "2", "3"})
1336     public void asyncFromAsyncTask() throws Exception {
1337         final String html = DOCTYPE_HTML
1338             + "<html><body><script>\n"
1339             + LOG_TITLE_FUNCTION
1340             + "function addAsyncScript() {\n"
1341             + "  var script = document.createElement('script');\n"
1342             + "  script.src = 'js.js';\n"
1343             + "  script.async = true;\n"
1344             + "  document.head.appendChild(script);\n"
1345             + "  log('2');\n"
1346             + "}\n"
1347             + "setTimeout(addAsyncScript, 5);\n"
1348             + "  log('1');\n"
1349             + "</script></body></html>\n";
1350 
1351         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('3')");
1352 
1353         final WebDriver driver = loadPage2(html);
1354         verifyTitle2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts());
1355     }
1356 
1357     /**
1358      * @throws Exception if the test fails
1359      */
1360     @Test
1361     @Alerts({"undefined", "append", "append done", "from script", "undefined"})
1362     public void asyncOnLoad() throws Exception {
1363         final String html = DOCTYPE_HTML
1364                 + "<html><body>\n"
1365                 + "<script>\n"
1366                 + LOG_TITLE_FUNCTION
1367                 + "</script>\n"
1368                 + "<script>\n"
1369                 + "  var script = document.createElement('script');\n"
1370                 + "  log(script.readyState);\n"
1371                 + "  script.src = 'js.js';\n"
1372                 + "  script.async = true;\n"
1373                 + "  script.onload = function () {\n"
1374                 + "    log(this.readyState);\n"
1375                 + "  };\n"
1376                 + "  log('append');\n"
1377                 + "  document.body.appendChild(script);\n"
1378                 + "  log('append done');\n"
1379                 + "</script>\n"
1380                 + "</body></html>\n";
1381 
1382         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('from script');");
1383 
1384         final WebDriver driver = loadPage2(html);
1385         verifyTitle2(driver, getExpectedAlerts());
1386     }
1387 
1388     /**
1389      * @throws Exception if the test fails
1390      */
1391     @Test
1392     @Alerts({"false", "null", "true", "", "true", "", "false", "null"})
1393     public void asyncProperty() throws Exception {
1394         final String html = DOCTYPE_HTML
1395             + "<html>\n"
1396             + "<head>\n"
1397             + "<script id='script1' src='js1.js'></script>\n"
1398             + "<script id='script2' src='js2.js' async></script>\n"
1399             + "<script>\n"
1400             + LOG_TITLE_FUNCTION
1401             + "function doTest() {\n"
1402             + "  var script = document.getElementById('script1');\n"
1403             + "  log(script.async);\n"
1404             + "  log(script.getAttribute('async'));\n"
1405 
1406             + "  script.async = true;\n"
1407             + "  log(script.async);\n"
1408             + "  log(script.getAttribute('async'));\n"
1409 
1410             + "  script = document.getElementById('script2');\n"
1411             + "  log(script.async);\n"
1412             + "  log(script.getAttribute('async'));\n"
1413 
1414             + "  script.async = false;\n"
1415             + "  log(script.async);\n"
1416             + "  log(script.getAttribute('async'));\n"
1417 
1418             + "}\n"
1419             + "</script>\n"
1420             + "</head><body onload='doTest()'>\n"
1421             + "</body></html>\n";
1422 
1423         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "");
1424         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "");
1425 
1426         loadPageVerifyTitle2(html);
1427     }
1428 
1429     /**
1430      * @throws Exception if the test fails
1431      */
1432     @Test
1433     @Alerts({"false", "null", "true", "true", "true", "", "true", "true", "false", "null"})
1434     public void asyncAttribute() throws Exception {
1435         final String html = DOCTYPE_HTML
1436             + "<html>\n"
1437             + "<head>\n"
1438             + "<script id='script1' src='js1.js'></script>\n"
1439             + "<script id='script2' src='js2.js' async></script>\n"
1440             + "<script>\n"
1441             + LOG_TITLE_FUNCTION
1442             + "function doTest() {\n"
1443             + "  var script = document.getElementById('script1');\n"
1444             + "  log(script.async);\n"
1445             + "  log(script.getAttribute('async'));\n"
1446 
1447             + "  script.setAttribute('async', true);\n"
1448             + "  log(script.async);\n"
1449             + "  log(script.getAttribute('async'));\n"
1450 
1451             + "  script = document.getElementById('script2');\n"
1452             + "  log(script.async);\n"
1453             + "  log(script.getAttribute('async'));\n"
1454 
1455             + "  script.setAttribute('async', true);\n"
1456             + "  log(script.async);\n"
1457             + "  log(script.getAttribute('async'));\n"
1458 
1459             + "  script.removeAttribute('async');\n"
1460             + "  log(script.async);\n"
1461             + "  log(script.getAttribute('async'));\n"
1462             + "}\n"
1463             + "</script>\n"
1464             + "</head><body onload='doTest()'>\n"
1465             + "</body></html>\n";
1466 
1467         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "");
1468         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "");
1469 
1470         loadPageVerifyTitle2(html);
1471     }
1472 
1473     /**
1474      * <a href="https://github.com/HtmlUnit/htmlunit/issues/11">issue #11</a>.
1475      * @throws Exception if an error occurs
1476      */
1477     @Test
1478     @Alerts("inside script.js")
1479     public void loadScriptDynamicallyAdded() throws Exception {
1480         final String html = DOCTYPE_HTML
1481             + "<html>\n"
1482             + "  <head>\n"
1483             + "    <script>\n"
1484             + LOG_TITLE_FUNCTION
1485             + "      function test() {\n"
1486             + "        var script = document.createElement('script');\n"
1487             + "        script.type = 'text/javascript';\n"
1488             + "        script.async = true;\n"
1489             + "        script.src = 'script.js';\n"
1490 
1491             + "        var s = document.getElementsByTagName('script')[0];\n"
1492             + "        s.parentNode.insertBefore(script, s);\n"
1493             + "      }\n"
1494             + "    </script>\n"
1495             + "  </head>\n"
1496             + "  <body onload='test()'>\n"
1497             + "  </body></html>";
1498 
1499         final String js = "log('inside script.js');";
1500 
1501         getMockWebConnection().setDefaultResponse(js, MimeType.TEXT_JAVASCRIPT);
1502 
1503         loadPageVerifyTitle2(html);
1504     }
1505 
1506     /**
1507      * JQuery disables script execution this way.
1508      * @throws Exception if an error occurs
1509      */
1510     @Test
1511     @Alerts({"change type", "type changed"})
1512     public void loadScriptDynamicallyAddedUnsupportedType() throws Exception {
1513         final String html = DOCTYPE_HTML
1514             + "<html>\n"
1515             + "  <head>\n"
1516             + "    <script>\n"
1517             + LOG_TITLE_FUNCTION
1518             + "      function test() {\n"
1519             + "        var script = document.createElement('script');\n"
1520             + "        script.type = 'true/text/javascript';\n"
1521             + "        script.src = 'script.js';\n"
1522 
1523             + "        var s = document.getElementsByTagName('script')[0];\n"
1524             + "        s.parentNode.insertBefore(script, s);\n"
1525 
1526             + "        log('change type');\n"
1527             + "        s.type = 'text/javascript';\n"
1528             + "        log('type changed');\n"
1529             + "      }\n"
1530             + "    </script>\n"
1531             + "  </head>\n"
1532             + "  <body onload='test()'>\n"
1533             + "  </body></html>";
1534 
1535         final String js = "log('inside script.js');";
1536 
1537         getMockWebConnection().setDefaultResponse(js, MimeType.TEXT_JAVASCRIPT);
1538 
1539         loadPageVerifyTitle2(html);
1540     }
1541 
1542     /**
1543      * @throws Exception if the test fails
1544      */
1545     @Test
1546     @Alerts({"out", "\\n\\s\\s\\s\\s<!--\\syy\\s--!>\\n\\s\\s\\s\\slog('out');\\n\\s\\s"})
1547     public void incorrectlyClosedComment() throws Exception {
1548         final String html = DOCTYPE_HTML
1549             + "<html>\n"
1550             + "<head>\n"
1551             + "  <script>\n"
1552             + LOG_TITLE_FUNCTION_NORMALIZE
1553             + "  </script>\n"
1554             + "  <script id='testScript'>\n"
1555             + "    <!-- yy --!>\n"
1556             + "    log('out');\n"
1557             + "  </script>\n"
1558             + "</head>\n"
1559             + "<body>\n"
1560             + "  <!-- xx -->\n"
1561 
1562             + "  <script >\n"
1563             + "    log(document.getElementById('testScript').innerHTML);\n"
1564             + "  </script>\n"
1565 
1566             + "</body>\n"
1567             + "</html>\n";
1568 
1569         loadPageVerifyTitle2(html);
1570     }
1571 
1572     /**
1573      * @throws Exception if the test fails
1574      */
1575     @Test
1576     @Alerts({"null-", "testType-testType", "-"})
1577     public void modifyType() throws Exception {
1578         final String html = DOCTYPE_HTML
1579             + "<html>\n"
1580             + "<head>\n"
1581             + "  <script id='testScript'></script>\n"
1582             + "</head>\n"
1583             + "<body>\n"
1584 
1585             + "  <script >\n"
1586             + LOG_TITLE_FUNCTION
1587             + "    var script = document.getElementById('testScript');\n"
1588             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1589 
1590             + "    script.type = 'testType';\n"
1591             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1592 
1593             + "    script.type = '';\n"
1594             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1595 
1596             + "  </script>\n"
1597 
1598             + "</body>\n"
1599             + "</html>\n";
1600 
1601         loadPageVerifyTitle2(html);
1602     }
1603 
1604     /**
1605      * @throws Exception if the test fails
1606      */
1607     @Test
1608     @Alerts({"typeAttr-typeAttr", "null-", "newType-newType", "null-null"})
1609     public void modifyTypeAttribute() throws Exception {
1610         final String html = DOCTYPE_HTML
1611             + "<html>\n"
1612             + "<head>\n"
1613             + "  <script id='testScript' type='typeAttr'></script>\n"
1614             + "</head>\n"
1615             + "<body>\n"
1616 
1617             + "  <script >\n"
1618             + LOG_TITLE_FUNCTION
1619             + "    var script = document.getElementById('testScript');\n"
1620             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1621 
1622             + "    script.removeAttribute('type');\n"
1623             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1624 
1625             + "    script.setAttribute('type', 'newType');\n"
1626             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1627 
1628             + "    script.setAttribute('type', null);\n"
1629             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1630 
1631             + "  </script>\n"
1632 
1633             + "</body>\n"
1634             + "</html>\n";
1635 
1636         loadPageVerifyTitle2(html);
1637     }
1638 
1639     /**
1640      * @throws Exception if the test fails
1641      */
1642     @Test
1643     @Alerts({"typeAttr", "text/javascript"})
1644     public void modifyTypeToJs() throws Exception {
1645         final String html = DOCTYPE_HTML
1646             + "<html>\n"
1647             + "<head>\n"
1648             + "<script>\n"
1649             + LOG_TITLE_FUNCTION
1650             + "</script>\n"
1651             + "  <script id='testScript' type='typeAttr'>log('exec');</script>\n"
1652             + "</head>\n"
1653             + "<body>\n"
1654 
1655             + "  <script >\n"
1656             + "    var script = document.getElementById('testScript');\n"
1657             + "    log(script.getAttribute('type'));\n"
1658 
1659             + "    script.type = 'text/javascript';\n"
1660             + "    log(script.getAttribute('type'));\n"
1661             + "  </script>\n"
1662 
1663             + "</body>\n"
1664             + "</html>\n";
1665 
1666         loadPageVerifyTitle2(html);
1667     }
1668 
1669     /**
1670      * @throws Exception if an error occurs
1671      */
1672     @Test
1673     @Alerts("onerror")
1674     public void onErrorHandler() throws Exception {
1675         final String html = DOCTYPE_HTML
1676             + "<html>\n"
1677             + "  <head>\n"
1678             + "    <script>\n"
1679             + LOG_TITLE_FUNCTION
1680             + "    </script>\n"
1681             + "    <script src='http://www.unknown-host.xyz' onload='log(\"onload\")' onerror='log(\"onerror\")'></script>\n"
1682             + "  </head>\n"
1683             + "  <body>\n"
1684             + "  </body></html>";
1685 
1686         loadPageVerifyTitle2(html);
1687     }
1688 
1689     /**
1690      * @throws Exception if the test fails
1691      */
1692     @Test
1693     @Alerts({"var x = 'HtmlUnit'", "</> htmx rocks!"})
1694     public void innerHtml1() throws Exception {
1695         final String html = DOCTYPE_HTML
1696             + "<html>\n"
1697             + "  <head>\n"
1698             + "    <title>Page Title</title>\n"
1699             + "    <script>\n"
1700             + LOG_TEXTAREA_FUNCTION
1701             + "      function test() {\n"
1702             + "        var script = document.getElementsByTagName('script')[1];\n"
1703             + "        log(script.innerHTML);\n"
1704             + "        script.innerHTML = '</> htmx rocks!';\n"
1705             + "        log(script.innerHTML);\n"
1706             + "      }\n"
1707             + "    </script>\n"
1708             + "  </head>\n"
1709             + "  <body onload='test()'>"
1710             + "    <script>var x = 'HtmlUnit'</script>\n"
1711             + LOG_TEXTAREA
1712             + "  </body>\n"
1713             + "</html>";
1714 
1715         loadPageVerifyTextArea2(html);
1716     }
1717 
1718     /**
1719      * @throws Exception if the test fails
1720      */
1721     @Test
1722     @Alerts({"var x = 'HtmlUnit'", "<div>htmx rocks</div>"})
1723     public void innerHtmlTag() throws Exception {
1724         final String html = DOCTYPE_HTML
1725             + "<html>\n"
1726             + "  <head>\n"
1727             + "    <title>Page Title</title>\n"
1728             + "    <script>\n"
1729             + LOG_TEXTAREA_FUNCTION
1730             + "      function test() {\n"
1731             + "        var script = document.getElementsByTagName('script')[1];\n"
1732             + "        log(script.innerHTML);\n"
1733             + "        script.innerHTML = '<div>htmx rocks</div>';\n"
1734             + "        log(script.innerHTML);\n"
1735             + "      }\n"
1736             + "    </script>\n"
1737             + "  </head>\n"
1738             + "  <body onload='test()'>\n"
1739             + "    <script>var x = 'HtmlUnit'</script>\n"
1740             + LOG_TEXTAREA
1741             + "  </body>\n"
1742             + "</html>";
1743 
1744         loadPageVerifyTextArea2(html);
1745     }
1746 
1747     /**
1748      * @throws Exception if the test fails
1749      */
1750     @Test
1751     @Alerts({"", "&lt;/> htmx rocks!"})
1752     public void innerHtmlEscaping() throws Exception {
1753         final String html = DOCTYPE_HTML
1754             + "<html>\n"
1755             + "  <head>\n"
1756             + "    <title>Page Title</title>\n"
1757             + "    <script>\n"
1758             + LOG_TEXTAREA_FUNCTION
1759             + "      function test() {\n"
1760             + "        var script = document.getElementsByTagName('script')[1];\n"
1761             + "        log(script.innerHTML);\n"
1762             + "        script.innerHTML = '&lt;/> htmx rocks!';\n"
1763             + "        log(script.innerHTML);\n"
1764             + "      }\n"
1765             + "    </script>\n"
1766             + "  </head>\n"
1767             + "  <body onload='test()'>\n"
1768             + "    <script></script>\n"
1769             + LOG_TEXTAREA
1770             + "  </body>\n"
1771             + "</html>";
1772 
1773         loadPageVerifyTextArea2(html);
1774     }
1775 }