KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > gargoylesoftware > htmlunit > javascript > JavaScriptEngineTest


1 /*
2  * Copyright (c) 2002, 2005 Gargoyle Software Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12  * 3. The end-user documentation included with the redistribution, if any, must
13  * include the following acknowledgment:
14  *
15  * "This product includes software developed by Gargoyle Software Inc.
16  * (http://www.GargoyleSoftware.com/)."
17  *
18  * Alternately, this acknowledgment may appear in the software itself, if
19  * and wherever such third-party acknowledgments normally appear.
20  * 4. The name "Gargoyle Software" must not be used to endorse or promote
21  * products derived from this software without prior written permission.
22  * For written permission, please contact info@GargoyleSoftware.com.
23  * 5. Products derived from this software may not be called "HtmlUnit", nor may
24  * "HtmlUnit" appear in their name, without prior written permission of
25  * Gargoyle Software Inc.
26  *
27  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30  * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */

38 package com.gargoylesoftware.htmlunit.javascript;
39
40 import java.io.FileNotFoundException;
41 import java.io.IOException;
42 import java.net.URL;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.Map;
49
50 import org.xml.sax.EntityResolver;
51 import org.xml.sax.ErrorHandler;
52 import org.xml.sax.InputSource;
53 import org.xml.sax.SAXException;
54 import org.xml.sax.SAXParseException;
55 import org.xml.sax.XMLReader;
56 import org.xml.sax.helpers.XMLReaderFactory;
57
58 import com.gargoylesoftware.htmlunit.CollectingAlertHandler;
59 import com.gargoylesoftware.htmlunit.MockWebConnection;
60 import com.gargoylesoftware.htmlunit.ScriptEngine;
61 import com.gargoylesoftware.htmlunit.ScriptException;
62 import com.gargoylesoftware.htmlunit.WebClient;
63 import com.gargoylesoftware.htmlunit.WebTestCase;
64 import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
65 import com.gargoylesoftware.htmlunit.html.HtmlButtonInput;
66 import com.gargoylesoftware.htmlunit.html.HtmlElement;
67 import com.gargoylesoftware.htmlunit.html.HtmlForm;
68 import com.gargoylesoftware.htmlunit.html.HtmlFrame;
69 import com.gargoylesoftware.htmlunit.html.HtmlPage;
70 import com.gargoylesoftware.htmlunit.html.HtmlScript;
71 import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
72 import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
73
74
75 /**
76  * Tests for the Javascript engine
77  *
78  * @version $Revision: 1.29 $
79  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
80  * @author Noboru Sinohara
81  * @author Darrell DeBoer
82  * @author <a HREF="mailto:bcurren@esomnie.com">Ben Curren</a>
83  * @author Marc Guillemot
84  */

