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.dom;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.junit.jupiter.api.Test;
20  
21  /**
22   * Tests for {@link DOMParser}.
23   *
24   * @author Ahmed Ashour
25   * @author Marc Guillemot
26   * @author Frank Danek
27   * @author Ronald Brill
28   */
29  public class DOMParserTest extends WebDriverTestCase {
30  
31      /**
32       * @throws Exception if the test fails
33       */
34      @Test
35      @Alerts("[object DOMParser]")
36      public void scriptableToString() throws Exception {
37          final String html = DOCTYPE_HTML
38              + "<html><head>\n"
39              + "<script>\n"
40              + LOG_TITLE_FUNCTION
41              + "  function test() {\n"
42              + "    try {\n"
43              + "      log(new DOMParser());\n"
44              + "    } catch(e) {logEx(e);}\n"
45              + "  }\n"
46              + "</script></head><body onload='test()'>\n"
47              + "</body></html>";
48  
49          loadPageVerifyTitle2(html);
50      }
51  
52      /**
53       * @throws Exception if the test fails
54       */
55      @Test
56      @Alerts({"[object HTMLDocument]", "", "§§URL§§"})
57      public void parseFromString_text_html() throws Exception {
58          final String content = DOCTYPE_HTML
59              + "<html><head>\n"
60              + "<script>\n"
61              + LOG_TITLE_FUNCTION
62              + "  function test() {\n"
63              + "    var text='<html></html>';\n"
64              + "    try {\n"
65              + "      var parser = new DOMParser();\n"
66              + "      var doc = parser.parseFromString(text, 'text/html');\n"
67              + "      log(doc);\n"
68              + "      log(doc.body.innerHTML);\n"
69              + "      log(doc.URL);\n"
70              + "    } catch(e) { logEx(e); }\n"
71              + "  }\n"
72              + "</script></head><body onload='test()'>\n"
73              + "</body></html>";
74  
75          expandExpectedAlertsVariables(URL_FIRST);
76          loadPageVerifyTitle2(content);
77      }
78  
79      /**
80       * @throws Exception if the test fails
81       */
82      @Test
83      @Alerts({"[object HTMLDocument]", "<div></div>", "§§URL§§"})
84      public void parseFromString_text_html_div() throws Exception {
85          final String content = DOCTYPE_HTML
86              + "<html><head>\n"
87              + "<script>\n"
88              + LOG_TITLE_FUNCTION
89              + "  function test() {\n"
90              + "    var text='<div></div>';\n"
91              + "    try {\n"
92              + "      var parser = new DOMParser();\n"
93              + "      var doc = parser.parseFromString(text, 'text/html');\n"
94              + "      log(doc);\n"
95              + "      log(doc.body.innerHTML);\n"
96              + "      log(doc.URL);\n"
97              + "    } catch(e) { logEx(e); }\n"
98              + "  }\n"
99              + "</script></head><body onload='test()'>\n"
100             + "</body></html>";
101 
102         expandExpectedAlertsVariables(URL_FIRST);
103         loadPageVerifyTitle2(content);
104     }
105 
106     /**
107      * @throws Exception if the test fails
108      */
109     @Test
110     @Alerts("[object XMLDocument]")
111     public void parseFromString_text_xml() throws Exception {
112         final String content = DOCTYPE_HTML
113             + "<html><head>\n"
114             + "<script>\n"
115             + LOG_TITLE_FUNCTION
116             + "  function test() {\n"
117             + "    var text='<note/>';\n"
118             + "    try {\n"
119             + "      var parser = new DOMParser();\n"
120             + "      var doc = parser.parseFromString(text, 'text/xml');\n"
121             + "      log(doc);\n"
122             + "    } catch(e) { logEx(e); }\n"
123             + "  }\n"
124             + "</script></head><body onload='test()'>\n"
125             + "</body></html>";
126 
127         loadPageVerifyTitle2(content);
128     }
129 
130     /**
131      * @throws Exception if the test fails
132      */
133     @Test
134     @Alerts("[object XMLDocument]")
135     public void parseFromString_application_xml() throws Exception {
136         final String content = DOCTYPE_HTML
137             + "<html><head>\n"
138             + "<script>\n"
139             + LOG_TITLE_FUNCTION
140             + "  function test() {\n"
141             + "    var text='<note/>';\n"
142             + "    try {\n"
143             + "      var parser = new DOMParser();\n"
144             + "      var doc = parser.parseFromString(text, 'application/xml');\n"
145             + "      log(doc);\n"
146             + "    } catch(e) { logEx(e); }\n"
147             + "  }\n"
148             + "</script></head><body onload='test()'>\n"
149             + "</body></html>";
150 
151         loadPageVerifyTitle2(content);
152     }
153 
154     /**
155      * @throws Exception if the test fails
156      */
157     @Test
158     @Alerts("[object XMLDocument]")
159     public void parseFromString_application_xhtmlXml() throws Exception {
160         final String content = DOCTYPE_HTML
161             + "<html><head>\n"
162             + "<script>\n"
163             + LOG_TITLE_FUNCTION
164             + "  function test() {\n"
165             + "    var text='<html/>';\n"
166             + "    try {\n"
167             + "      var parser = new DOMParser();\n"
168             + "      var doc = parser.parseFromString(text, 'application/xhtml+xml');\n"
169             + "      log(doc);\n"
170             + "    } catch(e) { logEx(e); }\n"
171             + "  }\n"
172             + "</script></head><body onload='test()'>\n"
173             + "</body></html>";
174 
175         loadPageVerifyTitle2(content);
176     }
177 
178     /**
179      * @throws Exception if the test fails
180      */
181     @Test
182     @Alerts("[object XMLDocument]")
183     public void parseFromString_application_svgXml() throws Exception {
184         final String content = DOCTYPE_HTML
185             + "<html><head>\n"
186             + "<script>\n"
187             + LOG_TITLE_FUNCTION
188             + "  function test() {\n"
189             + "    var text='<svg xmlns=\"http://www.w3.org/2000/svg\"/>';\n"
190             + "    try {\n"
191             + "      var parser = new DOMParser();\n"
192             + "      var doc = parser.parseFromString(text, 'image/svg+xml');\n"
193             + "      log(doc);\n"
194             + "    } catch(e) { logEx(e); }\n"
195             + "  }\n"
196             + "</script></head><body onload='test()'>\n"
197             + "</body></html>";
198 
199         loadPageVerifyTitle2(content);
200     }
201 
202     /**
203      * @throws Exception if the test fails
204      */
205     @Test
206     @Alerts("TypeError")
207     public void parseFromString_unknownType() throws Exception {
208         final String content = DOCTYPE_HTML
209             + "<html><head>\n"
210             + "<script>\n"
211             + LOG_TITLE_FUNCTION
212             + "  function test() {\n"
213             + "    var text='<test/>';\n"
214             + "    try {\n"
215             + "      var parser = new DOMParser();\n"
216             + "      var doc = parser.parseFromString(text, 'unknown/type');\n"
217             + "      log(doc);\n"
218             + "    } catch(e) { logEx(e); }\n"
219             + "  }\n"
220             + "</script></head><body onload='test()'>\n"
221             + "</body></html>";
222 
223         loadPageVerifyTitle2(content);
224     }
225 
226     /**
227      * @throws Exception if the test fails
228      */
229     @Test
230     @Alerts("9")
231     public void parseFromString() throws Exception {
232         final String content = DOCTYPE_HTML
233             + "<html><head>\n"
234             + "<script>\n"
235             + LOG_TITLE_FUNCTION
236             + "  function test() {\n"
237             + "    var text='<note> ';\n"
238             + "    text += '<to>Tove</to> ';\n"
239             + "    text += '<from>Jani</from> ';\n"
240             + "    text += '<heading>Reminder</heading> ';\n"
241             + "    text += '<body>Do not forget me this weekend!</body> ';\n"
242             + "    text += '</note>';\n"
243             + "    try {\n"
244             + "      var parser = new DOMParser();\n"
245             + "      var doc = parser.parseFromString(text, 'text/xml');\n"
246             + "      if (doc.getElementsByTagName('parsererror').length > 0) { log('parsererror'); return; }\n"
247 
248             + "      var x = doc.documentElement;\n"
249             + "      log(x.childNodes.length);\n"
250             + "    } catch(e) { logEx(e); }\n"
251             + "  }\n"
252             + "</script></head><body onload='test()'>\n"
253             + "</body></html>";
254 
255         loadPageVerifyTitle2(content);
256     }
257 
258     /**
259      * In 2.9-SNAPSHOT on 26.10.2010 this was causing an internal error in DOMParser.parseFromString.
260      * @throws Exception if the test fails
261      */
262     @Test
263     @Alerts("parsererror")
264     public void parseFromString_invalidXml() throws Exception {
265         final String content = DOCTYPE_HTML
266             + "<html><head>\n"
267             + "<script>\n"
268             + LOG_TITLE_FUNCTION
269             + "  function test() {\n"
270             + "    var text = '</notvalid> ';\n"
271             + "    try {\n"
272             + "      var parser = new DOMParser();\n"
273             + "      var doc = parser.parseFromString(text, 'text/xml');\n"
274             + "      if (doc.getElementsByTagName('parsererror').length > 0) {\n"
275             + "        log('parsererror');\n"
276             + "        return;\n"
277             + "      }\n"
278             + "    } catch(e) { logEx(e); }\n"
279             + "  }\n"
280             + "</script></head><body onload='test()'>\n"
281             + "</body></html>";
282 
283         loadPageVerifyTitle2(content);
284     }
285 
286     /**
287      * @throws Exception if the test fails
288      */
289     @Test
290     @Alerts("parsererror")
291     public void parseFromString_emptyString() throws Exception {
292         final String content = DOCTYPE_HTML
293             + "<html><head>\n"
294             + "<script>\n"
295             + LOG_TITLE_FUNCTION
296             + "  function test() {\n"
297             + "    var text='';\n"
298             + "    try {\n"
299             + "      var parser = new DOMParser();\n"
300             + "      var doc = parser.parseFromString(text, 'text/xml');\n"
301             + "      if (doc.getElementsByTagName('parsererror').length > 0) {\n"
302             + "        log('parsererror');\n"
303             + "        return;\n"
304             + "      }\n"
305             + "      log(doc.childNodes.length);\n"
306             + "    } catch(e) { logEx(e); }\n"
307             + "  }\n"
308             + "</script></head><body onload='test()'>\n"
309             + "</body></html>";
310 
311         loadPageVerifyTitle2(content);
312     }
313 
314     /**
315      * @throws Exception if the test fails
316      */
317     @Test
318     @Alerts("TypeError")
319     public void parseFromString_missingMimeType() throws Exception {
320         final String content = DOCTYPE_HTML
321             + "<html><head>\n"
322             + "<script>\n"
323             + LOG_TITLE_FUNCTION
324             + "  function test() {\n"
325             + "    var text='<root/>';\n"
326             + "    try {\n"
327             + "      var parser=new DOMParser();\n"
328             + "      parser.parseFromString(text);\n"
329             + "    } catch(e) { logEx(e); }\n"
330             + "  }\n"
331             + "</script></head>\n"
332             + "<body onload='test()'>\n"
333             + "</body></html>";
334 
335         loadPageVerifyTitle2(content);
336     }
337 
338     /**
339      * Regression test for bug 2899485.
340      * @throws Exception if an error occurs
341      */
342     @Test
343     @Alerts({"5", "[object CDATASection]", "[object Comment]", "[object Element]",
344                 "[object ProcessingInstruction]", "[object Text]"})
345     public void parseFromString_processingInstructionKept() throws Exception {
346         final String html = DOCTYPE_HTML
347             + "<html><head>\n"
348             + "<script>\n"
349             + LOG_TITLE_FUNCTION
350             + "  function test() {\n"
351             + "    var text = '<elementWithChildren>' + '<![CDATA[sampl<<< >>e data]]>' + '<!--a sample comment-->'\n"
352             + "      + '<elementWithChildren/>' + '<?target processing instruction data?>' + 'sample text node'\n"
353             + "      + '</elementWithChildren>';\n"
354             + "    try {\n"
355             + "      var parser = new DOMParser();\n"
356             + "      var doc = parser.parseFromString(text, 'text/xml');\n"
357             + "      if (doc.getElementsByTagName('parsererror').length > 0) {\n"
358             + "        log('parsererror');\n"
359             + "        return;\n"
360             + "      }\n"
361             + "      log(doc.documentElement.childNodes.length);\n"
362             + "      for(var i = 0; i < doc.documentElement.childNodes.length; i++) {\n"
363             + "        log(doc.documentElement.childNodes[i]);\n"
364             + "      }\n"
365             + "    } catch(e) { logEx(e); }\n"
366             + "  }\n"
367             + "</script></head><body onload='test()'></body></html>";
368 
369         loadPageVerifyTitle2(html);
370     }
371 
372     /**
373      * @throws Exception if an error occurs
374      */
375     @Test
376     @Alerts("[object HTMLDocument]")
377     public void parseFromString_doNotExecuteScripts() throws Exception {
378         final String html = DOCTYPE_HTML
379             + "<html>\n"
380             + "<head>\n"
381             + "  <script>\n"
382             + LOG_TITLE_FUNCTION
383             + "    function test() {\n"
384             + "      var html = '<script>document.title = \"parsed script executed\";</' + 'script>';\n"
385             + "      var parser = new DOMParser();\n"
386             + "      log(parser.parseFromString(html, 'text/html'));\n"
387             + "  }\n"
388             + "  </script>\n"
389             + "</head>\n"
390             + "<body onload='test()'>\n"
391             + "</body></html>";
392 
393         loadPageVerifyTitle2(html);
394     }
395 
396     /**
397      * @throws Exception if an error occurs
398      */
399     @Test
400     @Alerts("[object HTMLDocument]")
401     public void parseFromString_doNotExecuteSvgScripts() throws Exception {
402         final String html = DOCTYPE_HTML
403             + "<html>\n"
404             + "<head>\n"
405             + "  <script>\n"
406             + LOG_TITLE_FUNCTION
407             + "    function test() {\n"
408             + "      var html = '<svg viewBox=\"0 0 10 10\" xmlns=\"http://www.w3.org/2000/svg\">'\n"
409             + "                + '<script>document.title = \"parsed script executed\";</' + 'script>'\n"
410             + "                + '</svg>';\n"
411             + "      var parser = new DOMParser();\n"
412             + "      log(parser.parseFromString(html, 'text/html'));\n"
413             + "  }\n"
414             + "  </script>\n"
415             + "</head>\n"
416             + "<body onload='test()'>\n"
417             + "</body></html>";
418 
419         loadPageVerifyTitle2(html);
420     }
421 
422     /**
423      * Test exception throw by IE when calling <code>insertBefore</code>.
424      * @throws Exception if the test fails
425      */
426     @Test
427     @Alerts({"parsed", "inserted"})
428     public void dontExecScriptsFromDOMParser() throws Exception {
429         final String html = DOCTYPE_HTML
430               + "<html>\n"
431               + "<head></head>\n"
432               + "<body>\n"
433               + "<div id='tester'><div>"
434               + "<script>\n"
435               + LOG_TITLE_FUNCTION
436               + "  var script = \"<div><script>log('from script');</\" + \"script></div>\"\n"
437               + "  var parser = new DOMParser();\n"
438               + "  var parsedDoc = parser.parseFromString(script, 'text/html');\n"
439               + "  var parsedNode = parsedDoc.body.firstChild.firstChild;\n"
440               + "  log('parsed');\n"
441 
442               + "  document.getElementById('tester').insertBefore(parsedNode, null);\n"
443               + "  log('inserted');\n"
444               + "</script>\n"
445               + "</body></html>";
446 
447         loadPageVerifyTitle2(html);
448     }
449 }