View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.Test;
22  import org.junit.runner.RunWith;
23  
24  /**
25   * Tests for {@link HtmlUnitScriptable}.
26   *
27   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
28   * @author <a href="mailto:BarnabyCourt@users.sourceforge.net">Barnaby Court</a>
29   * @author David K. Taylor
30   * @author <a href="mailto:bcurren@esomnie.com">Ben Curren</a>
31   * @author Marc Guillemot
32   * @author Chris Erskine
33   * @author Ahmed Ashour
34   * @author Sudhan Moghe
35   * @author <a href="mailto:mike@10gen.com">Mike Dirolf</a>
36   * @author Frank Danek
37   * @author Ronald Brill
38   */
39  @RunWith(BrowserRunner.class)
40  public class HtmlUnitScriptable2Test extends WebDriverTestCase {
41  
42      /**
43       * @throws Exception if the test fails
44       */
45      @Test
46      @Alerts({"text/html", "text/html"})
47      public void setNonWritablePropertyContentType() throws Exception {
48          final String html = DOCTYPE_HTML
49              + "<html><head>\n"
50              + "<script>\n"
51              + LOG_TITLE_FUNCTION
52              + "  function test() {\n"
53              + "    try {\n"
54              + "      log(document.contentType);\n"
55              + "      document.contentType = '123456';\n"
56              + "      log(document.contentType);\n"
57              + "    } catch(e) { logEx(e); }\n"
58              + "  }\n"
59              + "</script></head>\n"
60              + "<body onload='test()'>\n"
61              + "</body></html>";
62  
63          loadPageVerifyTitle2(html);
64      }
65  
66      /**
67       * @throws Exception if the test fails
68       */
69      @Test
70      @Alerts({"CSS1Compat", "CSS1Compat"})
71      public void setNonWritablePropertyCompatMode() throws Exception {
72          final String html = DOCTYPE_HTML
73              + "<html><head>\n"
74              + "<script>\n"
75              + LOG_TITLE_FUNCTION
76              + "  function test() {\n"
77              + "    try {\n"
78              + "      log(document.compatMode);\n"
79              + "      document.compatMode = '123456';\n"
80              + "      log(document.compatMode);\n"
81              + "    } catch(e) { logEx(e); }\n"
82              + "  }\n"
83              + "</script></head>\n"
84              + "<body onload='test()'>\n"
85              + "</body></html>";
86  
87          loadPageVerifyTitle2(html);
88      }
89  
90      /**
91       * @throws Exception if the test fails
92       */
93      @Test
94      @Alerts("[object Arguments]")
95      public void arguments_toString() throws Exception {
96          final String html = DOCTYPE_HTML
97              + "<html><head>\n"
98              + "<script>\n"
99              + LOG_TITLE_FUNCTION
100             + "  function test() {\n"
101             + "    log(arguments);\n"
102             + "  }\n"
103             + "</script></head>\n"
104             + "<body onload='test()'>\n"
105             + "</body></html>";
106 
107         loadPageVerifyTitle2(html);
108     }
109 
110     /**
111      * @throws Exception if the test fails
112      */
113     @Test
114     @Alerts("3")
115     public void stringWithExclamationMark() throws Exception {
116         final String html = DOCTYPE_HTML
117             + "<html><head>\n"
118             + "<script>\n"
119             + LOG_TITLE_FUNCTION
120             + "  function test() {\n"
121             + "    var x = '<!>';\n"
122             + "    log(x.length);\n"
123             + "  }\n"
124             + "</script></head>\n"
125             + "<body onload='test()'>\n"
126             + "</body></html>";
127 
128         loadPageVerifyTitle2(html);
129     }
130 
131     /**
132      * Blocked by Rhino bug 419090 (https://bugzilla.mozilla.org/show_bug.cgi?id=419090).
133      * @throws Exception if the test fails
134      */
135     @Test
136     @Alerts({"x1", "x2", "x3", "x4", "x5"})
137     public void arrayedMap() throws Exception {
138         final String html = DOCTYPE_HTML
139             + "<html><head>\n"
140             + "<script>\n"
141             + LOG_TITLE_FUNCTION
142             + "  function test() {\n"
143             + "    var map = {};\n"
144             + "    map['x1'] = 'y1';\n"
145             + "    map['x2'] = 'y2';\n"
146             + "    map['x3'] = 'y3';\n"
147             + "    map['x4'] = 'y4';\n"
148             + "    map['x5'] = 'y5';\n"
149             + "    for (var i in map) {\n"
150             + "      log(i);\n"
151             + "    }\n"
152             + "  }\n"
153             + "</script></head>\n"
154             + "<body onload='test()'>\n"
155             + "</body></html>";
156 
157         loadPageVerifyTitle2(html);
158     }
159 
160     /**
161      * This is related to HtmlUnitContextFactory.hasFeature(Context.FEATURE_PARENT_PROTO_PROPERTIES).
162      * @throws Exception if the test fails
163      */
164     @Test
165     @Alerts("true")
166     public void parentProtoFeature() throws Exception {
167         final String html = DOCTYPE_HTML
168             + "<html><head>\n"
169             + "<script>\n"
170             + LOG_TITLE_FUNCTION
171             + "  function test() {\n"
172             + "    log(document.createElement('div').__proto__ != undefined);\n"
173             + "  }\n"
174             + "</script></head>\n"
175             + "<body onload='test()'>\n"
176             + "</body></html>";
177 
178         loadPageVerifyTitle2(html);
179     }
180 
181     /**
182      * Test for http://sourceforge.net/p/htmlunit/bugs/587/.
183      * See also http://groups.google.com/group/mozilla.dev.tech.js-engine.rhino/browse_thread/thread/1f1c24f58f662c58.
184      * @throws Exception if the test fails
185      */
186     @Test
187     @Alerts("1")
188     public void passFunctionAsParameter() throws Exception {
189         final String html = DOCTYPE_HTML
190             + "<html><head>\n"
191             + "<script>\n"
192             + LOG_TITLE_FUNCTION
193             + "  function run(fun) {\n"
194             + "    fun('log(1)');\n"
195             + "  }\n"
196             + "\n"
197             + "  function test() {\n"
198             + "    run(eval);\n"
199             + "  }\n"
200             + "</script></head>\n"
201             + "<body onload='test()'>\n"
202             + "</body></html>";
203 
204         loadPageVerifyTitle2(html);
205     }
206 
207     /**
208      * @throws Exception if the test fails
209      */
210     @Test
211     @Alerts({"true", "function", "function"})
212     public void callee() throws Exception {
213         final String html = DOCTYPE_HTML
214             + "<html><head>\n"
215             + "<script>\n"
216             + LOG_TITLE_FUNCTION
217             + "function test() {\n"
218             + "  var fun = arguments.callee.toString();\n"
219             + "  log(fun.indexOf('test()') != -1);\n"
220             + "  log(typeof arguments.callee);\n"
221             + "  log(typeof arguments.callee.caller);\n"
222             + "}\n"
223             + "</script></head>\n"
224             + "<body onload='test()'>\n"
225             + "</body></html>";
226 
227         loadPageVerifyTitle2(html);
228     }
229 
230     /**
231      * @throws Exception if the test fails
232      */
233     @Test
234     @Alerts("[object HTMLDivElement]")
235     public void getDefaultValue() throws Exception {
236         getDefaultValue(false);
237     }
238 
239     /**
240      * @throws Exception if the test fails
241      */
242     @Test
243     @Alerts("[object HTMLDivElement]")
244     public void getDefaultValue_xhtml() throws Exception {
245         getDefaultValue(true);
246     }
247 
248     private void getDefaultValue(final boolean xhtml) throws Exception {
249         final String header = xhtml ? "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
250                 + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" : "";
251         final String html = header
252             + "<html><head>\n"
253             + "<script>\n"
254             + LOG_TITLE_FUNCTION
255             + "function test() {\n"
256             + "  log(document.createElement('div'));\n"
257             + "}\n"
258             + "</script></head>\n"
259             + "<body onload='test()'>\n"
260             + "</body></html>";
261 
262         loadPageVerifyTitle2(html);
263     }
264 
265     /**
266      * Setting is actually ignored in FF.
267      *
268      * @throws Exception if the test fails
269      */
270     @Test
271     @Alerts("false")
272     public void set_ReadOnly_window_closed() throws Exception {
273         set_ReadOnly("window.closed");
274     }
275 
276     /**
277      * Setting the property works in FF.
278      *
279      * @throws Exception if the test fails
280      */
281     @Test
282     @Alerts("window.length was set")
283     public void set_ReadOnly_window_length() throws Exception {
284         set_ReadOnly("window.length");
285     }
286 
287     /**
288      * Setting the property works in FF.
289      *
290      * @throws Exception if the test fails
291      */
292     @Test
293     @Alerts("0")
294     public void set_ReadOnly_style_length() throws Exception {
295         set_ReadOnly("document.body.style.length");
296     }
297 
298     /**
299      * All functions seem to be able to be set.
300      *
301      * @throws Exception if the test fails
302      */
303     @Test
304     @Alerts("document.getElementById was set")
305     public void set_ReadOnly_getElementById() throws Exception {
306         set_ReadOnly("document.getElementById");
307     }
308 
309     private void set_ReadOnly(final String expression) throws Exception {
310         final String html = DOCTYPE_HTML
311             + "<html><head>\n"
312             + "<script>\n"
313             + LOG_TITLE_FUNCTION
314             + "function test() {\n"
315             + "  try {\n"
316             + "    " + expression + " = '" + expression + " was set" + "';\n"
317             + "    log(" + expression + ");\n"
318             + "  } catch(e) { logEx(e) }\n"
319             + "}\n"
320             + "</script></head>\n"
321             + "<body onload='test()'>\n"
322             + "</body></html>";
323 
324         loadPageVerifyTitle2(html);
325     }
326 
327     /**
328      * Tests for the result of __lookupGetter__.
329      * Until 20.06.2014 the result was wrongly a MemberBox. Converting it to a boolean was producing warning messages
330      * on the error output.
331      * @throws Exception if the test fails
332      */
333     @Test
334     @Alerts(DEFAULT = {"function", "true", "function length() { [native code] }", "0", "0"},
335             CHROME = {"function", "true", "function get length() { [native code] }", "0", "0"},
336             EDGE = {"function", "true", "function get length() { [native code] }", "0", "0"})
337     @HtmlUnitNYI(CHROME = {"function", "true", "function length() { [native code] }", "0", "0"},
338             EDGE = {"function", "true", "function length() { [native code] }", "0", "0"})
339     public void lookupGetter() throws Exception {
340         final String html = DOCTYPE_HTML
341             + "<html><head>\n"
342             + "<script>\n"
343             + LOG_TITLE_FUNCTION
344             + "function test() {\n"
345             + "  try {\n"
346             + "    var lengthGetter = window.__lookupGetter__('length');\n"
347             + "    log(typeof lengthGetter);\n"
348             + "    log(!!lengthGetter);\n"
349             + "    log(lengthGetter);\n"
350             + "    log(lengthGetter.call(window));\n"
351             + "    log(lengthGetter.call());\n"
352             + "  } catch(e) { logEx(e) }\n"
353             + "}\n"
354             + "</script></head>\n"
355             + "<body onload='test()'>\n"
356             + "</body></html>";
357 
358         loadPageVerifyTitle2(html);
359     }
360 }