KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > gargoylesoftware > htmlunit > WebClientTest


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;
39
40 import java.io.ByteArrayOutputStream;
41 import java.io.File;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.io.OutputStreamWriter;
45 import java.net.URI;
46 import java.net.URL;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.List;
51
52 import org.apache.commons.io.FileUtils;
53 import org.apache.commons.lang.StringUtils;
54
55 import com.gargoylesoftware.base.testing.EventCatcher;
56 import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
57 import com.gargoylesoftware.htmlunit.html.HtmlElement;
58 import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame;
59 import com.gargoylesoftware.htmlunit.html.HtmlPage;
60 import com.gargoylesoftware.htmlunit.xml.XmlPage;
61
62 /**
63  * Tests for WebClient
64  *
65  * @version $Revision: 1.51 $
66  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
67  * @author <a HREF="mailto:cse@dynabean.de">Christian Sell</a>
68  * @author <a HREF="mailto:bcurren@esomnie.com">Ben Curren</a>
69  * @author Marc Guillemot
70  * @author David D. Kilzer
71  * @author Chris Erskine
72  * @author Hans Donner
73  */

74 public class WebClientTest extends WebTestCase {
75
76     /**
77      * Create an instance
78      *
79      * @param name The name of the test
80      */

81     public WebClientTest( final String name ) {
82         super( name );
83     }
84
85
86     /**
87      * Test the situation where credentials are required but they haven't been specified.
88      *
89      * @throws Exception If something goes wrong.
90      */

91     public void testCredentialProvider_NoCredentials() throws Exception {
92
93         final String htmlContent
94             = "<html><head><title>foo</title></head><body>"
95             + "No access</body></html>";
96         final WebClient client = new WebClient();
97         client.setPrintContentOnFailingStatusCode( false );
98
99         final MockWebConnection webConnection = new MockWebConnection( client );
100         webConnection.setDefaultResponse(
101             htmlContent, 401, "Credentials missing or just plain wrong", "text/plain" );
102         client.setWebConnection( webConnection );
103
104         try {
105             client.getPage(new WebRequestSettings(URL_GARGOYLE, SubmitMethod.POST));
106             fail( "Expected FailingHttpStatusCodeException" );
107         }
108         catch( final FailingHttpStatusCodeException e ) {
109             assertEquals( 401, e.getStatusCode() );
110         }
111     }
112
113
114     /**
115      * Test that {@link WebClient#assertionFailed(String)} actually throws an exception.
116      */

117     public void testAssertionFailed() {
118         final WebClient client = new WebClient();
119
120         try {
121             client.assertionFailed( "foobar" );
122             fail( "Expected AssertionFailedError" );
123         }
124         catch( final junit.framework.AssertionFailedError e ) {
125             assertEquals( "foobar", e.getMessage() );
126         }
127     }
128
129
130     /**
131      * Test that the {@link WebWindowEvent#CHANGE} window event gets fired at the
132      * appropriate time.
133      * @throws Exception If something goes wrong.
134      */

135     public void testHtmlWindowEvents_changed() throws Exception {
136         final String htmlContent
137             = "<html><head><title>foo</title></head><body>"
138             + "<a HREF='http://www.foo2.com' id='a2'>link to foo2</a>"
139             + "</body></html>";
140         final WebClient client = new WebClient();
141         final EventCatcher eventCatcher = new EventCatcher();
142         eventCatcher.listenTo(client);
143
144         final MockWebConnection webConnection = new MockWebConnection( client );
145         webConnection.setDefaultResponse( htmlContent );
146         client.setWebConnection( webConnection );
147
148         final HtmlPage firstPage = ( HtmlPage )client.getPage(URL_GARGOYLE);
149         final HtmlAnchor anchor = ( HtmlAnchor )firstPage.getHtmlElementById( "a2" );
150
151         final List firstExpectedEvents = Arrays.asList( new Object[] {
152             new WebWindowEvent(
153                 client.getCurrentWindow(), WebWindowEvent.CHANGE, null, firstPage),
154         } );
155         assertEquals( firstExpectedEvents, eventCatcher.getEvents() );
156
157         eventCatcher.clear();
158         final HtmlPage secondPage = ( HtmlPage )anchor.click();
159
160         final List secondExpectedEvents = Arrays.asList( new Object[] {
161             new WebWindowEvent(
162                 client.getCurrentWindow(), WebWindowEvent.CHANGE, firstPage, secondPage),
163         } );
164         assertEquals( secondExpectedEvents, eventCatcher.getEvents() );
165     }
166
167
168     /**
169      * Test that the {@link WebWindowEvent#OPEN} window event gets fired at
170      * the appropriate time.
171      * @throws Exception If something goes wrong.
172      */

173     public void testHtmlWindowEvents_opened() throws Exception {
174         final String page1Content
175             = "<html><head><title>foo</title>"
176             + "<script>window.open('" + URL_SECOND.toExternalForm() + "', 'myNewWindow')</script>"
177             + "</head><body>"
178             + "<a HREF='http://www.foo2.com' id='a2'>link to foo2</a>"
179             + "</body></html>";
180         final String page2Content
181             = "<html><head><title>foo</title></head><body></body></html>";
182         final WebClient client = new WebClient();
183         final EventCatcher eventCatcher = new EventCatcher();
184         eventCatcher.listenTo(client);
185
186         final MockWebConnection webConnection = new MockWebConnection( client );
187         webConnection.setResponse(URL_FIRST, page1Content);
188         webConnection.setResponse(URL_SECOND, page2Content);
189
190         client.setWebConnection( webConnection );
191
192         final HtmlPage firstPage = ( HtmlPage )client.getPage(URL_FIRST);
193         assertEquals("foo", firstPage.getTitleText());
194
195         final WebWindow firstWindow = client.getCurrentWindow();
196         final WebWindow secondWindow = client.getWebWindowByName("myNewWindow");
197         final List expectedEvents = Arrays.asList( new Object[] {
198             new WebWindowEvent(
199                 secondWindow, WebWindowEvent.OPEN, null, null),
200             new WebWindowEvent(
201                 secondWindow, WebWindowEvent.CHANGE, null, secondWindow.getEnclosedPage()),
202             new WebWindowEvent(
203                 firstWindow, WebWindowEvent.CHANGE, null, firstPage),
204         } );
205         assertEquals( expectedEvents, eventCatcher.getEvents() );
206     }
207
208
209     /**
210      * Test that the {@link WebWindowEvent#CLOSE} window event gets fired at
211      * the appropriate time.
212      * @throws Exception If something goes wrong.
213      */

214     public void testHtmlWindowEvents_closedFromFrame() throws Exception {
215         final String firstContent
216             = "<html><head><title>first</title></head><body>"
217             + "<iframe SRC='http://third' id='frame1'>"
218             + "<a HREF='http://second' id='a2'>link to foo2</a>"
219             + "</body></html>";
220         final String secondContent
221             = "<html><head><title>second</title></head><body></body></html>";
222         final String thirdContent
223             = "<html><head><title>third</title></head><body></body></html>";
224         final WebClient client = new WebClient();
225
226         final MockWebConnection webConnection = new MockWebConnection( client );
227         webConnection.setResponse(URL_FIRST, firstContent);
228         webConnection.setResponse(URL_SECOND, secondContent);
229         webConnection.setResponse(URL_THIRD, thirdContent);
230
231         client.setWebConnection( webConnection );
232
233         final HtmlPage firstPage = ( HtmlPage )client.getPage(URL_FIRST);
234         assertEquals("first", firstPage.getTitleText());
235
236         final EventCatcher eventCatcher = new EventCatcher();
237         eventCatcher.listenTo(client);
238
239         final HtmlInlineFrame frame = (HtmlInlineFrame)firstPage.getHtmlElementById("frame1");
240         final HtmlPage thirdPage = (HtmlPage)frame.getEnclosedPage();
241
242         // Load the second page
243
final HtmlAnchor anchor = (HtmlAnchor)firstPage.getHtmlElementById( "a2" );
244         final HtmlPage secondPage = (HtmlPage)anchor.click();
245         assertEquals("second", secondPage.getTitleText());
246
247         final WebWindow firstWindow = client.getCurrentWindow();
248         final List expectedEvents = Arrays.asList( new Object[] {
249             new WebWindowEvent(
250                 frame.getEnclosedWindow(), WebWindowEvent.CLOSE, thirdPage, null),
251             new WebWindowEvent(
252                 firstWindow, WebWindowEvent.CHANGE, firstPage, secondPage),
253         } );
254         assertEquals( expectedEvents.get(0), eventCatcher.getEvents().get(0) );
255         assertEquals( expectedEvents, eventCatcher.getEvents() );
256     }
257
258
259     /**
260      * Test a 301 redirection code where the original request was a GET.
261      * @throws Exception If something goes wrong.
262      */

263     public void testRedirection301_MovedPermanently_GetMethod() throws Exception {
264         final int statusCode = 301;
265         final SubmitMethod initialRequestMethod = SubmitMethod.GET;
266         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
267
268         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
269     }
270
271
272     /**
273      * From the http spec: If the 301 status code is received in response
274      * to a request other than GET or HEAD, the user agent MUST NOT automatically
275      * redirect the request unless it can be confirmed by the user, since this
276      * might change the conditions under which the request was issued.
277      * @throws Exception If something goes wrong.
278      */

279     public void testRedirection301_MovedPermanently_PostMethod() throws Exception {
280         final int statusCode = 301;
281         final SubmitMethod initialRequestMethod = SubmitMethod.POST;
282         final SubmitMethod expectedRedirectedRequestMethod = null;
283
284         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
285     }
286
287
288     /**
289      * From the http spec: Note: RFC 1945 and RFC 2068 specify that the client
290      * is not allowed to change the method on the redirected request. However,
291      * most existing user agent implementations treat 302 as if it were a 303
292      * response, performing a GET on the Location field-value regardless
293      * of the original request method. The status codes 303 and 307 have
294      * been added for servers that wish to make unambiguously clear which
295      * kind of reaction is expected of the client.
296      * @throws Exception If something goes wrong.
297      */

298     public void testRedirection302_MovedTemporarily_PostMethod() throws Exception {
299         final int statusCode = 302;
300         final SubmitMethod initialRequestMethod = SubmitMethod.POST;
301         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
302
303         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
304     }
305
306
307     /**
308      * Test a 302 redirection code.
309      * @throws Exception If something goes wrong.
310      */

311     public void testRedirection302_MovedTemporarily_GetMethod() throws Exception {
312         final int statusCode = 302;
313         final SubmitMethod initialRequestMethod = SubmitMethod.GET;
314         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
315
316         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
317     }
318
319
320     /**
321      * Tests a 303 redirection code. This should be the same as a 302.
322      * @throws Exception If something goes wrong.
323      */

324     public void testRedirection303_SeeOther_GetMethod() throws Exception {
325         final int statusCode = 303;
326         final SubmitMethod initialRequestMethod = SubmitMethod.GET;
327         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
328
329         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
330     }
331
332
333     /**
334      * Tests a 303 redirection code - this should be the same as a 302.
335      * @throws Exception If something goes wrong.
336      */

337     public void testRedirection303_SeeOther_PostMethod() throws Exception {
338         final int statusCode = 303;
339         final SubmitMethod initialRequestMethod = SubmitMethod.POST;
340         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
341
342         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
343     }
344
345
346     /**
347      * Tests a 307 redirection code.
348      * @throws Exception If something goes wrong.
349      */

350     public void testRedirection307_TemporaryRedirect_GetMethod() throws Exception {
351         final int statusCode = 307;
352         final SubmitMethod initialRequestMethod = SubmitMethod.GET;
353         final SubmitMethod expectedRedirectedRequestMethod = SubmitMethod.GET;
354
355         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
356     }
357
358
359     /**
360      * Tests a 307 redirection code.
361      * @throws Exception If something goes wrong.
362      */

363     public void testRedirection307_TemporaryRedirect_PostMethod() throws Exception {
364         final int statusCode = 307;
365         final SubmitMethod initialRequestMethod = SubmitMethod.POST;
366         final SubmitMethod expectedRedirectedRequestMethod = null;
367
368         doTestRedirection( statusCode, initialRequestMethod, expectedRedirectedRequestMethod );
369     }
370
371
372     /**
373      * Basic logic for all the redirection tests.
374      *
375      * @param statusCode The code to return from the initial request
376      * @param initialRequestMethod The initial request.
377      * @param expectedRedirectedRequestMethod The submit method of the second (redirected) request.
378      * If a redirect is not expected to happen then this must be null
379      * @throws Exception if the test fails.
380      */

381     private void doTestRedirection(
382             final int statusCode,
383             final SubmitMethod initialRequestMethod,
384             final SubmitMethod expectedRedirectedRequestMethod )
385         throws
386              Exception {
387
388         final String firstContent = "<html><head><title>First</title></head><body></body></html>";
389         final String secondContent = "<html><head><title>Second</title></head><body></body></html>";
390
391         final WebClient webClient = new WebClient();
392         webClient.setThrowExceptionOnFailingStatusCode(false);
393         webClient.setPrintContentOnFailingStatusCode(false);
394
395         final List headers = Collections.singletonList(
396             new KeyValuePair("Location", "http://second") );
397         final MockWebConnection webConnection = new MockWebConnection( webClient );
398         webConnection.setResponse(
399             URL_FIRST, firstContent, statusCode,
400             "Some error", "text/html", headers );
401         webConnection.setResponse(URL_SECOND, secondContent);
402
403         webClient.setWebConnection( webConnection );
404
405         final URL url = URL_FIRST;
406
407         HtmlPage page;
408         WebResponse webResponse;
409
410         //
411
// Second time redirection is turned on (default setting)
412
//
413
page = (HtmlPage) webClient.getPage(new WebRequestSettings(url, initialRequestMethod));
414         webResponse = page.getWebResponse();
415         if( expectedRedirectedRequestMethod == null ) {
416             // No redirect should have happened
417
assertEquals( statusCode, webResponse.getStatusCode() );
418             assertEquals( initialRequestMethod, webConnection.getLastMethod() );
419         }
420         else {
421             // A redirect should have happened
422
assertEquals( 200, webResponse.getStatusCode() );
423             assertEquals( "Second", page.getTitleText() );
424             assertEquals( expectedRedirectedRequestMethod, webConnection.getLastMethod() );
425         }
426
427         //
428
// Second time redirection is turned off
429
//
430
webClient.setRedirectEnabled(false);
431         page = (HtmlPage) webClient.getPage(new WebRequestSettings(url, initialRequestMethod));
432         webResponse = page.getWebResponse();
433         assertEquals( statusCode, webResponse.getStatusCode() );
434         assertEquals( initialRequestMethod, webConnection.getLastMethod() );
435
436     }
437
438
439     /**
440      * Test passing in a null page creator.
441      */

442     public void testSetPageCreator_null() {
443         final WebClient webClient = new WebClient();
444         try {
445             webClient.setPageCreator(null);
446             fail("Expected NullPointerException");
447         }
448         catch( final NullPointerException e ) {
449             // expected path
450
}
451     }
452
453
454     /**
455      * Test {@link WebClient#setPageCreator(PageCreator)}.
456      * @throws Exception If something goes wrong.
457      */

458     public void testSetPageCreator() throws Exception {
459         final String page1Content
460             = "<html><head><title>foo</title>"
461             + "</head><body>"
462             + "<a HREF='http://www.foo2.com' id='a2'>link to foo2</a>"
463             + "</body></html>";
464         final WebClient client = new WebClient();
465
466         final MockWebConnection webConnection = new MockWebConnection( client );
467         webConnection.setResponse(
468             URL_FIRST, page1Content, 200, "OK", "text/html", Collections.EMPTY_LIST );
469
470         client.setWebConnection( webConnection );
471         final List collectedPageCreationItems = new ArrayList();
472         client.setPageCreator( new CollectingPageCreator(collectedPageCreationItems) );
473
474         final Page page = client.getPage(URL_FIRST);
475         assertTrue( "instanceof TextPage", page instanceof TextPage );
476
477         final List expectedPageCreationItems = Arrays.asList( new Object[] {
478             page
479         } );
480
481         assertEquals( expectedPageCreationItems, collectedPageCreationItems );
482     }
483
484
485     /** A PageCreator that collects data */
486     private class CollectingPageCreator implements PageCreator {
487         private final List collectedPages_;
488         /**
489          * Create an instance
490          * @param list The list that will contain the data
491          */

492         public CollectingPageCreator( final List list ) {
493             this.collectedPages_ = list;
494         }
495         /**
496          * Create a page
497          * @param webResponse The web response
498          * @param webWindow The web window
499          * @return The new page
500          * @throws IOException If an IO problem occurs
501          */

502         public Page createPage( final WebResponse webResponse, final WebWindow webWindow )
503             throws IOException {
504             final Page page = new TextPage(webResponse, webWindow);
505             webWindow.setEnclosedPage(page);
506             collectedPages_.add(page);
507             return page;
508         }
509     }
510
511     /**
512      * Test loading a page with POST parameters.
513      * @throws Exception If something goes wrong.
514      */

515     public void testLoadPage_PostWithParameters() throws Exception {
516
517         final String htmlContent
518             = "<html><head><title>foo</title></head><body>"
519             + "</body></html>";
520         final WebClient client = new WebClient();
521
522         final MockWebConnection webConnection = new MockWebConnection( client );
523         webConnection.setDefaultResponse( htmlContent );
524         client.setWebConnection( webConnection );
525
526         final String urlString = "http://first?a=b";
527         final URL url = new URL(urlString);
528         final HtmlPage page = (HtmlPage) client.getPage(new WebRequestSettings(url, SubmitMethod.POST));
529
530         assertEquals(urlString, page.getWebResponse().getUrl().toExternalForm());
531     }
532
533     /**
534      * Test that double / in query string are not changed.
535      * @throws Exception If something goes wrong.
536      */

537     public void testLoadPage_SlashesInQueryString() throws Exception {
538         final String htmlContent
539             = "<html><head><title>foo</title></head>"
540             + "<body><a HREF='foo.html?id=UYIUYTY//YTYUY..F'>to page 2</a>"
541             + "</body></html>";
542
543         final WebClient client = new WebClient();
544
545         final MockWebConnection webConnection = new MockWebConnection(client);
546         webConnection.setDefaultResponse(htmlContent);
547         client.setWebConnection(webConnection);
548         
549         final HtmlPage page = (HtmlPage) client.getPage(URL_FIRST);
550         final HtmlAnchor link = (HtmlAnchor) page.getAnchors().get(0);
551         final Page page2 = link.click();
552         assertEquals("http://first/foo.html?id=UYIUYTY//YTYUY..F", page2.getWebResponse().getUrl().toExternalForm());
553     }
554
555     /**
556      * Test that the query string is encoded to be valid.
557      * @throws Exception If something goes wrong.
558      */

559     public void testLoadPage_EncodeQueryString() throws Exception {
560         final String htmlContent
561             = "<html><head><title>foo</title></head><body>"
562             + "</body></html>";
563         
564         final WebClient client = new WebClient();
565
566         final MockWebConnection webConnection = new MockWebConnection(client);
567         webConnection.setDefaultResponse(htmlContent);
568         client.setWebConnection(webConnection);
569
570         // with query string not encoded
571
HtmlPage page = (HtmlPage) client.getPage(new URL("http://first?a=b c&d=" + ((char) 0xE9) + ((char) 0xE8)));
572         assertEquals(
573             "http://first?a=b%20c&d=%C3%A9%C3%A8",
574             page.getWebResponse().getUrl().toExternalForm());
575
576
577         // with query string already encoded
578
page = (HtmlPage) client.getPage(new URL("http://first?a=b%20c&d=%C3%A9%C3%A8"));
579         assertEquals(
580             "http://first?a=b%20c&d=%C3%A9%C3%A8",
581             page.getWebResponse().getUrl().toExternalForm());
582         
583         // with query string partially encoded
584
page = (HtmlPage) client.getPage(new URL("http://first?a=b%20c&d=e f"));
585         assertEquals(
586             "http://first?a=b%20c&d=e%20f",
587             page.getWebResponse().getUrl().toExternalForm());
588         
589         // with anchor
590
page = (HtmlPage) client.getPage(new URL("http://first?a=b c#myAnchor"));
591         assertEquals(
592             "http://first?a=b%20c#myAnchor",
593             page.getWebResponse().getUrl().toExternalForm());
594         
595         // with query string containing encoded "&", "=", "+", ",", and "$"
596
page = (HtmlPage) client.getPage(new URL("http://first?a=%26%3D%20%2C%24"));
597         assertEquals(
598             "http://first?a=%26%3D%20%2C%24",
599             page.getWebResponse().getUrl().toExternalForm());
600     }
601
602     /**
603      * Test loading a file page
604      * @throws Exception If something goes wrong.
605      */

606     public void testLoadFilePage() throws Exception {
607
608         // create a real file to read
609
// it could be usefull to have existing files to test in a special location in filesystem.
610
// It will be really needed when we have to test binary files using the file protocol.
611
final String htmlContent = "<html><head><title>foo</title></head><body></body></html>";
612         final File currentDirectory = new File((new File("")).getAbsolutePath());
613         final File tmpFile = File.createTempFile("test", ".html", currentDirectory);
614         tmpFile.deleteOnExit();
615         final String encoding = (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding();
616         FileUtils.writeStringToFile(tmpFile, htmlContent, encoding);
617
618         final URL fileURL = new URL("file://" + tmpFile.getCanonicalPath());
619         
620         final WebClient client = new WebClient();
621         final HtmlPage page = (HtmlPage) client.getPage(fileURL);
622
623         assertEquals(htmlContent, page.getWebResponse().getContentAsString());
624         assertEquals("text/html", page.getWebResponse().getContentType());
625         assertEquals(200, page.getWebResponse().getStatusCode());
626         assertEquals("foo", page.getTitleText());
627     }
628
629     /**
630      * Test loading a file page with xml content.
631      * Regression test for bug 1113487.
632      * @throws Exception If something goes wrong.
633      */

634     public void testLoadFilePageXml() throws Exception {
635         final String xmlContent = "<?xml version='1.0' encoding='UTF-8'?>\n"
636             + "<dataset>\n"
637             + "<table name=\"USER\">\n"
638             + "<column>ID</column>\n"
639             + "<row>\n"
640             + "<value>116517</value>\n"
641             + "</row>\n"
642             + "</table>\n"
643             + "</dataset>";
644         final File currentDirectory = new File((new File("")).getAbsolutePath());
645         final File tmpFile = File.createTempFile("test", ".xml", currentDirectory);
646         tmpFile.deleteOnExit();
647         final String encoding = (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding();
648         FileUtils.writeStringToFile(tmpFile, xmlContent, encoding);
649
650         URL fileURL = new URL("file://" + tmpFile.getCanonicalPath());
651         
652         final WebClient client = new WebClient();
653         final XmlPage page = (XmlPage) client.getPage(fileURL);
654
655         assertEquals(xmlContent, page.getWebResponse().getContentAsString());
656         // "text/xml" or "application/xml", it doesn't matter
657
assertEquals("/xml", StringUtils.substring(page.getWebResponse().getContentType(), -4));
658         assertEquals(200, page.getWebResponse().getStatusCode());
659     }
660
661     /**
662      * Test redirecting with javascript during page load.
663      * @throws Exception If something goes wrong.
664      */

665     public void testRedirectViaJavaScriptDuringInitialPageLoad() throws Exception {
666         final String firstContent = "<html><head><title>First</title><script>"
667             + "location.href='http://second'"
668             + "</script></head><body></body></html>";
669         final String secondContent = "<html><head><title>Second</title></head><body></body></html>";
670
671         final WebClient webClient = new WebClient();
672
673         final MockWebConnection webConnection = new MockWebConnection( webClient );
674         webConnection.setResponse(
675             URL_FIRST, firstContent, 200, "OK", "text/html", Collections.EMPTY_LIST );
676         webConnection.setResponse(
677             URL_SECOND, secondContent, 200, "OK", "text/html", Collections.EMPTY_LIST );
678
679         webClient.setWebConnection( webConnection );
680
681         final URL url = URL_FIRST;
682
683         final HtmlPage page = (HtmlPage)webClient.getPage(url);
684         assertEquals("Second", page.getTitleText());
685     }
686
687
688     /**
689      * Test tabbing where there are no tabbable elements.
690      * @throws Exception If something goes wrong.
691      */

692     public void testKeyboard_NoTabbableElements() throws Exception {
693         final WebClient webClient = new WebClient();
694         final HtmlPage page = getPageForKeyboardTest(webClient, new String[0]);
695         final List collectedAlerts = new ArrayList();
696         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
697
698         assertNull( "original", webClient.getElementWithFocus() );
699         assertNull( "next", page.tabToNextElement() );
700         assertNull( "previous", page.tabToPreviousElement() );
701         assertNull( "accesskey", page.pressAccessKey('a') );
702
703         final List expectedAlerts = Collections.EMPTY_LIST;
704         assertEquals(expectedAlerts, collectedAlerts);
705     }
706
707
708     /**
709      * Test tabbing where there is only one tabbable element.
710      * @throws Exception If something goes wrong.
711      */

712     public void testKeyboard_OneTabbableElement() throws Exception {
713         final WebClient webClient = new WebClient();
714         final List collectedAlerts = new ArrayList();
715         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
716
717         final HtmlPage page = getPageForKeyboardTest(webClient, new String[]{ null });
718         final HtmlElement element = page.getHtmlElementById("submit0");
719
720         assertNull( "original", webClient.getElementWithFocus() );
721         assertNull( "accesskey", page.pressAccessKey('x') );
722
723         assertEquals( "next", element, page.tabToNextElement() );
724         assertEquals( "nextAgain", element, page.tabToNextElement() );
725
726         webClient.getElementWithFocus().blur();
727         assertNull( "original", webClient.getElementWithFocus() );
728
729         assertEquals( "previous", element, page.tabToPreviousElement() );
730         assertEquals( "previousAgain", element, page.tabToPreviousElement() );
731
732         assertEquals( "accesskey", element, page.pressAccessKey('z') );
733
734         final List expectedAlerts = Arrays.asList( new String[]{"focus-0", "blur-0", "focus-0"} );
735         assertEquals(expectedAlerts, collectedAlerts);
736     }
737
738
739     /**
740      * Test pressing an accesskey.
741      * @throws Exception If something goes wrong.
742      */

743     public void testAccessKeys() throws Exception {
744         final WebClient webClient = new WebClient();
745         final List collectedAlerts = new ArrayList();
746         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
747
748         final HtmlPage page = getPageForKeyboardTest(webClient, new String[]{ "1", "2", "3" });
749
750         assertEquals( "submit0", page.pressAccessKey('a').getAttributeValue("name") );
751         assertEquals( "submit2", page.pressAccessKey('c').getAttributeValue("name") );
752         assertEquals( "submit1", page.pressAccessKey('b').getAttributeValue("name") );
753
754         final List expectedAlerts = Arrays.asList( new String[]{
755             "focus-0", "blur-0", "focus-2", "blur-2", "focus-1"
756         } );
757         assertEquals( expectedAlerts, collectedAlerts );
758     }
759
760
761     /**
762      * Test tabbing to the next element.
763      * @throws Exception If something goes wrong.
764      */

765     public void testTabNext() throws Exception {
766         final WebClient webClient = new WebClient();
767         final List collectedAlerts = new ArrayList();
768         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
769
770         final HtmlPage page = getPageForKeyboardTest(webClient, new String[]{ "1", "2", "3" });
771
772         assertEquals( "submit0", page.tabToNextElement().getAttributeValue("name") );
773         assertEquals( "submit1", page.tabToNextElement().getAttributeValue("name") );
774         assertEquals( "submit2", page.tabToNextElement().getAttributeValue("name") );
775
776         final List expectedAlerts = Arrays.asList( new String[]{
777             "focus-0", "blur-0", "focus-1", "blur-1", "focus-2"
778         } );
779         assertEquals( expectedAlerts, collectedAlerts );
780     }
781
782
783     /**
784      * Test tabbing to the previous element.
785      * @throws Exception If something goes wrong.
786      */

787     public void testTabPrevious() throws Exception {
788         final WebClient webClient = new WebClient();
789         final List collectedAlerts = new ArrayList();
790         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
791
792         final HtmlPage page = getPageForKeyboardTest(webClient, new String[]{ "1", "2", "3" });
793
794         assertEquals( "submit2", page.tabToPreviousElement().getAttributeValue("name") );
795         assertEquals( "submit1", page.tabToPreviousElement().getAttributeValue("name") );
796         assertEquals( "submit0", page.tabToPreviousElement().getAttributeValue("name") );
797
798         final List expectedAlerts = Arrays.asList( new String[]{
799             "focus-2", "blur-2", "focus-1", "blur-1", "focus-0"
800         } );
801         assertEquals( expectedAlerts, collectedAlerts );
802     }
803
804
805     /**
806      * Test that a button can be selected via accesskey.
807      * @throws Exception If something goes wrong.
808      */

809     public void testPressAccessKey_Button() throws Exception {
810         final WebClient webClient = new WebClient();
811         final List collectedAlerts = new ArrayList();
812         webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
813
814         final HtmlPage page = getPageForKeyboardTest(webClient, new String[]{ "1", "2", "3" });
815         final HtmlElement button = page.getHtmlElementById("button1");
816
817         final List expectedAlerts = Collections.singletonList("buttonPushed");
818         collectedAlerts.clear();
819
820         button.removeAttribute("disabled");
821         page.pressAccessKey('1');
822
823         assertEquals( expectedAlerts, collectedAlerts );
824     }
825
826
827     /**
828      * Return a loaded page for one of the keyboard tests.
829      * @param webClient the WebClient to load the page from.
830      * @param tabIndexValues The tab index values. One input will be created for each item
831      * in this list.
832      * @return The loaded page.
833      * @throws Exception If something goes wrong.
834      */

835     private HtmlPage getPageForKeyboardTest(
836         final WebClient webClient, final String[] tabIndexValues ) throws Exception {
837
838         final StringBuffer buffer = new StringBuffer();
839         buffer.append(
840             "<html><head><title>First</title></head><body><form name='form1' method='post' onsubmit='return false;'>");
841
842         for( int i=0; i<tabIndexValues.length; i++ ) {
843             buffer.append( "<input type='submit' name='submit");
844             buffer.append(i);
845             buffer.append("' id='submit");
846             buffer.append(i);
847             buffer.append("'");
848             if( tabIndexValues[i] != null ) {
849                 buffer.append(" tabindex='");
850                 buffer.append(tabIndexValues[i]);
851                 buffer.append("'");
852             }
853             buffer.append(" onblur='alert(\"blur-"+i+"\")'");
854             buffer.append(" onfocus='alert(\"focus-"+i+"\")'");
855             buffer.append(" accesskey='"+(char)('a'+i)+"'");
856             buffer.append(">");
857         }
858         buffer.append("<div id='div1'>foo</div>"); // something that isn't tabbable
859

860         // Elements that are tabbable but are disabled
861
buffer.append("<button name='button1' id='button1' disabled onclick='alert(\"buttonPushed\")' ");
862         buffer.append("accesskey='1'>foo</button>");
863
864         buffer.append("</form></body></html>");
865
866         final MockWebConnection webConnection = new MockWebConnection( webClient );
867         webConnection.setResponse(
868             new URL("http://first/"), buffer.toString(), 200, "OK", "text/html", Collections.EMPTY_LIST );
869         webClient.setWebConnection( webConnection );
870
871         final URL url = new URL("http://first/");
872         return (HtmlPage)webClient.getPage(url);
873     }
874
875     /**
876      * Test {@link WebClient#loadWebResponseInto(WebResponse,WebWindow)}
877      * @throws Exception If the test fails.
878      */

879     public void testLoadWebResponseInto() throws Exception {
880         final WebClient webClient = new WebClient();
881         final WebResponse webResponse = new StringWebResponse(
882             "<html><head><title>first</title></head><body></body></html>");
883
884         final Page page = webClient.loadWebResponseInto(
885             webResponse, webClient.getCurrentWindow() );
886         assertInstanceOf( page, HtmlPage.class);
887
888         final HtmlPage htmlPage = (HtmlPage)page;
889         assertEquals("first", htmlPage.getTitleText() );
890     }
891     
892     /**
893      * Verifies that exceptions are thrown on failing status code and the returned page
894      * is still set as the current page in the WebWindow.
895      *
896      * @throws Exception if test fails
897      */

898     public void testGetPageFailingStatusCode() throws Exception {
899         final String firstContent = "<html><head><title>Hello World</title></head><body></body></html>";
900
901         final WebClient webClient = new WebClient();
902
903         final MockWebConnection webConnection = new MockWebConnection(webClient);
904         webConnection.setResponse(
905                 URL_FIRST,
906                 firstContent,
907                 500,
908                 "BOOM",
909                 "text/html",
910                 Collections.EMPTY_LIST);
911         webClient.setWebConnection(webConnection);
912         webClient.setThrowExceptionOnFailingStatusCode(true);
913         webClient.setPrintContentOnFailingStatusCode(false);
914         try {
915             webClient.getPage(URL_FIRST);
916             fail("Should have thrown");
917         }
918         catch (final FailingHttpStatusCodeException e) {
919             assertEquals(e.getStatusCode(), 500);
920             assertEquals(e.getStatusMessage(), "BOOM");
921         }
922         final HtmlPage page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();
923         assertEquals("Hello World", page.getTitleText());
924     }
925
926     /**
927      * Test {@link WebClient#expandUrl(URL,String)} for the case where an anchor name
928      * was specified.
929      * @throws Exception If the test fails.
930      */

931     public void testExpandUrl() throws Exception {
932         assertEquals(
933             "http://first",
934             WebClient.expandUrl(URL_FIRST, "#second").toExternalForm());
935     }
936     
937     /**
938      * @throws Exception If the test fails.
939      */

940     public void testExpandUrlWithFile() throws Exception {
941         final String urlString = "http://host/page.html";
942         final URL url = new URL(urlString);
943         assertEquals(
944             urlString,
945             WebClient.expandUrl(url, "#second").toExternalForm());
946     }
947
948
949     /** Test the accessors for refreshHandler */
950     public void testRefreshHandlerAccessors() {
951         final WebClient webClient = new WebClient();
952         assertInstanceOf( webClient.getRefreshHandler(), ImmediateRefreshHandler.class );
953         
954         final RefreshHandler handler = new ImmediateRefreshHandler() {};
955         webClient.setRefreshHandler( handler );
956         assertSame( handler, webClient.getRefreshHandler() );
957     }
958     
959     /**
960      * Test the script preprocessor
961      * @throws IOException if the test fails
962      */

963     public void testScriptPreProcessor() throws IOException {
964         final WebClient client = new WebClient();
965         final MockWebConnection webConnection = new MockWebConnection( client );
966         final String alertText = "content";
967         final String newAlertText = "newcontent";
968         final String content
969             = "<html><head><title>foo</title><script>"
970             + "<!--\n alert('" + alertText + "');\n// -->"
971             + "</script></head><body>"
972             + "<p>hello world</p>"
973             + "<form name='form1'>"
974             + " <input type='text' name='textfield1' id='textfield1' value='foo' />"
975             + " <input type='text' name='textfield2' id='textfield2'/>"
976             + "</form>"
977             + "</body></html>";
978
979         webConnection.setDefaultResponse( content );
980         client.setWebConnection( webConnection );
981
982         // Test null return from pre processor
983
client.setScriptPreProcessor( new ScriptPreProcessor() {
984             public String preProcess( final HtmlPage htmlPage, final String sourceCode, final String sourceName,
985                                       final HtmlElement htmlElement ) {
986                 return null;
987             }
988         });
989         client.setAlertHandler( new AlertHandler() {
990             public void handleAlert( final Page page, final String message ) {
991                 fail("The pre processor did not remove the javascript");
992             }
993
994         });
995         client.getPage( new URL( "http://www.yahoo.com" ) );
996
997         // Test modify script in pre processor
998
client.setScriptPreProcessor( new ScriptPreProcessor() {
999             public String preProcess( final HtmlPage htmlPage, final String sourceCode, final String sourceName,
1000                                      final HtmlElement htmlElement ) {
1001                final int start = sourceCode.indexOf( alertText );
1002                final int end = start + alertText.length();
1003
1004                return sourceCode.substring( 0, start ) + newAlertText + sourceCode.substring( end );
1005            }
1006        });
1007        client.setAlertHandler( new AlertHandler() {
1008            public void handleAlert( final Page page, final String message ) {
1009                if( !message.equals( newAlertText ) ) {
1010                    fail( "The pre processor did not modify the javascript" );
1011                }
1012            }
1013
1014        });
1015        client.getPage( new URL( "http://www.yahoo.com" ) );
1016    }
1017    
1018    /**
1019     * Test the ScriptPreProcessor's ability to filter out a javascript method
1020     * that is not implemented without affecting the rest of the page.
1021     *
1022     * @throws Exception if the test fails
1023     */

1024    public void testScriptPreProcessor_UnimplementedJavascript() throws Exception {
1025        
1026        final WebClient client = new WebClient();
1027        final MockWebConnection webConnection = new MockWebConnection( client );
1028        final String content = "<html><head><title>foo</title></head><body>"
1029            + "<p>hello world</p>"
1030            + "<script>document.unimplementedFunction();</script>"
1031            + "<script>alert('implemented function');</script>"
1032            + "</body></html>";
1033
1034        webConnection.setDefaultResponse( content );
1035        client.setWebConnection( webConnection );
1036
1037        client.setScriptPreProcessor( new ScriptPreProcessor() {
1038            public String preProcess( final HtmlPage htmlPage, final String sourceCode, final String sourceName,
1039                                      final HtmlElement htmlElement ) {
1040                if (sourceCode.indexOf("unimplementedFunction") > -1) {
1041                    return "";
1042                }
1043                return sourceCode;
1044            }
1045        });
1046        final List alerts = new ArrayList();
1047        client.setAlertHandler( new CollectingAlertHandler(alerts));
1048        client.getPage( new URL( "http://page" ) );
1049        
1050        assertEquals(1, alerts.size());
1051        assertEquals("implemented function", alerts.get(0).toString());
1052    }
1053
1054    /**
1055     * Apparently if the browsers receive a charset that they don't understand, they ignore
1056     * it and assume ISO-8895-1. Ensure we do the same.
1057     * @throws Exception If the test fails.
1058     */

1059    public void testBadCharset() throws Exception {
1060        final String page1Content
1061            = "<html><head><title>foo</title>"
1062            + "</head><body></body></html>";
1063        final WebClient client = new WebClient();
1064
1065        final MockWebConnection webConnection = new MockWebConnection( client );
1066        webConnection.setResponse(URL_FIRST, page1Content, "text/html; charset=garbage");
1067
1068        client.setWebConnection( webConnection );
1069
1070        final Page page = client.getPage(URL_FIRST);
1071        assertInstanceOf(page, HtmlPage.class);
1072    }
1073    
1074    /**
1075     * Colons are legal in the path of a url but {@link WebClient#expandUrl(URL,String)} was
1076     * blowing up on this case. Ensure it's fixed.
1077     * @throws Exception If the test fails.
1078     */

1079    public void testExpandUrlHandlesColonsInRelativeUrl() throws Exception {
1080        final URL newUrl = WebClient.expandUrl( new URL("http://host/foo"), "/bar/blah:de:blah");
1081        assertEquals( "http://host/bar/blah:de:blah", newUrl.toExternalForm() );
1082    }
1083
1084    /**
1085     * Test reuse of a single {@link HtmlPage} object to submit the same form multiple times.
1086     *
1087     * @throws Exception if test fails
1088     */

1089    public void testReusingHtmlPageToSubmitFormMultipleTimes() throws Exception {
1090
1091        final String firstContent = "<html><head><title>First</title></head>" +
1092                                    "<body onload='document.myform.mysubmit.focus()'>" +
1093                                    "<form action='" + URL_SECOND + "' name='myform'>" +
1094                                    "<input type='submit' name='mysubmit'>" +
1095                                    "</form></body></html>";
1096        final String secondContent = "<html><head><title>Second</title></head><body>Second</body></html>";
1097
1098        final WebClient webClient = new WebClient();
1099
1100        final MockWebConnection webConnection = new MockWebConnection(webClient);
1101        webConnection.setResponse(URL_FIRST, firstContent, 200, "OK", "text/html", Collections.EMPTY_LIST);
1102        webConnection.setResponse(URL_SECOND, secondContent, 200, "OK", "text/html", Collections.EMPTY_LIST);
1103
1104        webClient.setWebConnection(webConnection);
1105
1106        final HtmlPage page = (HtmlPage) webClient.getPage(URL_FIRST);
1107        for (int i = 0; i < 1000; i++) {
1108            page.getFormByName("myform").submit();
1109        }
1110    }
1111
1112    /**
1113     * Test the value of window.opener when a link has target="_top"
1114     * @throws Exception if test fails
1115     */

1116    public void testOpenerInFrameset() throws Exception {
1117
1118        final String firstContent = "<html><head><script>alert(window.opener)</script><frameset cols='*'>"
1119                                    + "<frame SRC='" + URL_SECOND + "'>"
1120                                    + "</frameset>"
1121                                    + "</html>";
1122        final String secondContent = "<html><body><a HREF='" + URL_FIRST + "' target='_top'>to top</a></body></html>";
1123
1124        final WebClient webClient = new WebClient();
1125
1126        final MockWebConnection webConnection = new MockWebConnection(webClient);
1127        webConnection.setResponse(URL_FIRST, firstContent);
1128        webConnection.setResponse(URL_SECOND, secondContent);
1129        webClient.setWebConnection(webConnection);
1130        
1131        final List collectedAlerts = new ArrayList();
1132        webClient.setAlertHandler( new CollectingAlertHandler(collectedAlerts) );
1133
1134        final HtmlPage page = (HtmlPage) webClient.getPage(URL_FIRST);
1135        final HtmlPage pageInFrame = (HtmlPage) ((WebWindow) page.getFrames().get(0)).getEnclosedPage();
1136        ((HtmlAnchor) pageInFrame.getAnchors().get(0)).click();
1137
1138        final List expectedAlerts = Arrays.asList( new String[]{
1139            "null", "null"} );
1140        assertEquals( expectedAlerts, collectedAlerts );
1141    }
1142    
1143    /**
1144     * Test setting the NekoHTML logging and parsing flags
1145     *
1146     * @throws Exception if test fails
1147     */

1148    public void testNekoFlagSetters() throws Exception {
1149        assertEquals("Default logging is wrong", false, WebClient.getValidateHtml());
1150        WebClient.setValidateHtml(true);
1151        assertEquals("Logging did not get set", true, WebClient.getValidateHtml());
1152        assertEquals("Default ignore content is wrong", false, WebClient.getIgnoreOutsideContent());
1153        WebClient.setIgnoreOutsideContent(true);
1154        assertEquals("Ignore content did not get set", true, WebClient.getIgnoreOutsideContent());
1155    }
1156    /**
1157     * Unset the static items set in tests here
1158     * @throws Exception if superclass throws
1159     */

1160    protected void tearDown() throws Exception {
1161        super.tearDown();
1162        WebClient.setValidateHtml(false);
1163        WebClient.setIgnoreOutsideContent(false);
1164    }
1165
1166    /**
1167     *
1168     * @throws Exception if an error occurs
1169     */

1170    public void testGuessContentType() throws Exception {
1171        final WebClient webClient = new WebClient();
1172
1173        // test real files with bad file suffix
1174
assertEquals("tiny-png.img", "image/png", webClient.guessContentType(getTestFile("tiny-png.img")));
1175        assertEquals("tiny-jpg.img", "image/jpeg", webClient.guessContentType(getTestFile("tiny-jpg.img")));
1176        assertEquals("tiny-gif.img", "image/gif", webClient.guessContentType(getTestFile("tiny-gif.img")));
1177        
1178        // tests empty files, type should be determined from file suffix
1179
assertEquals("empty.png", "image/png", webClient.guessContentType(getTestFile("empty.png")));
1180        assertEquals("empty.jpg", "image/jpeg", webClient.guessContentType(getTestFile("empty.jpg")));
1181        assertEquals("empty.gif", "image/gif", webClient.guessContentType(getTestFile("empty.gif")));
1182    }
1183
1184
1185    /**
1186     * Gets the file located in testfiles from the file name
1187     * @param fileName the file name
1188     * @return the file
1189     * @throws Exception if a pb occurs
1190     */

1191    private File getTestFile(final String fileName) throws Exception {
1192        final URL url = getClass().getResource("testfiles/" + fileName);
1193        if( url == null ) {
1194            throw new FileNotFoundException(fileName);
1195        }
1196        final File file = new File(new URI(url.toString()));
1197        
1198        return file;
1199    }
1200}
1201
1202
Popular Tags