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.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.junit.Test;
21  import org.junit.runner.RunWith;
22  
23  /**
24   * Tests for {@link XPathEvaluator}.
25   *
26   * @author Marc Guillemot
27   * @author Chuck Dumont
28   * @author Ronald Brill
29   */
30  @RunWith(BrowserRunner.class)
31  public class XPathEvaluatorTest extends WebDriverTestCase {
32  
33      /**
34       * @throws Exception if the test fails
35       */
36      @Test
37      @Alerts({"function", "[object XPathEvaluator]", "[object HTMLHtmlElement]", "first", "second", ""})
38      public void evaluate() throws Exception {
39          final String html = DOCTYPE_HTML
40              + "<html><body>\n"
41              + "<span id='first'>hello</span>\n"
42              + "<div><span id='second'>world</span></div>\n"
43              + "<script>\n"
44              + LOG_TITLE_FUNCTION
45              + "var res = '';\n"
46              + "try {\n"
47              + "  res += typeof window.XPathEvaluator + '§';\n"
48              + "  var xpe = new XPathEvaluator();\n"
49              + "  res += xpe + '§';\n"
50              + "  var nsResolver = xpe.createNSResolver(document.documentElement);\n"
51              + "  res += nsResolver + '§';\n"
52              + "  var result = xpe.evaluate('//span', document.body, nsResolver, 0, null);\n"
53              + "  var found = [];\n"
54              + "  var next;\n"
55              + "  while (next = result.iterateNext()) {\n"
56              + "    res += next.id + '§';\n"
57              + "  }\n"
58              + "} catch(e) { res += 'exception' + '§'; }\n"
59              + "log(res);\n"
60              + "</script></body></html>";
61  
62          loadPageVerifyTitle2(html);
63      }
64  
65      /**
66       * @throws Exception if the test fails
67       */
68      @Test
69      @Alerts({"function", "[object XPathEvaluator]", "[object HTMLHtmlElement]", "first", "second", ""})
70      public void evaluateWithoutResult() throws Exception {
71          final String html = DOCTYPE_HTML
72              + "<html><body>\n"
73              + "<span id='first'>hello</span>\n"
74              + "<div><span id='second'>world</span></div>\n"
75              + "<script>\n"
76              + LOG_TITLE_FUNCTION
77              + "var res = '';\n"
78              + "try {\n"
79              + "  res += typeof window.XPathEvaluator + '§';\n"
80              + "  var xpe = new XPathEvaluator();\n"
81              + "  res += xpe + '§';\n"
82              + "  var nsResolver = xpe.createNSResolver(document.documentElement);\n"
83              + "  res += nsResolver + '§';\n"
84              + "  var result = xpe.evaluate('//span', document.body, nsResolver, 0);\n"
85              + "  var found = [];\n"
86              + "  var next;\n"
87              + "  while (next = result.iterateNext()) {\n"
88              + "    res += next.id + '§';\n"
89              + "  }\n"
90              + "} catch(e) { res += 'exception' + '§'; }\n"
91              + "log(res);\n"
92              + "</script></body></html>";
93  
94          loadPageVerifyTitle2(html);
95      }
96  
97      /**
98       * @throws Exception if the test fails
99       */
100     @Test
101     @Alerts({"function", "[object XPathEvaluator]", "[object HTMLHtmlElement]", "first", "second", ""})
102     public void evaluateWithoutTypeResult() throws Exception {
103         final String html = DOCTYPE_HTML
104             + "<html><body>\n"
105             + "<span id='first'>hello</span>\n"
106             + "<div><span id='second'>world</span></div>\n"
107             + "<script>\n"
108             + LOG_TITLE_FUNCTION
109             + "var res = '';\n"
110             + "try {\n"
111             + "  res += typeof window.XPathEvaluator + '§';\n"
112             + "  var xpe = new XPathEvaluator();\n"
113             + "  res += xpe + '§';\n"
114             + "  var nsResolver = xpe.createNSResolver(document.documentElement);\n"
115             + "  res += nsResolver + '§';\n"
116             + "  var result = xpe.evaluate('//span', document.body, nsResolver);\n"
117             + "  var found = [];\n"
118             + "  var next;\n"
119             + "  while (next = result.iterateNext()) {\n"
120             + "    res += next.id + '§';\n"
121             + "  }\n"
122             + "} catch(e) { res += 'exception' + '§'; }\n"
123             + "log(res);\n"
124             + "</script></body></html>";
125 
126         loadPageVerifyTitle2(html);
127     }
128 
129     /**
130      * @throws Exception if the test fails
131      */
132     @Test
133     @Alerts({"function", "[object XPathEvaluator]", "[object HTMLHtmlElement]", "first", "second", ""})
134     public void evaluateWithoutResolverTypeResult() throws Exception {
135         final String html = DOCTYPE_HTML
136             + "<html><body>\n"
137             + "<span id='first'>hello</span>\n"
138             + "<div><span id='second'>world</span></div>\n"
139             + "<script>\n"
140             + LOG_TITLE_FUNCTION
141             + "var res = '';\n"
142             + "try {\n"
143             + "  res += typeof window.XPathEvaluator + '§';\n"
144             + "  var xpe = new XPathEvaluator();\n"
145             + "  res += xpe + '§';\n"
146             + "  var nsResolver = xpe.createNSResolver(document.documentElement);\n"
147             + "  res += nsResolver + '§';\n"
148             + "  var result = xpe.evaluate('//span', document.body);\n"
149             + "  var found = [];\n"
150             + "  var next;\n"
151             + "  while (next = result.iterateNext()) {\n"
152             + "    res += next.id + '§';\n"
153             + "  }\n"
154             + "} catch(e) { res += 'exception' + '§'; }\n"
155             + "log(res);\n"
156             + "</script></body></html>";
157 
158         loadPageVerifyTitle2(html);
159     }
160 
161     /**
162      * @throws Exception if the test fails
163      */
164     @Test
165     @Alerts("TypeError")
166     public void namespacesWithNodeInArray() throws Exception {
167         final String html = DOCTYPE_HTML
168             + "<html><head>\n"
169             + "<script>\n"
170             + LOG_TITLE_FUNCTION
171             + "  var xml = "
172             + "  '<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
173             + "    <soap:books>"
174             + "      <soap:book>"
175             + "        <title>Immortality</title>"
176             + "        <author>John Smith</author>"
177             + "      </soap:book>"
178             + "    </soap:books>"
179             + "  </soap:Envelope>';\n"
180 
181             + "  function test() {\n"
182             + "    if (window.XPathEvaluator) {\n"
183             + "      var doc = (new DOMParser).parseFromString(xml, 'text/xml');\n"
184             + "      var xpe = new XPathEvaluator();\n"
185             + "      var nsResolver = xpe.createNSResolver(doc.documentElement);\n"
186             + "      try {\n"
187             + "        var result = xpe.evaluate('/soap:Envelope/soap:books/soap:book/title/text()', "
188                                      + "[doc.documentElement], nsResolver, XPathResult.STRING_TYPE, null);\n"
189             + "        log(result.stringValue);\n"
190             + "      } catch(e) { logEx(e); }\n"
191             + "    } else {\n"
192             + "      log('window.XPathEvaluator undefined');\n"
193             + "    }\n"
194             + "  }\n"
195             + "</script></head><body onload='test()'>\n"
196             + "</body></html>";
197 
198         loadPageVerifyTitle2(html);
199     }
200 
201     /**
202      * @throws Exception if the test fails
203      */
204     @Test
205     @Alerts("Immortality")
206     public void namespacesWithCustomNSResolver() throws Exception {
207         final String html = DOCTYPE_HTML
208             + "<html><head>\n"
209             + "<script>\n"
210             + LOG_TITLE_FUNCTION
211             + "  function nsResolver(prefix) {\n"
212             + "    return {s : 'http://schemas.xmlsoap.org/soap/envelope/'}[prefix] || null;\n"
213             + "  }\n"
214 
215             + "  var xml = "
216             + "  '<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
217             + "    <soap:books>"
218             + "      <soap:book>"
219             + "        <title>Immortality</title>"
220             + "        <author>John Smith</author>"
221             + "      </soap:book>"
222             + "    </soap:books>"
223             + "  </soap:Envelope>';\n"
224 
225             + "  function test() {\n"
226             + "    if (window.XPathEvaluator) {\n"
227             + "      var doc = (new DOMParser).parseFromString(xml, 'text/xml');\n"
228             + "      var xpe = new XPathEvaluator();\n"
229             + "      var result = xpe.evaluate('/s:Envelope/s:books/s:book/title/text()', "
230                                    + "doc.documentElement, nsResolver, XPathResult.STRING_TYPE, null);\n"
231             + "      log(result.stringValue);\n"
232             + "    } else {\n"
233             + "      log('window.XPathEvaluator undefined');\n"
234             + "    }\n"
235             + "  }\n"
236             + "</script></head><body onload='test()'>\n"
237             + "</body></html>";
238 
239         loadPageVerifyTitle2(html);
240     }
241 
242     /**
243      * @throws Exception if the test fails
244      */
245     @Test
246     @Alerts("exception")
247     public void createExpressionNoXPath() throws Exception {
248         final String html = DOCTYPE_HTML
249             + "<html><body>\n"
250             + "<script>\n"
251             + LOG_TITLE_FUNCTION
252             + "var res = '';\n"
253             + "try {\n"
254             + "  var expression = new XPathEvaluator().createExpression();\n"
255             + "  res += expression;\n"
256             + "} catch(e) { res += 'exception'; }\n"
257             + "log(res);\n"
258             + "</script></body></html>";
259 
260         loadPageVerifyTitle2(html);
261     }
262 
263     /**
264      * @throws Exception if the test fails
265      */
266     @Test
267     @Alerts({"function", "[object XPathEvaluator]", "[object XPathExpression]§"})
268     public void createExpressionUndefinedXPath() throws Exception {
269         final String html = DOCTYPE_HTML
270                 + "<html><body>\n"
271                 + "<span id='first'>hello</span>\n"
272                 + "<div><span id='second'>world</span></div>\n"
273                 + "<script>\n"
274                 + LOG_TITLE_FUNCTION
275                 + "var res = '';\n"
276                 + "try {\n"
277                 + "  res += typeof window.XPathEvaluator + '§';\n"
278                 + "  var xpe = new XPathEvaluator();\n"
279                 + "  res += xpe + '§';\n"
280                 + "  var expression = xpe.createExpression(undefined);\n"
281                 + "  res += expression + '§';\n"
282                 + "  var result = expression.evaluate(document.body);\n"
283                 + "  var found = [];\n"
284                 + "  var next;\n"
285                 + "  while (next = result.iterateNext()) {\n"
286                 + "    res += next.id + '§';\n"
287                 + "  }\n"
288                 + "} catch(e) { res += 'exception' + e + '§'; }\n"
289                 + "log(res);\n"
290                 + "</script></body></html>";
291 
292         loadPageVerifyTitle2(html);
293     }
294 
295     /**
296      * @throws Exception if the test fails
297      */
298     @Test
299     @Alerts({"function", "[object XPathEvaluator]", "[object XPathExpression]§"})
300     public void createExpressionNullXPath() throws Exception {
301         final String html = DOCTYPE_HTML
302                 + "<html><body>\n"
303                 + "<span id='first'>hello</span>\n"
304                 + "<div><span id='second'>world</span></div>\n"
305                 + "<script>\n"
306                 + LOG_TITLE_FUNCTION
307                 + "var res = '';\n"
308                 + "try {\n"
309                 + "  res += typeof window.XPathEvaluator + '§';\n"
310                 + "  var xpe = new XPathEvaluator();\n"
311                 + "  res += xpe + '§';\n"
312                 + "  var expression = xpe.createExpression(null);\n"
313                 + "  res += expression + '§';\n"
314                 + "  var result = expression.evaluate(document.body);\n"
315                 + "  var found = [];\n"
316                 + "  var next;\n"
317                 + "  while (next = result.iterateNext()) {\n"
318                 + "    res += next.id + '§';\n"
319                 + "  }\n"
320                 + "} catch(e) { res += 'exception' + '§'; }\n"
321                 + "log(res);\n"
322                 + "</script></body></html>";
323 
324         loadPageVerifyTitle2(html);
325     }
326 
327     /**
328      * @throws Exception if the test fails
329      */
330     @Test
331     @Alerts("SyntaxError")
332     public void createExpressionInvalid() throws Exception {
333         final String html = DOCTYPE_HTML
334             + "<html><body>\n"
335             + "<script>\n"
336             + LOG_TITLE_FUNCTION
337             + "var res = '';\n"
338             + "try {\n"
339             + "  var expression = new XPathEvaluator().createExpression('@@');\n"
340             + "  res += expression;\n"
341             + "} catch(e) { res += e.name; }\n"
342             + "log(res);\n"
343             + "</script></body></html>";
344 
345         loadPageVerifyTitle2(html);
346     }
347 }