85 public class JavaScriptEngineTest extends WebTestCase {
86     /**
87      * Create an instance
88      * @param name The name of the test
89      */

90     public JavaScriptEngineTest( final String name ) {
91         super(name);
92     }
93
94
95     /**
96      * @throws Exception if the test fails
97      */

98     public void testSetJavascriptEnabled_false() throws Exception {
99         final WebClient client = new WebClient();
100         client.setJavaScriptEnabled(false);
101         final MockWebConnection webConnection = new MockWebConnection( client );
102
103         final String content
104             = "<html><head><title>foo</title><script>"
105             + "document.form1.textfield1='blue'"
106             + "</script></head><body>"
107             + "<p>hello world</p>"
108             + "<form name='form1'>"
109             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
110             + " <input type='text' name='textfield2' id='textfield2'/>"
111             + "</form>"
112             + "</body></html>";
113
114         webConnection.setDefaultResponse( content );
115         client.setWebConnection( webConnection );
116
117         final HtmlPage page = (HtmlPage) client.getPage(URL_GARGOYLE);
118
119         final HtmlTextInput textInput = (HtmlTextInput)page.getHtmlElementById("textfield1");
120         assertEquals("foo", textInput.getValueAttribute());
121     }
122
123     /**
124      * Try to set the value of a text input field.
125      * @throws Exception if the test fails
126      */

127     public void testSetInputValue() throws Exception {
128         final String content
129             = "<html><head><title>foo</title><script>"
130             + "function doTest(){\n"
131             + " document.form1.textfield1.value='blue'"
132             + "}\n"
133             + "</script></head><body onload='doTest()'>"
134             + "<p>hello world</p>"
135             + "<form name='form1'>"
136             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
137             + " <input type='text' name='textfield2' id='textfield2'/>"
138             + "</form>"
139             + "</body></html>";
140         final List collectedAlerts = null;
141         final HtmlPage page = loadPage(content, collectedAlerts);
142
143         final HtmlTextInput textInput = (HtmlTextInput)page.getHtmlElementById("textfield1");
144         assertEquals("blue", textInput.getValueAttribute());
145     }
146
147
148     /**
149      * @throws Exception if the test fails
150      */

151     public void testAlert() throws Exception {
152         final String content
153             = "<html><head><title>foo</title><script>"
154             + "alert('foo')"
155             + "</script></head><body>"
156             + "<p>hello world</p>"
157             + "<form name='form1'>"
158             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
159             + " <input type='text' name='textfield2' id='textfield2'/>"
160             + "</form>"
161             + "</body></html>";
162         final List collectedAlerts = new ArrayList();
163         final HtmlPage page = loadPage(content, collectedAlerts);
164         assertEquals("foo", page.getTitleText());
165
166         final List expectedAlerts = Arrays.asList( new String[]{
167             "foo"
168         });
169         assertEquals( expectedAlerts, collectedAlerts );
170     }
171
172
173     /**
174      * Checks that a dynamically compiled function works in the scope of its birth
175      * @throws Exception if the test fails
176      */

177     public void testScopeOfNewFunction() throws Exception {
178         final String content
179             = "<html><head><script>"
180             + "var f = new Function('alert(\"foo\")');"
181             + "f();"
182             + "</script></head><body>"
183             + "</body></html>";
184         final List expectedAlerts = Arrays.asList( new String[]{"foo"});
185         createTestPageForRealBrowserIfNeeded(content, expectedAlerts);
186
187         final List collectedAlerts = new ArrayList();
188         loadPage(content, collectedAlerts);
189
190         assertEquals( expectedAlerts, collectedAlerts );
191     }
192
193     /**
194      * @throws Exception if the test fails
195      */

196     public void testScopeOfNestedNewFunction() throws Exception {
197         final List expectedAlerts = Collections.singletonList("foo");
198         final String content
199             = "<html><head>"
200             + "<script>\n"
201             + "var foo = 'foo';\n"
202             + "var f1 = new Function('f = new Function(\"alert(foo)\"); f()');\n"
203             + "f1();\n"
204             + "</script>"
205             + "</head>"
206             + "<body>\n"
207             + "</body></html>\n";
208         createTestPageForRealBrowserIfNeeded(content, expectedAlerts);
209         final List collectedAlerts = new ArrayList();
210         loadPage(content, collectedAlerts);
211         
212         assertEquals(expectedAlerts, collectedAlerts);
213     }
214
215     /**
216      * Checks that a dynamically compiled function works in the scope of its birth
217      * and not the other window
218      * @throws Exception if the test fails
219      */

220     public void testScopeOfNewFunctionCalledFormOtherWindow() throws Exception {
221         final String firstContent
222             = "<html><head>"
223             + "<script>"
224             + "var foo = 'foo';"
225             + "var test = new Function('alert(foo);');"
226             + "</script>"
227             + "</head>"
228             + "<body onload='test()'>"
229             + " <iframe SRC='page2.html'/>"
230             + "</body>"
231             + "</html>";
232         
233         final String secondContent = "<html><head><script>"
234             + "var foo = 'foo2';"
235             + "parent.test();"
236             + "var f = parent.test;"
237             + "f();"
238             + "</script></head></html>";
239
240         
241         final WebClient client = new WebClient();
242         final MockWebConnection webConnection = new MockWebConnection( client );
243         webConnection.setDefaultResponse( secondContent );
244         webConnection.setResponse(URL_FIRST, firstContent);
245         client.setWebConnection( webConnection );
246
247         final List expectedAlerts = Arrays.asList( new String[]{"foo", "foo", "foo"});
248
249         final List collectedAlerts = new ArrayList();
250         client.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
251         client.getPage(URL_FIRST);
252
253         assertEquals( expectedAlerts, collectedAlerts );
254     }
255
256     /**
257      * @throws Exception if the test fails
258      */

259     public void testExternalScript() throws Exception {
260
261         final WebClient client = new WebClient();
262         final MockWebConnection webConnection = new MockWebConnection( client );
263
264         final String htmlContent
265             = "<html><head><title>foo</title><script SRC='/foo.js' id='script1'/>"
266             + "</head><body>"
267             + "<p>hello world</p>"
268             + "<form name='form1'>"
269             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
270             + " <input type='text' name='textfield2' id='textfield2'/>"
271             + "</form>"
272             + "</body></html>";
273
274         final String jsContent = "alert('got here');";
275
276         webConnection.setResponse(URL_GARGOYLE, htmlContent);
277         webConnection.setResponse(new URL("http://www.gargoylesoftware.com/foo.js"), jsContent,
278                 "text/javascript");
279         client.setWebConnection( webConnection );
280
281         final List expectedAlerts = Collections.singletonList("got here");
282         final List collectedAlerts = new ArrayList();
283         client.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
284
285         final HtmlPage page = (HtmlPage) client.getPage(URL_GARGOYLE);
286         final HtmlScript htmlScript = (HtmlScript)page.getHtmlElementById("script1");
287         assertNotNull(htmlScript);
288         assertEquals( expectedAlerts, collectedAlerts );
289     }
290
291
292     /**
293      * @throws Exception if the test fails
294      */

295     public void testExternalScriptEncoding() throws Exception {
296         final WebClient client = new WebClient();
297         final MockWebConnection webConnection = new MockWebConnection( client );
298         /*
299      * this page has meta element , and script tag has no charset attribute
300      */

301         final String htmlContent
302             = "<html><head>"
303             + "<meta http-equiv='content-type' content='text/html; charset=Shift_JIS'>"
304             + "<title>foo</title>"
305             + "<script SRC='/foo.js' id='script1'/>"
306             + "</head><body>"
307             + "<p>hello world</p>"
308             + "<form name='form1'>"
309             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
310             + " <input type='text' name='textfield2' id='textfield2'/>"
311             + "</form>"
312             + "</body></html>";
313
314     /*
315      * this page has no meta element , and script tag has charset attribute
316      */

317         final String htmlContent2
318             = "<html><head>"
319             + "<title>foo</title>"
320             + "<script SRC='/foo2.js' charset='Shift_JIS' id='script2'/>"
321             + "</head><body>"
322             + "<p>hello world</p>"
323             + "<form name='form1'>"
324             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
325             + " <input type='text' name='textfield2' id='textfield2'/>"
326             + "</form>"
327             + "</body></html>";
328
329         /*
330          * the corresponding SJIS char of '?' has '\' in second byte.
331          * if encoding is misspecificated,
332          * this cause 'unterminated string reteral error'
333          */

334         final String jsContent = "alert('\u8868');";
335
336         webConnection.setResponse(URL_GARGOYLE, htmlContent);
337
338         webConnection.setResponse(
339             new URL("http://www.gargoylesoftware.com/hidden"),
340             htmlContent2);
341
342         webConnection.setResponse(
343             new URL("http://www.gargoylesoftware.com/foo.js"),
344         // make SJIS bytes as responsebody
345
new String(jsContent.getBytes("SJIS"),"8859_1"), "text/javascript");
346
347     /*
348      * foo2.js is same with foo.js
349      */

350         webConnection.setResponse(
351             new URL("http://www.gargoylesoftware.com/foo2.js"),
352         // make SJIS bytes as responsebody
353
new String(jsContent.getBytes("SJIS"),"8859_1"),
354             "text/javascript");
355
356         client.setWebConnection( webConnection );
357
358         final List expectedAlerts = Collections.singletonList("\u8868");
359         final List collectedAlerts = new ArrayList();
360         client.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
361
362     /*
363      * detect encoding from meta tag
364      */

365         final HtmlPage page = (HtmlPage) client.getPage(URL_GARGOYLE);
366         final HtmlScript htmlScript =
367                      (HtmlScript)page.getHtmlElementById("script1");
368
369         assertNotNull(htmlScript);
370         assertEquals( expectedAlerts, collectedAlerts );
371
372     /*
373      * detect encoding from charset attribute of script tag
374      */

375         collectedAlerts.clear();
376         final HtmlPage page2 = ( HtmlPage )client.getPage(
377              new URL( "http://www.gargoylesoftware.com/hidden"));
378         final HtmlScript htmlScript2 =
379                      (HtmlScript)page2.getHtmlElementById("script2");
380
381         assertNotNull(htmlScript2);
382         assertEquals( expectedAlerts, collectedAlerts );
383     }
384
385     /**
386      * Set value on input expects a string. If you pass in a value that isn't a string
387      * this used to blow up.
388      * @throws Exception if the test fails
389      */

390     public void testSetValuesThatAreNotStrings() throws Exception {
391         final String content
392             = "<html><head><title>foo</title><script>"
393             + "function doTest() {\n"
394             + " document.form1.textfield1.value=1;"
395             + " alert(document.form1.textfield1.value)"
396             + "}\n"
397             + "</script></head><body onload='doTest()'>"
398             + "<p>hello world</p>"
399             + "<form name='form1'>"
400             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
401             + " <input type='text' name='textfield2' id='textfield2'/>"
402             + "</form>"
403             + "</body></html>";
404         final List collectedAlerts = new ArrayList();
405         final HtmlPage page = loadPage(content, collectedAlerts);
406         assertEquals("foo", page.getTitleText());
407
408         final List expectedAlerts = Arrays.asList( new String[]{
409             "1"
410         });
411         assertEquals( expectedAlerts, collectedAlerts );
412     }
413
414
415     /**
416      * @throws Exception if the test fails
417      */

418     public void testReferencingVariablesFromOneScriptToAnother_Regression() throws Exception {
419
420         final WebClient client = new WebClient();
421         final MockWebConnection webConnection = new MockWebConnection( client );
422
423         final String htmlContent
424             = "<html><head><title>foo</title><script SRC='./test.js'></script>"
425             + "<script>var testLocalVariable = new Array();</script>"
426             + "</head><body onload='testNestedMethod();' >"
427             + "<form name='form1' method='POST' action='../foo' >"
428             + " <input type='submit' value='Login' name='loginButton'>"
429             + "</form></body></html>";
430
431         final String jsContent
432             = "function testNestedMethod() {\n"
433             + " if (testLocalVariable == null)\n"
434             + " testLocalVariable = 'foo';\n"
435             + "} ";
436         
437         webConnection.setResponse(URL_FIRST, htmlContent);
438         webConnection.setResponse(new URL("http://first/test.js"), jsContent, "text/javascript");
439         client.setWebConnection( webConnection );
440
441         final HtmlPage page = (HtmlPage) client.getPage(URL_FIRST);
442         assertEquals("foo", page.getTitleText());
443
444     }
445
446
447     /**
448      * @throws Exception if the test fails
449      */

450     public void testJavaScriptUrl() throws Exception {
451
452         final String htmlContent
453             = "<html><head><script language='javascript'>"
454             + "var f1 = '<html><head><title>frame1</title></head><body><h1>frame1</h1></body></html>';\n"
455             + "var f2 = '<html><head><title>frame2</title></head><body><h1>frame2</h1></body></html>';\n"
456             + "</script></head>\n"
457             + "<frameset border='0' frameborder='0' framespacing='0' rows='100,*'>"
458             + " <frame id='frame1' SRC='javascript:parent.f1'/>"
459             + " <frame id='frame2' SRC='javascript:parent.f2'/>"
460             + "</frameset></html>";
461
462         createTestPageForRealBrowserIfNeeded(htmlContent, Collections.EMPTY_LIST);
463         final HtmlPage page = loadPage(htmlContent);
464
465         final HtmlPage page1 = (HtmlPage)((HtmlFrame)page.getHtmlElementById("frame1")).getEnclosedPage();
466         final HtmlPage page2 = (HtmlPage)((HtmlFrame)page.getHtmlElementById("frame2")).getEnclosedPage();
467
468         assertNotNull("page1", page1);
469         assertNotNull("page2", page2);
470
471         assertEquals( "frame1", page1.getTitleText() );
472         assertEquals( "frame2", page2.getTitleText() );
473     }
474
475
476     /**
477      * @throws Exception if the test fails
478      */

479     public void testJavaScriptWrappedInHtmlComments() throws Exception {
480         final String htmlContent
481             = "<html><head><title>foo</title><script language='javascript'><!--\n"
482             + "function doTest() {\n"
483             + "}\n"
484             + "-->\n</script></head>\n"
485             + "<body onload='doTest()'></body></html>";
486         final HtmlPage page = loadPage(htmlContent);
487         assertEquals("foo", page.getTitleText());
488     }
489
490
491     /**
492      * @throws Exception if the test fails
493      */

494     public void testJavaScriptWrappedInHtmlComments_commentOnOpeningLine() throws Exception {
495         final String htmlContent
496             = "<html><head><title>foo</title><script language='javascript'><!-- Some comment here\n"
497             + "function doTest() {\n"
498             + "}\n"
499             + "-->\n</script></head>\n"
500             + "<body onload='doTest()'></body></html>";
501
502         final HtmlPage page = loadPage(htmlContent);
503         assertEquals("foo", page.getTitleText());
504     }
505
506
507     /**
508      * @throws Exception If the test fails.
509      */

510     public void testJavaScriptWrappedInHtmlComments_allOnOneLine() throws Exception {
511         final String content
512             = "<html>\n"
513             + " <head>\n"
514             + " <title>test</title>\n"
515             + " <script>var test;</script>\n"
516             + " <!-- var test should be undefined since it's on first line -->\n"
517             + " <!-- but there should be no index out of bounds exception -->\n"
518             + " <script> <!-- test = 'abc'; // --> </script>\n"
519             + " </head>\n"
520             + " <body onload='alert(test)'>\n"
521             + " </body>\n"
522             + "</html>\n";
523         final List collectedAlerts = new ArrayList();
524         loadPage(content, collectedAlerts);
525         final List expectedAlerts = Arrays.asList( new String[]{"undefined"} );
526         assertEquals(expectedAlerts, collectedAlerts);
527     }
528
529
530     /**
531      * When using the syntax this.something in an onclick handler, "this" must represent
532      * the object being clicked, not the window. Regression test.
533      * @throws Exception if the test fails
534      */

535     public void testThisDotInOnClick() throws Exception {
536
537         final String htmlContent
538             = "<html><head><title>First</title><script>function foo(message){alert(message);}</script><body>"
539              + "<form name='form1'><input type='submit' name='button1' onClick='foo(this.name)'></form>"
540              + "</body></html>";
541
542         final List collectedAlerts = new ArrayList();
543         final HtmlPage page = loadPage(htmlContent, collectedAlerts);
544         assertEquals("First", page.getTitleText());
545
546         ((HtmlSubmitInput)page.getFormByName("form1").getInputByName("button1")).click();
547
548         final List expectedAlerts = Collections.singletonList("button1");
549         assertEquals( expectedAlerts, collectedAlerts );
550     }
551
552
553     /**
554      * @throws Exception if the test fails
555      */

556     public void testFunctionDefinedInExternalFile_CalledFromInlineScript() throws Exception {
557
558         final WebClient client = new WebClient();
559         final MockWebConnection webConnection = new MockWebConnection( client );
560
561         final String htmlContent
562             = "<html><head><title>foo</title><script SRC='./test.js'></script>"
563             + "</head><body>"
564             + " <script>externalMethod()</script>"
565             + "</body></html>";
566
567         final String jsContent
568             = "function externalMethod() {\n"
569             + " alert('Got to external method');\n"
570             + "} ";
571
572         webConnection.setResponse(
573             new URL("http://first/index.html"),
574             htmlContent);
575         webConnection.setResponse(
576             new URL("http://first/test.js"),
577             jsContent, "text/javascript");
578         client.setWebConnection( webConnection );
579
580         final List collectedAlerts = new ArrayList();
581         client.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
582
583         final HtmlPage page = (HtmlPage) client.getPage(new URL("http://first/index.html"));
584         assertEquals("foo", page.getTitleText());
585         assertEquals( Collections.singletonList("Got to external method"), collectedAlerts );
586     }
587
588
589     /**
590      * Test case for bug 707134. Currently I am unable to reproduce the problem.
591      * @throws Exception if the test fails
592      */

593     public void testFunctionDefinedInSameFile() throws Exception {
594         final String htmlContent
595             = "<html><head><title>First</title><script>"
596             + "function showFoo( foo ) {\n"
597             + " alert( 'Foo is: |' + foo + '|' );\n"
598             + "}\n"
599             + "</script>"
600             + "</head><body><form name='form1'>"
601             + "<input name='text1' type='text'>\n"
602             + "<input name='button1' type='button' onclick='showFoo( document.form1.text1.value);'>\n"
603             + "</form></body></html>";
604
605         final List collectedAlerts = new ArrayList();
606
607         final HtmlPage page = loadPage(htmlContent, collectedAlerts);
608         assertEquals("First", page.getTitleText());
609
610         final HtmlForm form = page.getFormByName("form1");
611         final HtmlTextInput textInput = (HtmlTextInput)form.getInputByName("text1");
612         textInput.setValueAttribute("flintstone");
613
614         final HtmlButtonInput button = (HtmlButtonInput)form.getInputByName("button1");
615         assertEquals( Collections.EMPTY_LIST, collectedAlerts );
616
617         button.click();
618
619         assertEquals( Collections.singletonList("Foo is: |flintstone|"), collectedAlerts );
620     }
621
622     /**
623      * Test that the file JavaScriptConfiguration.xml is valid.
624      * @throws Exception If the test fails
625      */

626     public void testConfigurationFileAgainstSchema() throws Exception {
627         final XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
628         final String directory = "src/java/com/gargoylesoftware/htmlunit/javascript/";
629         parser.setFeature("http://xml.org/sax/features/validation", true);
630         parser.setFeature("http://apache.org/xml/features/validation/schema", true);
631         parser.setEntityResolver( new EntityResolver() {
632             public InputSource resolveEntity (final String publicId, final String systemId) throws IOException {
633                 return createInputSourceForFile(directory+"JavaScriptConfiguration.xsd");
634             }
635         });
636         parser.setErrorHandler( new ErrorHandler() {
637             public void warning(final SAXParseException exception) throws SAXException {
638                 throw exception;
639             }
640             public void error(final SAXParseException exception) throws SAXException {
641                 throw exception;
642             }
643             public void fatalError(final SAXParseException exception) throws SAXException {
644                 throw exception;
645             }
646         });
647
648         parser.parse( createInputSourceForFile(directory+"JavaScriptConfiguration.xml") );
649
650     }
651
652     /**
653      * Test that the javascript engine gets called correctly for variable access.
654      * @throws Exception If the test fails
655      */

656     public void testJavaScriptEngineCallsForVariableAccess() throws Exception {
657         final WebClient client = new WebClient();
658         final MockWebConnection webConnection = new MockWebConnection( client );
659
660         final List collectedAlerts = new ArrayList();
661         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
662
663         final String content
664             = "<html><head><title>foo</title><script>"
665             + "myDate = 'foo';"
666             + "function doUnqualifiedVariableAccess() {\n"
667             + " alert('unqualified: ' + myDate);\n"
668             + "}\n"
669             + "function doQualifiedVariableAccess() {\n"
670             + " alert('qualified: ' + window.myDate);\n"
671             + "}\n"
672             + "</script></head><body>"
673             + "<p>hello world</p>"
674             + "<a id='unqualified' onclick='doUnqualifiedVariableAccess();'>unqualified</a>"
675             + "<a id='qualified' onclick='doQualifiedVariableAccess();'>qualified</a>"
676             + "</body></html>";
677
678         webConnection.setDefaultResponse( content );
679         client.setWebConnection( webConnection );
680         final CountingJavaScriptEngine countingJavaScriptEngine = new CountingJavaScriptEngine(
681                 client.getScriptEngine());
682         client.setScriptEngine(countingJavaScriptEngine);
683
684         final HtmlPage page = (HtmlPage) client.getPage(URL_GARGOYLE);
685
686         assertEquals(1, countingJavaScriptEngine.getExecutionCount());
687         assertEquals(0, countingJavaScriptEngine.getCallCount());
688         
689         ((HtmlAnchor) page.getHtmlElementById("unqualified")).click();
690         assertEquals(1, countingJavaScriptEngine.getExecutionCount());
691         assertEquals(1, countingJavaScriptEngine.getCallCount());
692         
693         ((HtmlAnchor) page.getHtmlElementById("qualified")).click();
694         assertEquals(1, countingJavaScriptEngine.getExecutionCount());
695         assertEquals(2, countingJavaScriptEngine.getCallCount());
696
697         final List expectedAlerts = Arrays.asList(new String[]{"unqualified: foo", "qualified: foo"});
698         assertEquals(expectedAlerts, collectedAlerts);
699     }
700
701     /**
702      * ActiveX related exceptions that do not require a map
703      * @throws Exception If the test fails
704      */

705     public void testActiveXObjectNoMap() throws Exception {
706
707         try {
708             loadPage(getJavaScriptContent( "new ActiveXObject()" ));
709             fail( "An exception should be thrown for zero argument constructor." );
710         }
711         catch( final ScriptException e ) {
712             // Success
713
}
714
715         try {
716             loadPage(getJavaScriptContent( "new ActiveXObject(1, '2', '3')" ));
717             fail( "An exception should be thrown for a three argument constructor." );
718         }
719         catch( final ScriptException e ) {
720             // Success
721
}
722
723         try {
724             loadPage(getJavaScriptContent( "new ActiveXObject(a)" ));
725             fail( "An exception should be thrown for an undefined parameter in the constructor." );
726         }
727         catch( final ScriptException e ) {
728             // Success
729
}
730
731         try {
732             loadPage(getJavaScriptContent( "new ActiveXObject(10)" ));
733             fail( "An exception should be thrown for an integer parameter in the constructor." );
734         }
735         catch( final ScriptException e ) {
736             // Success
737
}
738
739         try {
740             loadPage(getJavaScriptContent( "new ActiveXObject('UnknownObject')" ));
741             fail( "An exception should be thrown for a null map." );
742         }
743         catch( final ScriptException e ) {
744             // Success
745
}
746     }
747     
748     /**
749      * Test that Java objects placed in the active x map can be instantiated and used within
750      * javascript using the IE specific ActiveXObject constructor.
751      * @throws Exception If the test fails
752      */

753     public void testActiveXObjectWithMap() throws Exception {
754         final Map activexToJavaMapping = new HashMap();
755         activexToJavaMapping.put(
756                 "MockActiveXObject",
757                 "com.gargoylesoftware.htmlunit.javascript.MockActiveXObject");
758         activexToJavaMapping.put(
759                 "FakeObject",
760                 "com.gargoylesoftware.htmlunit.javascript.NoSuchObject");
761         activexToJavaMapping.put("BadObject", new Object());
762
763         final WebClient client = new WebClient();
764         final MockWebConnection webConnection = new MockWebConnection(client);
765         client.setWebConnection(webConnection);
766         client.setActiveXObjectMap(activexToJavaMapping);
767         final List collectedAlerts = new ArrayList();
768         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
769
770         webConnection.setDefaultResponse( getJavaScriptContent( "new ActiveXObject('UnknownObject')" ) );
771         try {
772             client.getPage( new URL( "http://www.yahoo.com" ) );
773             fail( "An exception should be thrown for non existent object in the map." );
774         }
775         catch( final ScriptException e ) {
776             // Success
777
}
778
779         webConnection.setDefaultResponse( getJavaScriptContent( "new ActiveXObject('BadObject', 'server')" ) );
780         try {
781             client.getPage( new URL( "http://www.yahoo.com" ) );
782             fail( "An exception should be thrown for an invalid object in the map." );
783         }
784         catch( final ScriptException e ) {
785             // Success
786
}
787
788         // Test for a non existent class in the map
789
webConnection.setDefaultResponse( getJavaScriptContent( "new ActiveXObject('FakeObject')" ) );
790         try {
791             client.getPage( new URL( "http://www.yahoo.com" ) );
792             fail( "An exception should be thrown for a non existent object in the map." );
793         }
794         catch( final ScriptException e ) {
795             // Success
796
}
797
798         assertEquals("should no alerts yet", Collections.EMPTY_LIST, collectedAlerts);
799         
800         // Try a valid object in the map
801
webConnection.setDefaultResponse( getJavaScriptContent(
802                 "var t = new ActiveXObject('MockActiveXObject'); alert(t.MESSAGE);" ) );
803         client.getPage( new URL( "http://www.yahoo.com" ) );
804         assertEquals(
805                 "The active x object did not bind to the object.",
806                 Collections.singletonList(MockActiveXObject.MESSAGE),
807                 collectedAlerts);
808
809         collectedAlerts.clear();
810         
811         webConnection.setDefaultResponse( getJavaScriptContent(
812                 "var t = new ActiveXObject('MockActiveXObject', 'server'); alert(t.GetMessage());" ) );
813         client.getPage( new URL( "http://www.yahoo.com" ) );
814         assertEquals(
815                 "The active x object did not bind to the object.",
816                 Collections.singletonList(new MockActiveXObject().GetMessage()),
817                 collectedAlerts);
818         
819     }
820
821     private String getJavaScriptContent( final String javascript ) {
822         return "<html><head><title>foo</title><script>"
823              + javascript
824              + "</script></head><body>"
825              + "<p>hello world</p>"
826              + "<form name='form1'>"
827              + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
828              + " <input type='text' name='textfield2' id='textfield2'/>"
829              + "</form>"
830              + "</body></html>";
831     }
832
833     
834     /**
835      * Check that wrong javascript just causes its context to fail but not the whole page.
836      * @throws Exception If something goes wrong.
837      */

838     public void testScriptErrorIsolated() throws Exception {
839
840         final String content
841             = "<html>"
842             + "<head>"
843             + "<script>alert(1);</script>"
844             + "<script>alert(2</script>"
845             + "<script>alert(3);</script>"
846             + "</head>"
847             + "<body onload='alert(4);notExisting()'>"
848             + "<button onclick='alert(5)'>click me</button>"
849             + "</body>"
850             + "</html>";
851
852         final List expectedAlerts = Arrays.asList( new String[]{ "1", "3", "4" } );
853         createTestPageForRealBrowserIfNeeded(content, expectedAlerts);
854
855         final WebClient client = new WebClient();
856         final MockWebConnection webConnection = new MockWebConnection(client);
857         webConnection.setDefaultResponse(content);
858         client.setWebConnection(webConnection);
859         final List collectedAlerts = new ArrayList();
860         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
861
862         // first test with script exceptions thrown
863
try {
864             client.getPage(URL_FIRST);
865             fail("Should have thrown a script error");
866         }
867         catch (final Exception e) {
868             // nothing
869
}
870         assertEquals(Collections.singletonList("1"), collectedAlerts);
871         collectedAlerts.clear();
872
873         // and with script exception not thrown
874
client.setThrowExceptionOnScriptError(false);
875         client.getPage(URL_FIRST);
876         
877         assertEquals(expectedAlerts, collectedAlerts);
878     }
879     
880     
881     private InputSource createInputSourceForFile( final String fileName ) throws FileNotFoundException {
882         return new InputSource( getFileAsStream(fileName) );
883     }
884
885     private static final class CountingJavaScriptEngine extends ScriptEngine {
886         private ScriptEngine delegate_;
887         private int scriptExecutionCount_ = 0;
888         private int scriptCallCount_ = 0;
889
890         /**
891          * Create an instance
892          * @param delegate The ScriptEngine that we're wrapping.
893          */

894         protected CountingJavaScriptEngine(ScriptEngine delegate) {
895             super(delegate.getWebClient());
896             delegate_ = delegate;
897         }
898
899         /**
900          * Initialize with a given page.
901          * @param page The page.
902          */

903         public void initialize(final HtmlPage page) {
904             delegate_.initialize(page);
905         }
906
907         /** @inheritDoc ScriptEngine#execute(HtmlPage,String,String,HtmlElement) */
908         public Object execute(
909                 final HtmlPage htmlPage, final String sourceCode,
910                 final String sourceName, final HtmlElement htmlElement) {
911             scriptExecutionCount_++;
912             return delegate_.execute(htmlPage, sourceCode, sourceName, htmlElement);
913         }
914
915         /** @inheritDoc ScriptEngine#callFunction(HtmlPage,Object,Object,Object[],HtmlElement) */
916         public Object callFunction(
917                 final HtmlPage htmlPage, final Object javaScriptFunction,
918                 final Object thisObject, final Object[] args,
919                 final HtmlElement htmlElementScope) {
920             scriptCallCount_++;
921             return delegate_.callFunction(htmlPage, javaScriptFunction, thisObject, args, htmlElementScope);
922         }
923
924         /** @inheritDoc ScriptEngine#toString(HtmlPage,Object) */
925         public String toString(final HtmlPage htmlPage, final Object javaScriptObject) {
926             return delegate_.toString(htmlPage, javaScriptObject);
927         }
928
929         /** @return The number of times that this engine has called functions */
930         public int getCallCount() {
931             return scriptCallCount_;
932         }
933         /** @return The number of times that this engine has executed code */
934         public int getExecutionCount() {
935             return scriptExecutionCount_;
936         }
937         /** @return true if the script is running */
938         public boolean isScriptRunning() {
939             return false;
940         }
941     }
942 }
943
944
Popular Tags