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 static java.nio.charset.StandardCharsets.ISO_8859_1;
18  import static java.nio.charset.StandardCharsets.UTF_8;
19  
20  import java.net.URL;
21  import java.nio.charset.StandardCharsets;
22  import java.util.List;
23  
24  import org.htmlunit.MockWebConnection;
25  import org.htmlunit.WebDriverTestCase;
26  import org.htmlunit.junit.annotation.Alerts;
27  import org.htmlunit.junit.annotation.HtmlUnitNYI;
28  import org.htmlunit.util.MimeType;
29  import org.junit.jupiter.api.Test;
30  import org.openqa.selenium.By;
31  import org.openqa.selenium.WebDriver;
32  import org.openqa.selenium.WebElement;
33  
34  /**
35   * Tests for {@link HTMLDocument}'s write(ln) function.
36   *
37   * @author Ahmed Ashour
38   * @author Marc Guillemot
39   * @author Frank Danek
40   * @author Ronald Brill
41   */
42  public class HTMLDocumentWrite2Test extends WebDriverTestCase {
43  
44      /**
45       * @throws Exception if the test fails
46       */
47      @Test
48      @Alerts("[object HTMLDocument]")
49      public void openResult() throws Exception {
50          final String html = DOCTYPE_HTML
51              + "<html>\n"
52              + "<head>\n"
53              + "<script>\n"
54              + LOG_WINDOW_NAME_FUNCTION
55              + "function test() {\n"
56              + "  var res = document.open();\n"
57              + "  log(res);\n"
58              + "  document.close();\n"
59              + "}\n"
60              + "</script>\n"
61              + "</head>\n"
62              + "<body onload='setTimeout(test, 4);'>\n"
63              + "</body>\n"
64              + "</html>";
65  
66          loadPage2(html);
67          verifyWindowName2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
68      }
69  
70      /**
71       * @throws Exception if the test fails
72       */
73      @Test
74      @Alerts("Hello There")
75      public void write() throws Exception {
76          final String html = DOCTYPE_HTML
77              + "<html>\n"
78              + "<head>\n"
79              + "<title>Test</title>\n"
80              + "<script>\n"
81              + LOG_WINDOW_NAME_FUNCTION
82              + "function test() {\n"
83              + "  document.write('<html><body><scr'+'ipt>log(\"Hello There\")</scr'+'ipt></body></html>');\n"
84              + "}\n"
85              + "</script>\n"
86              + "</head>\n"
87              + "<body onload='setTimeout(test, 4);'>\n"
88              + "</body>\n"
89              + "</html>";
90  
91          loadPage2(html);
92          verifyWindowName2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
93      }
94  
95      /**
96       * @throws Exception if the test fails
97       */
98      @Test
99      public void writeSomeTags() throws Exception {
100         final String html = DOCTYPE_HTML
101             + "<html><head></head>\n"
102             + "<body>\n"
103             + "<script>\n"
104             + "document.write(\"<div id='div1'></div>\");\n"
105             + "document.write('<div', \" id='div2'>\", '</div>');\n"
106             + "document.writeln('<p', \" id='p3'>\", '</p>');\n"
107             + "</script>\n"
108             + "</form></body></html>";
109 
110         final WebDriver driver = loadPage2(html);
111 
112         assertEquals("div", driver.findElement(By.id("div1")).getTagName());
113         assertEquals("div", driver.findElement(By.id("div2")).getTagName());
114         assertEquals("p", driver.findElement(By.id("p3")).getTagName());
115     }
116 
117     /**
118      * <a href="https://sourceforge.net/tracker/?func=detail&aid=2855731&group_id=47038&atid=448266">Bug 2855731</a>.
119      * @throws Exception if an error occurs
120      */
121     @Test
122     @Alerts("1")
123     public void write_nested() throws Exception {
124         final String html = DOCTYPE_HTML
125             + "<html><body><script>\n"
126             + LOG_WINDOW_NAME_FUNCTION
127             + "var s = '\"<script>log(1);<\\/scr\" + \"ipt>\"';\n"
128             + "document.write('<script><!--\\ndocument.write(' + s + ');\\n--><\\/script>');\n"
129             + "</script></body></html>";
130 
131         loadPage2(html);
132         verifyWindowName2(getWebDriver(), getExpectedAlerts());
133     }
134 
135     /**
136      * Caused infinite loop at some point of 2.6 snapshot.
137      * See <a href="http://sourceforge.net/support/tracker.php?aid=2824922">Bug 2824922</a>
138      * @throws Exception if the test fails
139      */
140     @Test
141     public void write2_html_endhtml_in_head() throws Exception {
142         final String html = DOCTYPE_HTML
143             + "<html><head>\n"
144             + "<script>\n"
145             + "document.write('<HTML></HTML>');\n"
146             + "</script>\n"
147             + "</head><body>\n"
148             + "</body></html>\n";
149 
150         loadPage2(html);
151     }
152 
153     /**
154      * We couldn't document.write() script elements that contained the '&lt;' character...
155      * @exception Exception if the test fails
156      */
157     @Test
158     @Alerts("true")
159     public void writeScript() throws Exception {
160         final String html = DOCTYPE_HTML
161             + "<html><body><script>\n"
162             + LOG_WINDOW_NAME_FUNCTION
163             + "  document.write('<scr'+'ipt>log(1<2)</sc'+'ript>');\n"
164             + "</script></body></html>";
165 
166         loadPage2(html);
167         verifyWindowName2(getWebDriver(), getExpectedAlerts());
168     }
169 
170     /**
171      * @throws Exception if the test fails
172      */
173     @Test
174     public void writeUnicode() throws Exception {
175         final String html = DOCTYPE_HTML
176             + "<html><body><script>\n"
177             + "document.open();\n"
178             + "document.write('<div id=\"assert\">Hello worl\u0414</div>');\n"
179             + "document.close();\n"
180             + "</script>\n"
181             + "</body></html>";
182 
183         final WebDriver driver = loadPage2(html, URL_FIRST, "text/html; charset=UTF-8", UTF_8);
184         final String result = driver.findElement(By.id("assert")).getText();
185         assertEquals("Hello worl\u0414", result);
186     }
187 
188     /**
189      * @throws Exception if the test fails
190      */
191     @Test
192     public void writeISO_8859_1() throws Exception {
193         final String html = DOCTYPE_HTML
194             + "<html><body><script>\n"
195             + "document.open();\n"
196             + "document.write('<div id=\"assert\">\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc</div>');\n"
197             + "document.close();\n"
198             + "</script>\n"
199             + "</body></html>";
200 
201         final WebDriver driver = loadPage2(html, URL_FIRST, "text/html; charset=ISO-8859-1", ISO_8859_1);
202         final String result = driver.findElement(By.id("assert")).getText();
203         assertEquals("\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc", result);
204     }
205 
206     /**
207      * @throws Exception if the test fails
208      */
209     @Test
210     public void open_FF() throws Exception {
211         final String html = DOCTYPE_HTML
212             + "<html><head><title>foo</title><script>\n"
213             + "  function performAction() {\n"
214             + "    actionwindow = window.open('', '1205399746518', "
215             + "'location=no,scrollbars=no,resizable=no,width=200,height=275');\n"
216             + "    actionwindow.document.writeln('Please wait while connecting to server...');\n"
217             + "    actionwindow.focus();\n"
218             + "    actionwindow.close();\n"
219             + "  }\n"
220             + "</script></head><body>\n"
221             + "  <input value='Click Me' type=button onclick='performAction()'>\n"
222             + "</body></html>";
223 
224         final WebDriver driver = loadPageWithAlerts2(html);
225         driver.findElement(By.xpath("//input")).click();
226     }
227 
228     /**
229      * Regression test for bug 2884585.
230      * As of HtmlUnit-2.7-SNAPSHOT 17.01.2010 &lt;script src="..."... written
231      * by document.write was not loaded and executed after the &lt;/script&gt;
232      * when the page was loaded as result of a click.
233      * @throws Exception if the test fails
234      */
235     @Test
236     @Alerts({" after-write Hello", " after-write Hello after-write Hello"})
237     public void writeExternalScriptAfterClick() throws Exception {
238         shutDownAll();
239 
240         final String html = DOCTYPE_HTML
241             + "<html><head>\n"
242             + "<script>\n"
243             + "document.write('<scr'+'ipt src=\"script.js\"></scr'+'ipt>');\n"
244             + "window.name += ' after-write ';\n"
245             + "</script>\n"
246             + "<script>\n"
247             + "window.name += window.foo;\n"
248             + "</script>\n"
249             + "</head>\n"
250             + "<body>\n"
251             + "<a href='?again'>a link</a>\n"
252             + "</body>\n"
253             + "</html>";
254 
255         getMockWebConnection().setDefaultResponse("window.foo = 'Hello'", MimeType.TEXT_JAVASCRIPT);
256         final WebDriver driver = loadPage2(html);
257         verifyJsVariable(driver, "window.top.name", getExpectedAlerts()[0]);
258 
259         driver.findElement(By.linkText("a link")).click();
260         verifyJsVariable(driver, "window.top.name", getExpectedAlerts()[1]);
261     }
262 
263     /**
264      * Regression test for bug 2921851.
265      * @throws Exception if the test fails
266      */
267     @Test
268     @Alerts("#1")
269     @HtmlUnitNYI(CHROME = "#0",
270             EDGE = "#0",
271             FF = "#0",
272             FF_ESR = "#0")
273     public void writeInNewWindowAndReadFormCollection() throws Exception {
274         final String html = DOCTYPE_HTML
275             + "<html><head>\n"
276             + "<script>\n"
277             + "function test() {\n"
278             + "  var newWin = window.open('', 'myPopup', '');\n"
279             + "  var newDoc = newWin.document;\n"
280             + "  newDoc.write('<html><body><form name=newForm></form></body></html>');\n"
281             + "  document.title = '#' + newDoc.forms.length;\n"
282             + "}\n"
283             + "</script></head>\n"
284             + "<body onload='test()'>\n"
285             + "</body></html>";
286 
287         final WebDriver driver = loadPage2(html);
288         assertTitle(driver, getExpectedAlerts()[0]);
289     }
290 
291     /**
292      * Partial regression test for bug 2921851: use opener URL as base URL
293      * for resolution of relative URLs in document.write.
294      * @throws Exception if the test fails
295      */
296     @Test
297     @Alerts({"2", "§§URL§§foo"})
298     public void urlResolutionInWriteForm() throws Exception {
299         final String html = DOCTYPE_HTML
300             + "<html><head>\n"
301             + "<script>\n"
302             + "function test() {\n"
303             + "  var newWin = window.open('', 'myPopup', '');\n"
304             + "  var d = newWin.document;\n"
305             + "  d.write('<html><body><form action=foo method=post><input type=submit id=it></form></body></html>');\n"
306             + "  d.close();\n"
307             + "}\n"
308             + "</script></head>\n"
309             + "<body onload='test()'>\n"
310             + "</body></html>";
311 
312         final int startCount = getMockWebConnection().getRequestCount();
313         expandExpectedAlertsVariables(URL_FIRST);
314 
315         getMockWebConnection().setDefaultResponse("");
316         final WebDriver driver = loadPage2(html);
317         driver.switchTo().window("myPopup");
318         driver.findElement(By.id("it")).click();
319         if (useRealBrowser()) {
320             Thread.sleep(400);
321         }
322 
323         assertEquals(Integer.parseInt(getExpectedAlerts()[0]),
324                 getMockWebConnection().getRequestCount() - startCount);
325         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest().getUrl());
326     }
327 
328     /**
329      * Partial regression test for bug 2921851: the window returned by <tt>window.open()</tt> should
330      * be proxied (i.e. "live").
331      * @throws Exception if an error occurs
332      */
333     @Test
334     @Alerts("<form></form>#[object HTMLFormElement]")
335     public void writeOnOpenedWindow_WindowIsProxied() throws Exception {
336         final String html = DOCTYPE_HTML
337             + "<html><head><script>\n"
338             + "function test() {\n"
339             + "  var w = window.open('','blah','width=460,height=420');\n"
340             + "  w.document.write('<html><body><form></form></body></html>');\n"
341             + "  w.document.close();\n"
342             + "  document.title = w.document.body.innerHTML;\n"
343             + "  document.title += '#' + w.document.forms[0];\n"
344             + "}\n"
345             + "</script></head>\n"
346             + "<body onload='test()'>\n"
347             + "</body></html>";
348 
349         final WebDriver driver = loadPage2(html);
350         assertTitle(driver, getExpectedAlerts()[0]);
351     }
352 
353     /**
354      * Partial regression test for bug 2921851: the document returned by <tt>window.document</tt> should
355      * be proxied (i.e. "live").
356      * @throws Exception if an error occurs
357      */
358     @Test
359     @Alerts("<form></form>#[object HTMLFormElement]")
360     public void writeOnOpenedWindow_DocumentIsProxied() throws Exception {
361         final String html = DOCTYPE_HTML
362             + "<html><head><script>\n"
363             + "function test() {\n"
364             + "  var w = window.open('','blah','width=460,height=420');\n"
365             + "  var d = w.document;\n"
366             + "  d.write('<html><body><form></form></body></html>');\n"
367             + "  d.close();\n"
368             + "  document.title = d.body.innerHTML;\n"
369             + "  document.title += '#' + d.forms[0];\n"
370             + "}\n"
371             + "</script></head><body onload='test()'>foo</body></html>";
372 
373         try {
374             final WebDriver driver = loadPage2(html);
375             assertTitle(driver, getExpectedAlerts()[0]);
376         }
377         finally {
378             shutDownAll();
379         }
380     }
381 
382     /**
383      * This was causing a StackOverflowError.
384      *
385      * @throws Exception if an error occurs
386      */
387     @Test
388     public void writeInFrameWithOnload() throws Exception {
389         final String html = DOCTYPE_HTML
390             + "<html><head></head>\n"
391             + "<body>\n"
392             + "<iframe id='theIframe' src='about:blank'></iframe>\n"
393             + "<script>\n"
394             + "var doc = document.getElementById('theIframe').contentWindow.document;\n"
395             + "doc.open();\n"
396             + "doc.write('<html>');\n"
397             + "doc.write('<body onload=\"document.getElementById(\\'foo\\')\">');\n"
398             + "doc.write('</body></html>');\n"
399             + "doc.close();\n"
400             + "</script>\n"
401             + "</body>\n"
402             + "</html>";
403         loadPageWithAlerts2(html);
404     }
405 
406     /**
407      * Regression test for bug 743241.
408      * @throws Exception if the test fails
409      */
410     @Test
411     public void write_loadScript() throws Exception {
412         final String html = DOCTYPE_HTML
413             + "<html><head><title>First</title></head><body>\n"
414             + "<script src='script.js'></script>\n"
415             + "</form></body></html>";
416 
417         final String script = "document.write(\"<div id='div1'>hello</div>\");\n";
418         getMockWebConnection().setDefaultResponse(script, MimeType.TEXT_JAVASCRIPT);
419 
420         final WebDriver driver = loadPage2(html);
421         assertTitle(driver, "First");
422 
423         assertEquals("hello", driver.findElement(By.id("div1")).getText());
424     }
425 
426     /**
427      * @throws Exception if an error occurs
428      */
429     @Test
430     public void write_fromScriptAddedWithAppendChild_inline() throws Exception {
431         final String html = DOCTYPE_HTML
432             + "<html><head></head><body>\n"
433             + "<div id='it'><script>\n"
434             + LOG_WINDOW_NAME_FUNCTION
435             + "try {\n"
436             + "  var s = document.createElement('script');\n"
437             + "  var t = document.createTextNode(\"document.write('in inline script'); document.title = 'done';\");\n"
438             + "  s.appendChild(t);\n"
439             + "  document.body.appendChild(s);\n"
440             + "} catch(e) { logEx(e); }\n"
441             + "</script></div></body></html>";
442 
443         final WebDriver driver = loadPage2(html);
444         verifyWindowName2(getWebDriver(), getExpectedAlerts());
445 
446         assertTitle(driver, "done");
447         assertEquals("in inline script", driver.findElement(By.id("it")).getText());
448     }
449 
450     /**
451      * @throws Exception if an error occurs
452      */
453     @Test
454     public void write_fromScriptAddedWithAppendChild_external() throws Exception {
455         final String html = DOCTYPE_HTML
456                 + "<html><head></head><body>\n"
457                 + "<div id='it'>here</div><script>\n"
458                 + "  var s = document.createElement('script');\n"
459                 + "  s.src = 'foo.js';\n"
460                 + "  document.body.appendChild(s);\n"
461                 + "</script></body></html>";
462 
463         final String js = "document.write('from external script');\n"
464                     + "document.title = 'done';";
465 
466         getMockWebConnection().setDefaultResponse(js, MimeType.TEXT_JAVASCRIPT);
467         final WebDriver driver = loadPage2(html);
468 
469         assertTitle(driver, "done");
470         assertEquals("here", driver.findElement(By.id("it")).getText());
471         assertEquals("here", driver.findElement(By.tagName("body")).getText());
472     }
473 
474     /**
475      * Verifies that document.write() sends content to the correct destination (always somewhere in the body).
476      * @throws Exception if an error occurs
477      */
478     @Test
479     @Alerts({"null", "[object HTMLBodyElement]", "s1 s2 s3 s4 s5"})
480     public void write_Destination() throws Exception {
481         final String html = DOCTYPE_HTML
482             + "<html>\n"
483             + "  <head>\n"
484             + "    <script>" + LOG_WINDOW_NAME_FUNCTION + "</script>\n"
485             + "    <script>log(document.body);</script>\n"
486             + "    <script>document.write('<span id=\"s1\">1</span>');</script>\n"
487             + "    <script>log(document.body);</script>\n"
488             + "    <title>test</title>\n"
489             + "    <script>document.write('<span id=\"s2\">2</span>');</script>\n"
490             + "  </head>\n"
491             + "  <body id='foo'>\n"
492             + "    <script>document.write('<span id=\"s3\">3</span>');</script>\n"
493             + "    <span id='s4'>4</span>\n"
494             + "    <script>document.write('<span id=\"s5\">5</span>');</script>\n"
495             + "    <script>\n"
496             + "      var s = '';\n"
497             + "      for(var n = document.body.firstChild; n; n = n.nextSibling) {\n"
498             + "        if(n.id) {\n"
499             + "          if(s.length > 0) s+= ' ';\n"
500             + "            s += n.id;\n"
501             + "        }\n"
502             + "      }\n"
503             + "      log(s);\n"
504             + "    </script>\n"
505             + "  </body>\n"
506             + "</html>";
507 
508         loadPage2(html);
509         verifyWindowName2(getWebDriver(), getExpectedAlerts());
510     }
511 
512     /**
513      * Verifies that document.write() sends content to the correct destination (always somewhere in the body),
514      * and that if a synthetic temporary body needs to be created, the attributes of the real body are eventually
515      * used once the body is parsed.
516      * @throws Exception if an error occurs
517      */
518     @Test
519     @Alerts({"null", "[object HTMLBodyElement]", "", "foo"})
520     public void write_BodyAttributesKept() throws Exception {
521         final String html = DOCTYPE_HTML
522             + "<html>\n"
523             + "  <head>\n"
524             + "    <script>" + LOG_WINDOW_NAME_FUNCTION + "</script>\n"
525             + "    <script>log(document.body);</script>\n"
526             + "    <script>document.write('<span id=\"s1\">1</span>');</script>\n"
527             + "    <script>log(document.body);</script>\n"
528             + "    <script>log(document.body.id);</script>\n"
529             + "    <title>test</title>\n"
530             + "  </head>\n"
531             + "  <body id='foo'>\n"
532             + "    <script>log(document.body.id);</script>\n"
533             + "  </body>\n"
534             + "</html>";
535 
536         loadPage2(html);
537         verifyWindowName2(getWebDriver(), getExpectedAlerts());
538     }
539 
540     /**
541      * Verifies that document.write() sends content to the correct destination (always somewhere in the body),
542      * and that script elements written to the document are executed in the correct order.
543      * @throws Exception if an error occurs
544      */
545     @Test
546     @Alerts({"1", "2", "3"})
547     public void write_ScriptExecutionOrder() throws Exception {
548         final String html = DOCTYPE_HTML
549             + "<html>\n"
550             + "  <head>\n"
551             + "    <title>test</title>\n"
552             + "    <script>" + LOG_WINDOW_NAME_FUNCTION + "</script>\n"
553             + "    <script>log('1');</script>\n"
554             + "    <script>document.write('<scrip'+'t>log(\"2\")</s'+'cript>');</script>\n"
555             + "  </head>\n"
556             + "  <body>\n"
557             + "    <script>document.write('<scrip'+'t>log(\"3\")</s'+'cript>');</script>\n"
558             + "  </body>\n"
559             + "</html>";
560 
561         loadPage2(html);
562         verifyWindowName2(getWebDriver(), getExpectedAlerts());
563     }
564 
565     /**
566      * @throws Exception if the test fails
567      */
568     @Test
569     @Alerts("outer")
570     public void writeInManyTimes() throws Exception {
571         final String html = DOCTYPE_HTML
572             + "<html><head><title>foo</title><script>\n"
573             + LOG_WINDOW_NAME_FUNCTION
574             + "function doTest() {\n"
575             + "  log(document.getElementById('inner').parentNode.id);\n"
576             + "}\n"
577             + "</script></head>\n"
578             + "<body onload='doTest()'>\n"
579             + "<script>\n"
580             + "document.write('<div id=\"outer\">');\n"
581             + "document.write('<div id=\"inner\"/>');\n"
582             + "document.write('</div>');\n"
583             + "</script>\n"
584             + "</body></html>";
585 
586         loadPage2(html);
587         verifyWindowName2(getWebDriver(), getExpectedAlerts());
588     }
589 
590     /**
591      * Test for bug 1185389.
592      * @throws Exception if the test fails
593      */
594     @Test
595     @Alerts({"theBody", "theBody", "theBody"})
596     public void writeAddNodesToCorrectParent() throws Exception {
597         final String html = DOCTYPE_HTML
598              + "<html><head><title>foo</title></head>\n"
599              + "<body id=\"theBody\">\n"
600              + "<script>\n"
601              + LOG_WINDOW_NAME_FUNCTION
602              + "document.write('<p id=\"para1\">Paragraph #1</p>');\n"
603              + "document.write('<p id=\"para2\">Paragraph #2</p>');\n"
604              + "document.write('<p id=\"para3\">Paragraph #3</p>');\n"
605              + "log(document.getElementById('para1').parentNode.id);\n"
606              + "log(document.getElementById('para2').parentNode.id);\n"
607              + "log(document.getElementById('para3').parentNode.id);\n"
608              + "</script>\n"
609              + "</body></html>";
610 
611         loadPage2(html);
612         verifyWindowName2(getWebDriver(), getExpectedAlerts());
613     }
614 
615     /**
616      * Test for bug 436.
617      * http://sourceforge.net/p/htmlunit/bugs/436/
618      * @throws Exception if the test fails
619      */
620     @Test
621     @Alerts({"outer", "inner1"})
622     public void writeAddNodesToCorrectParent_Bug1678826() throws Exception {
623         final String html = DOCTYPE_HTML
624              + "<html><head><title>foo</title><script>\n"
625              + LOG_WINDOW_NAME_FUNCTION
626              + "function doTest() {\n"
627              + "  log(document.getElementById('inner1').parentNode.id);\n"
628              + "  log(document.getElementById('inner2').parentNode.id);\n"
629              + "}\n"
630              + "</script></head>\n"
631              + "<body onload='doTest()'>\n"
632              + "<script>\n"
633              + "document.write('<div id=\"outer\">');\n"
634              + "document.write('<br id=\"br1\">');\n"
635              + "document.write('<div id=\"inner1\"/>');\n"
636              + "document.write('<hr id=\"hr1\"/>');\n"
637              + "document.write('<div id=\"inner2\"/>');\n"
638              + "document.write('</div>');\n"
639              + "</script>\n"
640              + "</body></html>";
641 
642         loadPage2(html);
643         verifyWindowName2(getWebDriver(), getExpectedAlerts());
644 
645         releaseResources();
646         shutDownAll();
647     }
648 
649      /**
650       * @throws Exception if the test fails
651       */
652     @Test
653     @Alerts({"STYLE", "SCRIPT"})
654     public void writeStyle() throws Exception {
655         final String html = DOCTYPE_HTML
656              + "<html><head><title>foo</title></head><body>\n"
657              + "<script>\n"
658              + LOG_WINDOW_NAME_FUNCTION
659              + "  document.write('<style type=\"text/css\" id=\"myStyle\">');\n"
660              + "  document.write('  .nwr {white-space: nowrap;}');\n"
661              + "  document.write('</style>');\n"
662              + "  document.write('<div id=\"myDiv\">');\n"
663              + "  document.write('</div>');\n"
664              + "  log(document.getElementById('myDiv').previousSibling.nodeName);\n"
665              + "  log(document.getElementById('myStyle').previousSibling.nodeName);\n"
666              + "</script>\n"
667              + "</body></html>";
668 
669         loadPage2(html);
670         verifyWindowName2(getWebDriver(), getExpectedAlerts());
671     }
672 
673     /**
674      * @throws Exception if the test fails
675      */
676     @Test
677     public void openReplace() throws Exception {
678         final String html = DOCTYPE_HTML
679             + "<html>\n"
680             + "<head>\n"
681             + "  <title>Test</title>\n"
682             + "<script>\n"
683             + "function test() {\n"
684             + "  var htmlDocument = '<html><head>"
685                     + "<script>document.title = \"parsed script executed\";</' + 'script>"
686                     + "</head><body>After</body</head>';\n"
687             + "  var newHTML = document.open('text/html', 'replace');\n"
688             + "  newHTML.write(htmlDocument);\n"
689             + "  newHTML.close();\n"
690             + "}\n"
691             + "</script>\n"
692             + "</head>\n"
693             + "<body onload='setTimeout(test, 4);'>\n"
694             + " Before\n"
695             + "</body>\n"
696             + "</html>";
697 
698         final WebDriver driver = loadPageWithAlerts2(html);
699         assertTitle(driver, "parsed script executed");
700         assertEquals("After", driver.findElement(By.tagName("body")).getText());
701     }
702 
703     /**
704      * Verifies that scripts added to the document via document.write(...) don't execute until the current script
705      * finishes executing; bug found at <a href="http://code.google.com/apis/maps/">the Google Maps API site</a>.
706      * @throws Exception if an error occurs
707      */
708     @Test
709     public void write_scriptExecutionPostponed() throws Exception {
710         final String html = DOCTYPE_HTML
711             + "<html><body>\n"
712             + "<div id='d'></div>\n"
713             + "<script>function log(s) { document.getElementById('d').innerHTML += s + ' '; }</script>\n"
714             + "<script src='a.js'></script>\n"
715             + "<script>log(2);document.write('<scr'+'ipt src=\"b.js\"></scr'+'ipt>');log(3);</script>\n"
716             + "<script src='c.js'></script>\n"
717             + "<script>\n"
718             + "  log(6);document.write('<scr'+'ipt src=\"d.js\"></scr'+'ipt>');log(7);\n"
719             + "  log(8);document.write('<scr'+'ipt src=\"e.js\"></scr'+'ipt>');log(9);\n"
720             + "</script>\n"
721             + "<script src='f.js'></script>\n"
722             + "</body></html>";
723         final MockWebConnection conn = getMockWebConnection();
724         conn.setResponse(URL_FIRST, html);
725         conn.setResponse(new URL(URL_FIRST, "a.js"), "log(1)", MimeType.TEXT_JAVASCRIPT);
726         conn.setResponse(new URL(URL_FIRST, "b.js"), "log(4)", MimeType.TEXT_JAVASCRIPT);
727         conn.setResponse(new URL(URL_FIRST, "c.js"), "log(5)", MimeType.TEXT_JAVASCRIPT);
728         conn.setResponse(new URL(URL_FIRST, "d.js"), "log(10)", MimeType.TEXT_JAVASCRIPT);
729         conn.setResponse(new URL(URL_FIRST, "e.js"), "log(11)", MimeType.TEXT_JAVASCRIPT);
730         conn.setResponse(new URL(URL_FIRST, "f.js"), "log(12)", MimeType.TEXT_JAVASCRIPT);
731 
732         final WebDriver driver = loadPage2(html);
733         assertEquals("1 2 3 4 5 6 7 8 9 10 11 12", driver.findElement(By.tagName("body")).getText());
734     }
735 
736     /**
737      * Regression test for Bug #71.
738      * @throws Exception if the test fails
739      */
740     @Test
741     public void write_script() throws Exception {
742         final URL mainUrl = new URL(URL_FIRST, "main.html");
743         final URL firstUrl = new URL(URL_FIRST, "first.html");
744         final URL secondUrl = new URL(URL_FIRST, "second.html");
745         final URL scriptUrl = new URL(URL_FIRST, "script.js");
746 
747         final String mainHtml = DOCTYPE_HTML
748             + "<html>\n"
749             + "<head><title>Main</title></head>\n"
750             + "<body>\n"
751             + "  <iframe name='iframe' id='iframe' src='" + firstUrl + "'></iframe>\n"
752             + "  <script type='text/javascript'>\n"
753             + "    document.write('<script type=\"text/javascript\" src=\"" + scriptUrl + "\"></' + 'script>');\n"
754             + "  </script>"
755             + "</body></html>";
756 
757         getMockWebConnection().setResponse(mainUrl, mainHtml);
758 
759         final String firstHtml = DOCTYPE_HTML + "<html><body><h1 id='first'>First</h1></body></html>";
760         getMockWebConnection().setResponse(firstUrl, firstHtml);
761 
762         final String secondHtml = DOCTYPE_HTML + "<html><body><h1 id='second'>Second</h1></body></html>";
763         getMockWebConnection().setResponse(secondUrl, secondHtml);
764 
765         final String script = "document.getElementById('iframe').src = '" + secondUrl + "';\n";
766         getMockWebConnection().setResponse(new URL(URL_FIRST, "script.js"), script, MimeType.TEXT_JAVASCRIPT);
767 
768         final WebDriver driver = loadPage2(mainUrl, StandardCharsets.UTF_8);
769         assertEquals("Main", driver.getTitle());
770 
771         final WebElement iframe = driver.findElement(By.id("iframe"));
772         assertEquals(secondUrl.toExternalForm(), iframe.getAttribute("src"));
773 
774         driver.switchTo().frame(iframe);
775         assertEquals("Second", driver.findElement(By.id("second")).getText());
776     }
777 
778     /**
779      * @throws Exception if the test fails
780      */
781     @Test
782     @Alerts({"A", "A"})
783     public void write_InDOM() throws Exception {
784         final String html = DOCTYPE_HTML
785             + "<html>\n"
786             + "<head></head>\n"
787             + "<body>\n"
788             + "  <script type='text/javascript'>\n"
789             + LOG_TITLE_FUNCTION
790             + "    document.write('<a id=\"blah\">Hello World</a>');\n"
791             + "    document.write('<a id=\"blah2\">Hello World 2</a>');\n"
792             + "    log(document.getElementById('blah').tagName);\n"
793             + "    log(document.getElementById('blah2').tagName);\n"
794             + "  </script>\n"
795             + "  <a id='blah3'>Hello World 3</a>\n"
796             + "</body></html>";
797 
798         final WebDriver driver = loadPage2(html);
799         verifyTitle2(driver, getExpectedAlerts());
800 
801         final List<WebElement> anchors = driver.findElements(By.tagName("a"));
802         assertEquals(3, anchors.size());
803         assertEquals("Hello World", anchors.get(0).getText());
804         assertEquals("Hello World 2", anchors.get(1).getText());
805         assertEquals("Hello World 3", anchors.get(2).getText());
806     }
807 
808     /**
809      * Test for bug 1950462: calling document.write inside a function (after assigning
810      * document.write to a local variable) tries to invoke document.write on the prototype
811      * document instance, rather than the actual document host object. This leads to an
812      * {@link IllegalStateException} (DomNode has not been set for this SimpleScriptable).
813      * @throws Exception if an error occurs
814      */
815     @Test
816     @Alerts({"foo called", "exception occurred"})
817     public void write_AssignedToVar2() throws Exception {
818         final String html = DOCTYPE_HTML
819             + "<html>\n"
820             + "<head></head>\n"
821             + "<body>\n"
822             + "<script>\n"
823             + LOG_TITLE_FUNCTION
824             + "  function foo() { log('foo called'); var d = document.write; d(4); }\n"
825             + "  try {\n"
826             + "    foo();\n"
827             + "  } catch(e) { log('exception occurred'); document.write(7); }\n"
828             + "</script>\n"
829             + "</body></html>";
830 
831         final WebDriver driver = loadPage2(html);
832         verifyTitle2(driver, getExpectedAlerts());
833 
834         assertEquals("7", driver.findElement(By.tagName("body")).getText());
835     }
836 
837     /**
838      * Verifies that calling document.write() after document parsing has finished results in a whole
839      * new page being loaded.
840      * @throws Exception if an error occurs
841      */
842     @Test
843     public void write_WhenParsingFinished() throws Exception {
844         final String html = DOCTYPE_HTML
845             + "<html>\n"
846             + "<head>\n"
847             + "<script>\n"
848             + "  function test() { document.write(1); document.write(2); document.close(); }\n"
849             + "</script></head>\n"
850             + "<body>\n"
851             + "  <span id='s' onclick='test()'>click</span>\n"
852             + "</body></html>";
853 
854         final WebDriver driver = loadPage2(html);
855         assertEquals("click", driver.findElement(By.tagName("body")).getText());
856 
857         driver.findElement(By.id("s")).click();
858         assertEquals("12", driver.findElement(By.tagName("body")).getText());
859     }
860 
861     /**
862      * @throws Exception if the test fails
863      */
864     @Test
865     public void writeWithSplitAnchorTag() throws Exception {
866         final String html = DOCTYPE_HTML
867             + "<html>\n"
868             + "<body><script>\n"
869             + "document.write(\"<a href=\'start.html\");\n"
870             + "document.write(\"\'>\");\n"
871             + "document.write('click here</a>');\n"
872             + "</script>\n"
873             + "</body></html>";
874 
875         final WebDriver driver = loadPage2(html);
876 
877         final List<WebElement> anchors = driver.findElements(By.tagName("a"));
878         assertEquals(1, anchors.size());
879         assertEquals("http://localhost:22222/start.html", anchors.get(0).getAttribute("href"));
880         assertEquals("click here", anchors.get(0).getText());
881     }
882 
883     /**
884      * Verifies that calls to document.open() are ignored while the page's HTML is being parsed.
885      * @throws Exception if an error occurs
886      */
887     @Test
888     public void open_IgnoredDuringParsing() throws Exception {
889         final String html = DOCTYPE_HTML
890                 + "<html><body>1<script>document.open();document.write('2');</script>3</body></html>";
891 
892         final WebDriver driver = loadPage2(html);
893         assertEquals("123", driver.findElement(By.tagName("body")).getText());
894     }
895 
896     /**
897      * @throws Exception if the test fails
898      */
899     @Test
900     public void writeWithSpace() throws Exception {
901         final String html = DOCTYPE_HTML
902             + "<html>\n"
903             + "<body>\n"
904             + "  <script>\n"
905             + "    document.write('Hello ');\n"
906             + "    document.write('World');\n"
907             + "  </script>\n"
908             + "</body></html>";
909 
910         final WebDriver driver = loadPage2(html);
911         assertEquals("Hello World", driver.findElement(By.tagName("body")).getText());
912     }
913 
914     /**
915      * @throws Exception if the test fails
916      */
917     @Test
918     @Alerts({"0", "foo1", "1", "2", "3", "4", "5", "A", "B", "foo3"})
919     public void writeScriptInManyTimes() throws Exception {
920         final String html = DOCTYPE_HTML
921             + "<html>\n"
922             + "<head>\n"
923             + "<script>\n"
924             + LOG_TITLE_FUNCTION
925             + "  log('0');\n"
926             + "  document.write('<script>log(\"foo1\");</' + 'script>');\n"
927 
928             + "  log('1');\n"
929             + "  document.write('<script src=\"scriptA.js\"></' + 'script>');\n"
930             + "  log('2');\n"
931 
932             + "  document.write('<script src=\"scriptB.js\">');\n"
933             + "  log('3');\n"
934             + "  document.write('<' + '/script>');\n"
935             + "  log('4');\n"
936             + "  document.write('<script>log(\"foo3\");</' + 'script>');\n"
937             + "  log('5');\n"
938             + "</script>\n"
939             + "</head>\n"
940             + "<body>\n"
941             + "</body></html>";
942 
943         final URL scriptUrlA = new URL(URL_FIRST, "scriptA.js");
944         final URL scriptUrlB = new URL(URL_FIRST, "scriptB.js");
945 
946         getMockWebConnection().setDefaultResponse(html);
947         getMockWebConnection().setResponse(scriptUrlA, "log('A');\n", MimeType.TEXT_JAVASCRIPT);
948         getMockWebConnection().setResponse(scriptUrlB, "log('B');\n", MimeType.TEXT_JAVASCRIPT);
949 
950         loadPageVerifyTitle2(html);
951     }
952 
953     /**
954      * @throws Exception if the test fails
955      */
956     @Test
957     @Alerts({"0", "foo1", "1", "foo2", "2", "3", "4", "A", "foo3"})
958     public void writeScriptPostponed() throws Exception {
959         final String html = DOCTYPE_HTML
960             + "<html>\n"
961             + "<head>\n"
962             + "<script>\n"
963             + LOG_TITLE_FUNCTION
964             + "  log('0');\n"
965             + "</script>\n"
966 
967             + "<script>log(\"foo1\");</script>'\n"
968 
969             + "<script>\n"
970             + "  log('1');\n"
971             + "  document.write('<script>log(\"foo2\");</' + 'script>');\n"
972             + "  log('2');\n"
973             + "  document.write('<script src=\"scriptA.js\"></' + 'script>');\n"
974             + "  log('3');\n"
975             + "  document.write('<script>log(\"foo3\");</' + 'script>');\n"
976             + "  log('4');\n"
977             + "</script>\n"
978 
979             + "</head>\n"
980             + "<body>\n"
981             + "</body></html>";
982 
983         final URL scriptUrlA = new URL(URL_FIRST, "scriptA.js");
984 
985         getMockWebConnection().setDefaultResponse(html);
986         getMockWebConnection().setResponse(scriptUrlA, "log('A');\n", MimeType.TEXT_JAVASCRIPT);
987 
988         loadPageVerifyTitle2(html);
989     }
990 
991     /**
992      * @throws Exception if the test fails
993      */
994     @Test
995     @Alerts({"0", "A", "1", "foo2", "2", "3", "4", "B", "foo3"})
996     public void writeScriptPostponedBeforeWrite() throws Exception {
997         final String html = DOCTYPE_HTML
998             + "<html>\n"
999             + "<head>\n"
1000             + "<script>\n"
1001             + LOG_TITLE_FUNCTION
1002             + "  log('0');\n"
1003             + "</script>\n"
1004 
1005             + "<script src='scriptA.js'></script>'\n"
1006 
1007             + "<script>\n"
1008             + "  log('1');\n"
1009             + "  document.write('<script>log(\"foo2\");</' + 'script>');\n"
1010             + "  log('2');\n"
1011             + "  document.write('<script src=\"scriptB.js\"></' + 'script>');\n"
1012             + "  log('3');\n"
1013             + "  document.write('<script>log(\"foo3\");</' + 'script>');\n"
1014             + "  log('4');\n"
1015             + "</script>\n"
1016 
1017             + "</head>\n"
1018             + "<body>\n"
1019             + "</body></html>";
1020 
1021         final URL scriptUrlA = new URL(URL_FIRST, "scriptA.js");
1022         final URL scriptUrlB = new URL(URL_FIRST, "scriptB.js");
1023 
1024         getMockWebConnection().setDefaultResponse(html);
1025         getMockWebConnection().setResponse(scriptUrlA, "log('A');\n", MimeType.TEXT_JAVASCRIPT);
1026         getMockWebConnection().setResponse(scriptUrlB, "log('B');\n", MimeType.TEXT_JAVASCRIPT);
1027 
1028         loadPageVerifyTitle2(html);
1029     }
1030 
1031     /**
1032      * Test for bug 1613119.
1033      * @throws Exception if the test fails
1034      */
1035     @Test
1036     @Alerts({"scr1", "scr2", "null", "null", "[object HTMLScriptElement]", "[object HTMLScriptElement]"})
1037     public void writeAddNodesInCorrectPositions() throws Exception {
1038         final String html = DOCTYPE_HTML
1039             + "<html>\n"
1040             + "<head></head>\n"
1041             + "<body id=\"theBody\">\n"
1042             + "<div id='target1'></div>\n"
1043             + "<script>\n"
1044             + LOG_TITLE_FUNCTION
1045             + "document.write(\""
1046             + "<div>"
1047             + "  <sc\"+\"ript id='scr1'>document.write('<div id=\\\"div1\\\" />');</s\"+\"cript>"
1048             + "  <sc\"+\"ript id='scr2'>document.write('<div id=\\\"div2\\\" />');</s\"+\"cript>"
1049             + "</div>"
1050             + "\");\n"
1051             + "let html = \""
1052             + "<div>"
1053             + "  <sc\"+\"ript id='scr3'>document.write('<div id=\\\"div3\\\" />');</s\"+\"cript>"
1054             + "  <sc\"+\"ript id='scr4'>document.write('<div id=\\\"div4\\\" />');</s\"+\"cript>"
1055             + "</div>"
1056             + "\";"
1057             + "document.getElementById('target1').innerHTML = html;\n"
1058             + "</script>\n"
1059             + "<script>\n"
1060             + "function logId(obj) { log(obj != null ? obj.id : 'null'); }\n"
1061             + "logId(document.getElementById('div1').previousSibling);\n"
1062             + "logId(document.getElementById('div2').previousSibling);\n"
1063             + "log(document.getElementById('div3'));\n"
1064             + "log(document.getElementById('div4'));\n"
1065             + "log(document.getElementById('scr3'));\n"
1066             + "log(document.getElementById('scr4'));\n"
1067 
1068             + "</script>\n"
1069             + "</body></html>";
1070 
1071         loadPageVerifyTitle2(html);
1072     }
1073 
1074     /**
1075      * @throws Exception if the test fails
1076      */
1077     @Test
1078     public void aboutURL() throws Exception {
1079         final String html = DOCTYPE_HTML
1080             + "<html><body><script language='JavaScript'>\n"
1081             + "w2 = window.open('about:blank', 'AboutBlank');\n"
1082             + "w2.document.open();\n"
1083             + "w2.document.write('<html><head><title>hello</title></head><body></body></html>');\n"
1084             + "w2.document.close();\n"
1085             + "</script></body></html>";
1086 
1087         final WebDriver driver = loadPage2(html);
1088         driver.switchTo().window("AboutBlank");
1089         assertEquals("hello", driver.getTitle());
1090     }
1091 
1092     /**
1093      * @throws Exception if an error occurs
1094      */
1095     @Test
1096     @Alerts("§§URL§§")
1097     public void locationAfterWrite() throws Exception {
1098         final String html = DOCTYPE_HTML
1099             + "<html>\n"
1100             + "<head><script>\n"
1101             + "function test() {\n"
1102             + "  window.document.title += 'abcd';\n"
1103             + "  document.open();\n"
1104             + "  document.write("
1105                     + "'<html><body onload=\"window.document.title += document.location + \\'§\\'\"></body></html>');\n"
1106             + "  document.close();\n"
1107             + "}\n"
1108             + "</script></head>\n"
1109             + "<body onload='setTimeout(test, 4);'></body></html>";
1110 
1111         loadPage2(html);
1112         expandExpectedAlertsVariables(URL_FIRST);
1113         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
1114     }
1115 
1116     /**
1117      * @throws Exception if an error occurs
1118      */
1119     @Test
1120     @Alerts(DEFAULT = {"", "First", "First", "FORM", "true", "true"},
1121             FF = {"", "First", "FORM", "true", "true", "First"},
1122             FF_ESR = {"", "First", "FORM", "true", "true", "First"})
1123     @HtmlUnitNYI(FF = {"", "First", "First", "FORM", "true", "true"},
1124             FF_ESR = {"", "First", "First", "FORM", "true", "true"})
1125     public void newElementsAfterWrite() throws Exception {
1126         final String html = DOCTYPE_HTML
1127             + "<html>"
1128             + "<head><script>\n"
1129             + LOG_WINDOW_NAME_FUNCTION
1130             + "function test() {\n"
1131             + "  log(document.title);\n"
1132             + "  document.open();\n"
1133             + "  document.write('<html><head><title>First</title></head>');\n"
1134             + "  document.write('<body onload=\"log(document.title)\">');\n"
1135             + "  document.write('<form name=\"submitForm\" method=\"post\">');\n"
1136             + "  document.write('</form></body></html>');\n"
1137             + "  document.close();\n"
1138             + "  log(document.title);\n"
1139             + "  log(document.submitForm.tagName);\n"
1140             + "  log(window.document == document);\n"
1141             + "  log(document.submitForm == document.getElementsByTagName('form')[0]);\n"
1142             + "}\n"
1143             + "</script></head>\n"
1144             + "<body onload='setTimeout(test, 4);'></body></html>";
1145 
1146         loadPage2(html);
1147         verifyWindowName2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
1148     }
1149 }