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