Java tutorial
/* * Copyright (c) 2002-2016 Gargoyle Software Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gargoylesoftware.htmlunit; import static com.gargoylesoftware.htmlunit.BrowserVersion.INTERNET_EXPLORER_11; import static java.util.Arrays.asList; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.http.HttpStatus; import org.junit.Test; import org.junit.runner.RunWith; import org.w3c.css.sac.CSSException; import org.w3c.css.sac.CSSParseException; import org.w3c.css.sac.ErrorHandler; import com.gargoylesoftware.base.testing.EventCatcher; import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts; import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlButtonInput; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLStyleElement; import com.gargoylesoftware.htmlunit.util.NameValuePair; import com.gargoylesoftware.htmlunit.util.UrlUtils; import com.gargoylesoftware.htmlunit.xml.XmlPage; /** * Tests for {@link WebClient}. * * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author <a href="mailto:cse@dynabean.de">Christian Sell</a> * @author <a href="mailto:bcurren@esomnie.com">Ben Curren</a> * @author Marc Guillemot * @author David D. Kilzer * @author Chris Erskine * @author Hans Donner * @author Paul King * @author Ahmed Ashour * @author Daniel Gredler * @author Sudhan Moghe * @author Ronald Brill * @author Carsten Steul */ @RunWith(BrowserRunner.class) public class WebClientTest extends SimpleWebTestCase { /** * Test the situation where credentials are required but they haven't been specified. * * @throws Exception if something goes wrong */ @Test public void credentialProvider_NoCredentials() throws Exception { final String htmlContent = "<html><head><title>foo</title></head><body>\n" + "No access</body></html>"; final WebClient client = getWebClient(); client.getOptions().setPrintContentOnFailingStatusCode(false); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(htmlContent, 401, "Credentials missing or just plain wrong", "text/plain"); client.setWebConnection(webConnection); try { client.getPage(new WebRequest(getDefaultUrl(), HttpMethod.POST)); fail("Expected FailingHttpStatusCodeException"); } catch (final FailingHttpStatusCodeException e) { assertEquals(401, e.getStatusCode()); } } /** * Test that the {@link WebWindowEvent#CHANGE} window event gets fired at the * appropriate time. * @throws Exception if something goes wrong */ @Test public void testHtmlWindowEvents_changed() throws Exception { final String htmlContent = "<html><head><title>foo</title></head><body>\n" + "<a href='http://www.foo2.com' id='a2'>link to foo2</a>\n" + "</body></html>"; final WebClient client = getWebClient(); final EventCatcher eventCatcher = new EventCatcher(); eventCatcher.listenTo(client); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(htmlContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(getDefaultUrl()); final HtmlAnchor anchor = firstPage.getHtmlElementById("a2"); final List<WebWindowEvent> firstExpectedEvents = Arrays.asList(new WebWindowEvent[] { new WebWindowEvent(client.getCurrentWindow(), WebWindowEvent.CHANGE, null, firstPage) }); assertEquals(firstExpectedEvents, eventCatcher.getEvents()); eventCatcher.clear(); final HtmlPage secondPage = anchor.click(); final List<WebWindowEvent> secondExpectedEvents = Arrays.asList(new WebWindowEvent[] { new WebWindowEvent(client.getCurrentWindow(), WebWindowEvent.CHANGE, firstPage, secondPage) }); assertEquals(secondExpectedEvents, eventCatcher.getEvents()); } /** * Test that the {@link WebWindowEvent#OPEN} window event gets fired at * the appropriate time. * @throws Exception if something goes wrong */ @Test public void testHtmlWindowEvents_opened() throws Exception { final String page1Content = "<html><head><title>foo</title>\n" + "<script>window.open('" + URL_SECOND + "', 'myNewWindow')</script>\n" + "</head><body>\n" + "<a href='http://www.foo2.com' id='a2'>link to foo2</a>\n" + "</body></html>"; final String page2Content = "<html><head><title>foo</title></head><body></body></html>"; final WebClient client = getWebClient(); final EventCatcher eventCatcher = new EventCatcher(); eventCatcher.listenTo(client); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, page1Content); webConnection.setResponse(URL_SECOND, page2Content); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); assertEquals("foo", firstPage.getTitleText()); final WebWindow firstWindow = client.getCurrentWindow(); final WebWindow secondWindow = client.getWebWindowByName("myNewWindow"); final List<WebWindowEvent> expectedEvents = Arrays .asList(new WebWindowEvent[] { new WebWindowEvent(secondWindow, WebWindowEvent.OPEN, null, null), new WebWindowEvent(secondWindow, WebWindowEvent.CHANGE, null, secondWindow.getEnclosedPage()), new WebWindowEvent(firstWindow, WebWindowEvent.CHANGE, null, firstPage), }); assertEquals(expectedEvents, eventCatcher.getEvents()); } /** * Test that the {@link WebWindowEvent#CLOSE} window event gets fired at * the appropriate time. * @throws Exception if something goes wrong */ @Test public void testHtmlWindowEvents_closedFromFrame() throws Exception { final String firstContent = "<html><head><title>first</title></head><body>\n" + "<iframe src='" + URL_THIRD + "' id='frame1'></iframe>\n" + "<a href='" + URL_SECOND + "' id='a2'>link to foo2</a>\n" + "</body></html>"; final String secondContent = "<html><head><title>second</title></head><body></body></html>"; final String thirdContent = "<html><head><title>third</title></head><body></body></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); webConnection.setResponse(URL_THIRD, thirdContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); assertEquals("first", firstPage.getTitleText()); final EventCatcher eventCatcher = new EventCatcher(); eventCatcher.listenTo(client); final HtmlInlineFrame frame = firstPage.getHtmlElementById("frame1"); final HtmlPage thirdPage = (HtmlPage) frame.getEnclosedPage(); // Load the second page final HtmlAnchor anchor = firstPage.getHtmlElementById("a2"); final HtmlPage secondPage = anchor.click(); assertEquals("second", secondPage.getTitleText()); final WebWindow firstWindow = client.getCurrentWindow(); final List<WebWindowEvent> expectedEvents = Arrays.asList(new WebWindowEvent[] { new WebWindowEvent(frame.getEnclosedWindow(), WebWindowEvent.CLOSE, thirdPage, null), new WebWindowEvent(firstWindow, WebWindowEvent.CHANGE, firstPage, secondPage), }); assertEquals(expectedEvents.get(0), eventCatcher.getEvents().get(0)); assertEquals(expectedEvents, eventCatcher.getEvents()); } /** * Test a 301 redirection code where the original request was a GET. * @throws Exception if something goes wrong */ @Test public void redirection301_MovedPermanently_GetMethod() throws Exception { final int statusCode = 301; final HttpMethod initialRequestMethod = HttpMethod.GET; final HttpMethod expectedRedirectedRequestMethod = HttpMethod.GET; doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod); } /** * Common utility for GET after POST redirection on same URLs * @param statusCode the code to return from the initial request * @throws Exception if the test fails */ private void doTestRedirectionSameUrlAfterPost(final int statusCode) throws Exception { final String firstContent = "<html><head><title>First</title></head><body></body></html>"; final String secondContent = "<html><head><title>Second</title></head><body></body></html>"; final WebClient webClient = getWebClient(); final List<NameValuePair> headers = Collections .singletonList(new NameValuePair("Location", URL_FIRST.toExternalForm())); // builds a webconnection that first sends a redirect and then a "normal" response for // the same requested URL final MockWebConnection webConnection = new MockWebConnection() { private int count_ = 0; @Override public WebResponse getResponse(final WebRequest webRequest) throws IOException { ++count_; if (count_ == 1) { final WebResponse response = super.getResponse(webRequest); setResponse(webRequest.getUrl(), secondContent); return response; } return super.getResponse(webRequest); } }; webConnection.setResponse(URL_FIRST, firstContent, statusCode, "Some error", "text/html", headers); webClient.setWebConnection(webConnection); final HtmlPage page = webClient.getPage(new WebRequest(URL_FIRST, HttpMethod.POST)); final WebResponse webResponse = page.getWebResponse(); // A redirect should have happened assertEquals(200, webResponse.getStatusCode()); assertEquals(URL_FIRST, webResponse.getWebRequest().getUrl()); assertEquals("Second", page.getTitleText()); assertSame(HttpMethod.GET, webResponse.getWebRequest().getHttpMethod()); } /** * From the HTTP spec: If the 301 status code is received in response * to a request other than GET or HEAD, the user agent MUST NOT automatically * redirect the request unless it can be confirmed by the user, since this * might change the conditions under which the request was issued. * BUT Firefox follows the redirection * @throws Exception if something goes wrong */ @Test public void redirection301_MovedPermanently_PostMethod() throws Exception { doTestRedirection(301, HttpMethod.POST, HttpMethod.GET); } /** * @throws Exception if the test fails */ @Test public void redirection301_MovedPermanently_PostMethod2() throws Exception { doTestRedirectionSameUrlAfterPost(301); } /** * From the HTTP spec: Note: RFC 1945 and RFC 2068 specify that the client * is not allowed to change the method on the redirected request. However, * most existing user agent implementations treat 302 as if it were a 303 * response, performing a GET on the Location field-value regardless * of the original request method. The status codes 303 and 307 have * been added for servers that wish to make unambiguously clear which * kind of reaction is expected of the client. * @throws Exception if something goes wrong */ @Test public void redirection302_MovedTemporarily_PostMethod() throws Exception { doTestRedirection(302, HttpMethod.POST, HttpMethod.GET); } /** * @throws Exception if the test fails */ @Test public void redirection302_MovedTemporarily_PostMethod2() throws Exception { doTestRedirectionSameUrlAfterPost(302); } /** * Test a 302 redirection code. * @throws Exception if something goes wrong */ @Test public void redirection302_MovedTemporarily_GetMethod() throws Exception { final int statusCode = 302; final HttpMethod initialRequestMethod = HttpMethod.GET; final HttpMethod expectedRedirectedRequestMethod = HttpMethod.GET; doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod); } /** * Test a 302 redirection code with "," in URL parameters. * @throws Exception if something goes wrong */ @Test public void redirection302_MovedTemporarily_CommaInParameters() throws Exception { doTestRedirection(302, HttpMethod.GET, HttpMethod.GET, URL_SECOND + "/foo.html?foo1=abc&foo2=1,2,3,4"); } /** * Tests a 303 redirection code. This should be the same as a 302. * @throws Exception if something goes wrong */ @Test public void redirection303_SeeOther_GetMethod() throws Exception { final int statusCode = 303; final HttpMethod initialRequestMethod = HttpMethod.GET; final HttpMethod expectedRedirectedRequestMethod = HttpMethod.GET; doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod); } /** * Tests a 303 redirection code - this should be the same as a 302. * @throws Exception if something goes wrong */ @Test public void redirection303_SeeOther_PostMethod() throws Exception { doTestRedirection(303, HttpMethod.POST, HttpMethod.GET); } /** * @throws Exception if something goes wrong */ @Test public void redirection303_SeeOther_PostMethod2() throws Exception { doTestRedirectionSameUrlAfterPost(303); } /** * Tests a 307 redirection code. * @throws Exception if something goes wrong */ @Test public void redirection307_TemporaryRedirect_GetMethod() throws Exception { final int statusCode = 307; final HttpMethod initialRequestMethod = HttpMethod.GET; final HttpMethod expectedRedirectedRequestMethod = HttpMethod.GET; doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod); } /** * Tests a 307 redirection code. * @throws Exception if something goes wrong */ @Test public void redirection307_TemporaryRedirect_PostMethod() throws Exception { final int statusCode = 307; final HttpMethod initialRequestMethod = HttpMethod.POST; final HttpMethod expectedRedirectedRequestMethod = HttpMethod.POST; doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod); } /** * Basic logic for all the redirection tests. * * @param statusCode the code to return from the initial request * @param initialRequestMethod the initial request * @param expectedRedirectedRequestMethod the submit method of the second (redirected) request * If a redirect is not expected to happen then this must be null * @throws Exception if the test fails */ private void doTestRedirection(final int statusCode, final HttpMethod initialRequestMethod, final HttpMethod expectedRedirectedRequestMethod) throws Exception { doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod, URL_SECOND.toExternalForm()); } /** * Basic logic for all the redirection tests. * * @param statusCode the code to return from the initial request * @param initialRequestMethod the initial request * @param expectedRedirectedRequestMethod the submit method of the second (redirected) request * If a redirect is not expected to happen then this must be null * @param newLocation the Location set in the redirection header * @throws Exception if the test fails */ private void doTestRedirection(final int statusCode, final HttpMethod initialRequestMethod, final HttpMethod expectedRedirectedRequestMethod, final String newLocation) throws Exception { doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod, newLocation, false); doTestRedirection(statusCode, initialRequestMethod, expectedRedirectedRequestMethod, newLocation, true); } /** * Browsers allow many redirections to the same URL before to stop redirections. * See Bug 1619765 and feature request 1472343. * @throws Exception if the test fails */ @Test public void redirectionSameURL() throws Exception { final HtmlPage page1 = getPageWithRedirectionsSameURL(1); assertEquals("Second", page1.getTitleText()); try { getPageWithRedirectionsSameURL(30); } catch (final Exception e) { assertTrue(e.getMessage(), e.getMessage().contains("Too much redirect")); } } private HtmlPage getPageWithRedirectionsSameURL(final int nbRedirections) throws Exception { final String firstContent = "<html><head><title>First</title></head><body></body></html>"; final String secondContent = "<html><head><title>Second</title></head><body></body></html>"; final WebClient webClient = getWebClient(); final URL url = URL_FIRST; final List<NameValuePair> headers = Collections .singletonList(new NameValuePair("Location", URL_FIRST.toExternalForm())); final MockWebConnection webConnection = new MockWebConnection() { private int count_ = 0; @Override public WebResponse getResponse(final WebRequest webRequest) throws IOException { ++count_; if (count_ < nbRedirections) { setResponse(url, firstContent, 302, "Redirect needed " + count_, "text/html", headers); return super.getResponse(webRequest); } else if (count_ == nbRedirections) { final WebResponse response = super.getResponse(webRequest); setResponse(webRequest.getUrl(), secondContent); return response; } else { return super.getResponse(webRequest); } } }; webConnection.setResponse(url, firstContent, 302, "Redirect needed", "text/html", headers); webClient.setWebConnection(webConnection); webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); return webClient.getPage(url); } /** * Verifies that any additional headers in the original {@link WebRequest} instance are kept * and sent to the redirect location. Specifically, the "Referer" header set in various locations was * being lost during redirects (see bug 1987911). * @throws Exception if an error occurs */ @Test public void redirection_AdditionalHeadersMaintained() throws Exception { redirection_AdditionalHeadersMaintained(301); redirection_AdditionalHeadersMaintained(302); } private void redirection_AdditionalHeadersMaintained(final int statusCode) throws Exception { final WebClient client = getWebClient(); final MockWebConnection conn = new MockWebConnection(); client.setWebConnection(conn); final List<NameValuePair> headers = asList(new NameValuePair("Location", URL_SECOND.toString())); conn.setResponse(URL_FIRST, "", statusCode, "", "text/html", headers); conn.setResponse(URL_SECOND, "<html><body>abc</body></html>"); final WebRequest request = new WebRequest(URL_FIRST); request.setAdditionalHeader("foo", "bar"); client.getPage(request); assertEquals(URL_SECOND, conn.getLastWebRequest().getUrl()); assertEquals("bar", conn.getLastAdditionalHeaders().get("foo")); } /** * Basic logic for all the redirection tests. * * @param statusCode the code to return from the initial request * @param initialRequestMethod the initial request * @param expectedRedirectedRequestMethod the submit method of the second (redirected) request * If a redirect is not expected to happen then this must be null * @param newLocation the Location set in the redirection header * @param useProxy indicates if the test should be performed with a proxy * @throws Exception if the test fails */ private void doTestRedirection(final int statusCode, final HttpMethod initialRequestMethod, final HttpMethod expectedRedirectedRequestMethod, final String newLocation, final boolean useProxy) throws Exception { final String firstContent = "<html><head><title>First</title></head><body></body></html>"; final String secondContent = "<html><head><title>Second</title></head><body></body></html>"; final WebClient webClient; final String proxyHost; final int proxyPort; if (useProxy) { proxyHost = "someHost"; proxyPort = 12233345; webClient = new WebClient(getBrowserVersion(), proxyHost, proxyPort); } else { proxyHost = null; proxyPort = 0; webClient = getWebClient(); } webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); webClient.getOptions().setPrintContentOnFailingStatusCode(false); final List<NameValuePair> headers = Collections.singletonList(new NameValuePair("Location", newLocation)); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent, statusCode, "Some error", "text/html", headers); webConnection.setResponse(new URL(newLocation), secondContent); webClient.setWebConnection(webConnection); final URL url = URL_FIRST; HtmlPage page; WebResponse webResponse; // // Second time redirection is turned on (default setting) // page = webClient.getPage(new WebRequest(url, initialRequestMethod)); webResponse = page.getWebResponse(); if (expectedRedirectedRequestMethod == null) { // No redirect should have happened assertEquals(statusCode, webResponse.getStatusCode()); assertEquals(initialRequestMethod, webConnection.getLastMethod()); } else { // A redirect should have happened assertEquals(HttpStatus.SC_OK, webResponse.getStatusCode()); assertEquals(newLocation, webResponse.getWebRequest().getUrl()); assertEquals("Second", page.getTitleText()); assertEquals(expectedRedirectedRequestMethod, webConnection.getLastMethod()); } assertEquals(proxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(proxyPort, webConnection.getLastWebRequest().getProxyPort()); // // Second time redirection is turned off // webClient.getOptions().setRedirectEnabled(false); page = webClient.getPage(new WebRequest(url, initialRequestMethod)); webResponse = page.getWebResponse(); assertEquals(statusCode, webResponse.getStatusCode()); assertEquals(initialRequestMethod, webConnection.getLastMethod()); assertEquals(proxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(proxyPort, webConnection.getLastWebRequest().getProxyPort()); webClient.close(); } /** * Test passing in a null page creator. */ @Test public void setPageCreator_null() { final WebClient webClient = getWebClient(); try { webClient.setPageCreator(null); fail("Expected NullPointerException"); } catch (final NullPointerException e) { // expected path } } /** * Test {@link WebClient#setPageCreator(PageCreator)}. * @throws Exception if something goes wrong */ @Test public void setPageCreator() throws Exception { final String page1Content = "<html><head><title>foo</title>\n" + "</head><body>\n" + "<a href='http://www.foo2.com' id='a2'>link to foo2</a>\n" + "</body></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, page1Content); client.setWebConnection(webConnection); final List<Page> collectedPageCreationItems = new ArrayList<>(); client.setPageCreator(new CollectingPageCreator(collectedPageCreationItems)); final Page page = client.getPage(URL_FIRST); assertTrue("instanceof TextPage", page instanceof TextPage); final List<Page> expectedPageCreationItems = Arrays.asList(new Page[] { page }); assertEquals(expectedPageCreationItems, collectedPageCreationItems); } /** A PageCreator that collects data. */ private static class CollectingPageCreator implements PageCreator { private final List<Page> collectedPages_; /** * Creates an instance. * @param list the list that will contain the data */ CollectingPageCreator(final List<Page> list) { collectedPages_ = list; } /** * Creates a page. * @param webResponse the web response * @param webWindow the web window * @return the new page * @throws IOException if an IO problem occurs */ @Override public Page createPage(final WebResponse webResponse, final WebWindow webWindow) throws IOException { final Page page = new TextPage(webResponse, webWindow); webWindow.setEnclosedPage(page); collectedPages_.add(page); return page; } } /** * Tests loading a page with POST parameters. * @throws Exception if something goes wrong */ @Test public void loadPage_PostWithParameters() throws Exception { final String htmlContent = "<html><head><title>foo</title></head><body>\n" + "</body></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(htmlContent); client.setWebConnection(webConnection); final String urlString = "http://first?a=b"; final URL url = new URL(urlString); final HtmlPage page = client.getPage(new WebRequest(url, HttpMethod.POST)); assertEquals("http://first/?a=b", page.getUrl()); } /** * Test that double / in query string are not changed. * @throws Exception if something goes wrong */ @Test public void loadPage_SlashesInQueryString() throws Exception { final String htmlContent = "<html><head><title>foo</title></head>\n" + "<body><a href='foo.html?id=UYIUYTY//YTYUY..F'>to page 2</a>\n" + "</body></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(htmlContent); client.setWebConnection(webConnection); final HtmlPage page = client.getPage(URL_FIRST); final Page page2 = page.getAnchors().get(0).click(); final URL url2 = new URL(URL_FIRST, "foo.html?id=UYIUYTY//YTYUY..F"); assertEquals(url2.toExternalForm(), page2.getUrl()); } /** * Test loading a file page. * * @throws Exception if something goes wrong */ @Test public void loadFilePage() throws Exception { // Create a real file to read. // It could be useful to have existing files to test in a special location in filesystem. // It will be really needed when we have to test binary files using the file protocol. final String htmlContent = "<html><head><title>foo</title></head><body></body></html>"; final File currentDirectory = new File((new File("")).getAbsolutePath()); final File tmpFile = File.createTempFile("test", ".html", currentDirectory); tmpFile.deleteOnExit(); final String encoding = (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding(); FileUtils.writeStringToFile(tmpFile, htmlContent, encoding); // Test a normal file URL. final WebClient client = getWebClient(); final URL url = new URL("file://" + tmpFile.getCanonicalPath()); final HtmlPage page = client.getPage(url); assertEquals(htmlContent, page.getWebResponse().getContentAsString()); assertEquals("text/html", page.getWebResponse().getContentType()); assertEquals(200, page.getWebResponse().getStatusCode()); assertEquals("foo", page.getTitleText()); // Test a file URL with a query portion (needs to work for Dojo, for example). final URL url2 = new URL(url + "?with=query"); final HtmlPage page2 = client.getPage(url2); assertEquals(htmlContent, page2.getWebResponse().getContentAsString()); assertEquals("text/html", page2.getWebResponse().getContentType()); assertEquals(200, page2.getWebResponse().getStatusCode()); assertEquals("foo", page2.getTitleText()); // Test a file URL with a ref portion (needs to work for Dojo, for example). final URL url3 = new URL(url + "#reference"); final HtmlPage page3 = client.getPage(url3); assertEquals(htmlContent, page3.getWebResponse().getContentAsString()); assertEquals("text/html", page3.getWebResponse().getContentType()); assertEquals(200, page3.getWebResponse().getStatusCode()); assertEquals("foo", page3.getTitleText()); } /** * Test loading a file page with non ascii names. * * @throws Exception if something goes wrong */ @Test public void loadFilePageEncoded() throws Exception { final WebClient client = getWebClient(); final String whitespaceFilename = "white space.txt"; String path = getClass().getClassLoader().getResource(whitespaceFilename).toExternalForm(); File file = new File(new URI(path)); assertTrue(file.exists()); String url = "file://" + file.getCanonicalPath(); Page page = client.getPage(url); assertEquals("the name of this file contains a blank", page.getWebResponse().getContentAsString()); // encode the whitespace url = "file://" + file.getCanonicalPath().replace(" ", "%20"); page = client.getPage(url); assertEquals("the name of this file contains a blank", page.getWebResponse().getContentAsString()); final String unicodeFilename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt"; path = getClass().getClassLoader().getResource(unicodeFilename).toExternalForm(); file = new File(new URI(path)); assertTrue(file.exists()); url = "file://" + file.getCanonicalPath(); page = client.getPage(url); assertEquals("", page.getWebResponse().getContentAsString()); url = url.replace(unicodeFilename, "%e6%aa%94%e6%a1%88%ed%8c%8c%ec%9d%bc%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%d9%85%d9%84%d9%81.txt"); page = client.getPage(url); assertEquals("", page.getWebResponse().getContentAsString()); } /** * Test loading a file page with XML content. Regression test for bug 1113487. * * @throws Exception if something goes wrong */ @Test public void loadFilePageXml() throws Exception { final String xmlContent = "<?xml version='1.0' encoding='UTF-8'?>\n" + "<dataset>\n" + "<table name=\"USER\">\n" + "<column>ID</column>\n" + "<row>\n" + "<value>116517</value>\n" + "</row>\n" + "</table>\n" + "</dataset>"; final File currentDirectory = new File((new File("")).getAbsolutePath()); final File tmpFile = File.createTempFile("test", ".xml", currentDirectory); tmpFile.deleteOnExit(); final String encoding = (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding(); FileUtils.writeStringToFile(tmpFile, xmlContent, encoding); final URL fileURL = new URL("file://" + tmpFile.getCanonicalPath()); final WebClient client = getWebClient(); final XmlPage page = (XmlPage) client.getPage(fileURL); assertEquals(xmlContent, page.getWebResponse().getContentAsString()); // "text/xml" or "application/xml", it doesn't matter assertEquals("/xml", StringUtils.substring(page.getWebResponse().getContentType(), -4)); assertEquals(200, page.getWebResponse().getStatusCode()); } /** * Test redirecting with JavaScript during page load. * @throws Exception if something goes wrong */ @Test public void redirectViaJavaScriptDuringInitialPageLoad() throws Exception { final String firstContent = "<html><head><title>First</title><script>\n" + "location.href='" + URL_SECOND + "'\n" + "</script></head><body></body></html>"; final String secondContent = "<html><head><title>Second</title></head><body></body></html>"; final WebClient webClient = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); webClient.setWebConnection(webConnection); final URL url = URL_FIRST; final HtmlPage page = webClient.getPage(url); assertEquals("Second", page.getTitleText()); } /** * Test tabbing where there are no tabbable elements. * @throws Exception if something goes wrong */ @Test public void testKeyboard_NoTabbableElements() throws Exception { final WebClient webClient = getWebClient(); final HtmlPage page = getPageForKeyboardTest(webClient, new String[0]); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); DomElement focus = page.getFocusedElement(); assertTrue("original", (focus == null) || (focus == page.getDocumentElement()) || (focus == page.getBody())); focus = page.tabToPreviousElement(); assertNull("previous", focus); focus = page.tabToNextElement(); assertNull("next", focus); focus = page.pressAccessKey('a'); assertNull("accesskey", focus); final String[] expectedAlerts = {}; assertEquals(expectedAlerts, collectedAlerts); } /** * Test tabbing where there is only one tabbable element. * @throws Exception if something goes wrong */ @Test public void testKeyboard_OneTabbableElement() throws Exception { final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = getPageForKeyboardTest(webClient, new String[] { null }); final HtmlElement element = page.getHtmlElementById("submit0"); final DomElement focus = page.getFocusedElement(); assertTrue("original", (focus == null) || (focus == page.getDocumentElement()) || (focus == page.getBody())); final DomElement accessKey = page.pressAccessKey('x'); assertEquals("accesskey", focus, accessKey); assertEquals("next", element, page.tabToNextElement()); assertEquals("nextAgain", element, page.tabToNextElement()); page.getFocusedElement().blur(); assertNull("original", page.getFocusedElement()); assertEquals("previous", element, page.tabToPreviousElement()); assertEquals("previousAgain", element, page.tabToPreviousElement()); assertEquals("accesskey", element, page.pressAccessKey('z')); final String[] expectedAlerts = { "focus-0", "blur-0", "focus-0" }; assertEquals(expectedAlerts, collectedAlerts); } /** * Test pressing an accesskey. * @throws Exception if something goes wrong */ @Test public void testAccessKeys() throws Exception { final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = getPageForKeyboardTest(webClient, new String[] { "1", "2", "3" }); assertEquals("submit0", page.pressAccessKey('a').getAttribute("name")); assertEquals("submit2", page.pressAccessKey('c').getAttribute("name")); assertEquals("submit1", page.pressAccessKey('b').getAttribute("name")); final String[] expectedAlerts = { "focus-0", "blur-0", "focus-2", "blur-2", "focus-1" }; assertEquals(expectedAlerts, collectedAlerts); } /** * Test tabbing to the next element. * @throws Exception if something goes wrong */ @Test public void tabNext() throws Exception { final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = getPageForKeyboardTest(webClient, new String[] { "1", "2", "3" }); assertEquals("submit0", page.tabToNextElement().getAttribute("name")); assertEquals("submit1", page.tabToNextElement().getAttribute("name")); assertEquals("submit2", page.tabToNextElement().getAttribute("name")); final String[] expectedAlerts = { "focus-0", "blur-0", "focus-1", "blur-1", "focus-2" }; assertEquals(expectedAlerts, collectedAlerts); } /** * Test tabbing to the previous element. * @throws Exception if something goes wrong */ @Test public void tabPrevious() throws Exception { final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = getPageForKeyboardTest(webClient, new String[] { "1", "2", "3" }); assertEquals("submit2", page.tabToPreviousElement().getAttribute("name")); assertEquals("submit1", page.tabToPreviousElement().getAttribute("name")); assertEquals("submit0", page.tabToPreviousElement().getAttribute("name")); final String[] expectedAlerts = { "focus-2", "blur-2", "focus-1", "blur-1", "focus-0" }; assertEquals(expectedAlerts, collectedAlerts); } /** * Test that a button can be selected via accesskey. * @throws Exception if something goes wrong */ @Test public void testPressAccessKey_Button() throws Exception { final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = getPageForKeyboardTest(webClient, new String[] { "1", "2", "3" }); final HtmlElement button = page.getHtmlElementById("button1"); final String[] expectedAlerts = { "buttonPushed" }; collectedAlerts.clear(); button.removeAttribute("disabled"); page.pressAccessKey('1'); assertEquals(expectedAlerts, collectedAlerts); } /** * Returns a loaded page for one of the keyboard tests. * @param webClient the WebClient to load the page from * @param tabIndexValues the tab index values; one input will be created for each item * in this list * @return the loaded page * @throws Exception if something goes wrong */ private HtmlPage getPageForKeyboardTest(final WebClient webClient, final String[] tabIndexValues) throws Exception { final StringBuilder buffer = new StringBuilder(); buffer.append("<html><head><title>First</title></head><body>") .append("<form name='form1' method='post' onsubmit='return false;'>"); for (int i = 0; i < tabIndexValues.length; i++) { buffer.append("<input type='submit' name='submit"); buffer.append(i); buffer.append("' id='submit"); buffer.append(i); buffer.append("'"); if (tabIndexValues[i] != null) { buffer.append(" tabindex='"); buffer.append(tabIndexValues[i]); buffer.append("'"); } buffer.append(" onblur='alert(\"blur-" + i + "\")'"); buffer.append(" onfocus='alert(\"focus-" + i + "\")'"); buffer.append(" accesskey='" + (char) ('a' + i) + "'"); buffer.append(">\n"); } buffer.append("<div id='div1'>foo</div>\n"); // something that isn't tabbable // Elements that are tabbable but are disabled buffer.append("<button name='button1' id='button1' disabled onclick='alert(\"buttonPushed\")' "); buffer.append("accesskey='1'>foo</button>\n"); buffer.append("</form></body></html>"); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, buffer.toString()); webClient.setWebConnection(webConnection); return webClient.getPage(URL_FIRST); } /** * Test {@link WebClient#loadWebResponseInto(WebResponse,WebWindow)}. * @throws Exception if the test fails */ @Test public void loadWebResponseInto() throws Exception { final WebClient webClient = getWebClient(); final WebResponse webResponse = new StringWebResponse( "<html><head><title>first</title></head><body></body></html>", getDefaultUrl()); final Page page = webClient.loadWebResponseInto(webResponse, webClient.getCurrentWindow()); assertTrue(HtmlPage.class.isInstance(page)); final HtmlPage htmlPage = (HtmlPage) page; assertEquals("first", htmlPage.getTitleText()); } /** * Verifies that exceptions are thrown on failing status code and the returned page * is still set as the current page in the WebWindow. * * @throws Exception if test fails */ @Test public void testGetPageFailingStatusCode() throws Exception { final String firstContent = "<html><head><title>Hello World</title></head><body></body></html>"; final WebClient webClient = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); final List<NameValuePair> emptyList = Collections.emptyList(); webConnection.setResponse(URL_FIRST, firstContent, 500, "BOOM", "text/html", emptyList); webClient.setWebConnection(webConnection); webClient.getOptions().setThrowExceptionOnFailingStatusCode(true); webClient.getOptions().setPrintContentOnFailingStatusCode(false); try { webClient.getPage(URL_FIRST); fail("Should have thrown"); } catch (final FailingHttpStatusCodeException e) { assertEquals(e.getStatusCode(), 500); assertEquals(e.getStatusMessage(), "BOOM"); assertEquals(firstContent, e.getResponse().getContentAsString()); } final HtmlPage page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage(); assertEquals("Hello World", page.getTitleText()); } /** * @throws Exception if the test fails */ @Test public void testProxyConfig() throws Exception { // Create the client. final String defaultProxyHost = "defaultProxyHost"; final int defaultProxyPort = 777; try (final WebClient webClient = new WebClient(getBrowserVersion(), defaultProxyHost, defaultProxyPort)) { // Configure the mock web connection. final String html = "<html><head><title>Hello World</title></head><body></body></html>"; final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, html); webClient.setWebConnection(webConnection); // Make sure the default proxy settings are used. webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort, webConnection.getLastWebRequest().getProxyPort()); // Change the webclient default proxy settings. final String defaultProxyHost2 = "defaultProxyHost2"; final int defaultProxyPort2 = 532; webClient.getOptions().getProxyConfig().setProxyHost(defaultProxyHost2); webClient.getOptions().getProxyConfig().setProxyPort(defaultProxyPort2); // Make sure the new default proxy settings are used. webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost2, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort2, webConnection.getLastWebRequest().getProxyPort()); // Make sure the custom proxy settings are used. final String customProxyHost = "customProxyHost"; final int customProxyPort = 1000; final WebRequest request = new WebRequest(URL_FIRST); request.setProxyHost(customProxyHost); request.setProxyPort(customProxyPort); webClient.getPage(request); assertEquals(customProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(customProxyPort, webConnection.getLastWebRequest().getProxyPort()); // Make sure the proxy bypass works with default proxy settings. webClient.getOptions().getProxyConfig().addHostsToProxyBypass(URL_FIRST.getHost()); webClient.getPage(URL_FIRST); assertEquals(null, webConnection.getLastWebRequest().getProxyHost()); assertEquals(0, webConnection.getLastWebRequest().getProxyPort()); // Make sure the proxy bypass doesn't work with custom proxy settings. webClient.getPage(request); assertEquals(customProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(customProxyPort, webConnection.getLastWebRequest().getProxyPort()); // Make sure we can remove proxy bypass filters. webClient.getOptions().getProxyConfig().removeHostsFromProxyBypass(URL_FIRST.getHost()); webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost2, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort2, webConnection.getLastWebRequest().getProxyPort()); } } /** * Regression test for http://sourceforge.net/p/htmlunit/bugs/431/. * @throws Exception if an error occurs */ @Test public void testProxyConfigWithRedirect() throws Exception { final String defaultProxyHost = "defaultProxyHost"; final int defaultProxyPort = 777; final String html = "<html><head><title>Hello World</title></head><body></body></html>"; try (final WebClient webClient = new WebClient(getBrowserVersion(), defaultProxyHost, defaultProxyPort)) { webClient.getOptions().getProxyConfig().addHostsToProxyBypass("hostToByPass"); final String location2 = "http://hostToByPass/foo.html"; final List<NameValuePair> headers = Collections.singletonList(new NameValuePair("Location", location2)); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, html, 302, "Some error", "text/html", headers); webConnection.setResponse(new URL(location2), "<html><head><title>2nd page</title></head></html>"); webClient.setWebConnection(webConnection); final Page page2 = webClient.getPage(URL_FIRST); webClient.getPage(URL_FIRST); assertEquals(null, webConnection.getLastWebRequest().getProxyHost()); assertEquals(0, webConnection.getLastWebRequest().getProxyPort()); assertEquals(location2, page2.getUrl()); // Make sure default proxy settings are used. webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); webClient.getOptions().setRedirectEnabled(false); final Page page1 = webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort, webConnection.getLastWebRequest().getProxyPort()); assertEquals(URL_FIRST, page1.getUrl()); } } /** * @throws Exception if the test fails */ @Test public void testProxyConfigForJS() throws Exception { final String defaultProxyHost = "defaultProxyHost"; final int defaultProxyPort = 777; final String html = "<html><head><title>Hello World</title>\n" + "<script language='javascript' type='text/javascript' src='foo.js'></script>\n" + "</head><body></body></html>"; try (final WebClient webClient = new WebClient(getBrowserVersion(), defaultProxyHost, defaultProxyPort)) { final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, html); webConnection.setResponse(new URL(URL_FIRST, "foo.js"), "", "text/javascript"); webClient.setWebConnection(webConnection); // Make sure default proxy settings are used. webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort, webConnection.getLastWebRequest().getProxyPort()); // Make sure proxy bypass works with default proxy settings. webClient.getOptions().getProxyConfig().addHostsToProxyBypass(URL_FIRST.getHost()); webClient.getPage(URL_FIRST); assertEquals(null, webConnection.getLastWebRequest().getProxyHost()); assertEquals(0, webConnection.getLastWebRequest().getProxyPort()); // Make sure we can remove proxy bypass filters. webClient.getOptions().getProxyConfig().removeHostsFromProxyBypass(URL_FIRST.getHost()); webClient.getPage(URL_FIRST); assertEquals(defaultProxyHost, webConnection.getLastWebRequest().getProxyHost()); assertEquals(defaultProxyPort, webConnection.getLastWebRequest().getProxyPort()); } } /** * Test {@link WebClient#expandUrl(URL,String)} for the case where an anchor name * was specified. * @throws Exception if the test fails */ @Test public void expandUrl() throws Exception { final String prefix = URL_FIRST.toExternalForm(); assertEquals(prefix + "#second", WebClient.expandUrl(URL_FIRST, "#second")); assertEquals(prefix + "?a=1&b=2", WebClient.expandUrl(new URL(prefix + "?a=1&b=2"), "")); assertEquals(prefix + "?b=2&c=3", WebClient.expandUrl(new URL(prefix + "?a=1&b=2"), "?b=2&c=3")); assertEquals("file:/home/myself/test.js", WebClient.expandUrl(new URL("file:/home/myself/myTest.html"), "test.js")); } /** * @throws Exception if the test fails */ @Test public void expandUrlWithFile() throws Exception { final String urlString = "http://host/page.html"; final URL url = new URL(urlString); assertEquals(urlString + "#second", WebClient.expandUrl(url, "#second")); } /** Test the accessors for refreshHandler. */ @Test public void testRefreshHandlerAccessors() { final WebClient webClient = getWebClient(); assertTrue(ImmediateRefreshHandler.class.isInstance(webClient.getRefreshHandler())); final RefreshHandler handler = new ImmediateRefreshHandler(); webClient.setRefreshHandler(handler); assertSame(handler, webClient.getRefreshHandler()); } /** * Apparently if the browsers receive a charset that they don't understand, they ignore * it and assume ISO-8895-1. Ensure we do the same. * @throws Exception if the test fails */ @Test public void testBadCharset() throws Exception { final String page1Content = "<html><head><title>foo</title>\n" + "</head><body></body></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, page1Content, "text/html; charset=garbage"); client.setWebConnection(webConnection); final Page page = client.getPage(URL_FIRST); assertTrue(HtmlPage.class.isInstance(page)); } /** * Colons are legal in the path of a URL but {@link WebClient#expandUrl(URL,String)} was * blowing up on this case. Ensure it's fixed. * @throws Exception if the test fails */ @Test public void expandUrlHandlesColonsInRelativeUrl() throws Exception { final URL newUrl = WebClient.expandUrl(new URL("http://host/foo"), "/bar/blah:de:blah"); assertEquals("http://host/bar/blah:de:blah", newUrl); } /** * Test reuse of a single {@link HtmlPage} object to submit the same form multiple times. * @throws Exception if test fails */ @Test public void testReusingHtmlPageToSubmitFormMultipleTimes() throws Exception { final String firstContent = "<html><head><title>First</title></head>\n" + "<body onload='document.myform.mysubmit.focus()'>\n" + "<form action='" + URL_SECOND + "' name='myform'>\n" + "<input type='submit' name='mysubmit'>\n" + "</form></body></html>"; final String secondContent = "<html><head><title>Second</title></head><body>Second</body></html>"; final WebClient webClient = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setDefaultResponse(secondContent); webClient.setWebConnection(webConnection); final HtmlPage page = webClient.getPage(URL_FIRST); for (int i = 0; i < 100; i++) { final HtmlElement button = page.getFormByName("myform").getInputByName("mysubmit"); button.click(); } } /** * Test the value of window.opener when a link has target="_top". * @throws Exception if test fails */ @Test public void testOpenerInFrameset() throws Exception { final String firstContent = "<html><head><script>alert(window.opener)</script><frameset cols='*'>\n" + "<frame src='" + URL_SECOND + "'>\n" + "</frameset>\n" + "</html>"; final String secondContent = "<html><body><a href='" + URL_FIRST + "' target='_top'>to top</a></body></html>"; final WebClient webClient = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); webClient.setWebConnection(webConnection); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final HtmlPage page = webClient.getPage(URL_FIRST); final HtmlPage pageInFrame = (HtmlPage) ((WebWindow) page.getFrames().get(0)).getEnclosedPage(); pageInFrame.getAnchors().get(0).click(); final String[] expectedAlerts = { "null", "null" }; assertEquals(expectedAlerts, collectedAlerts); } /** * @throws Exception if an error occurs */ @Test public void testGuessContentType() throws Exception { final WebClient c = getWebClient(); // tests empty files, type should be determined from file suffix assertEquals("empty.png", "image/png", c.guessContentType(getTestFile("empty.png"))); assertEquals("empty.jpg", "image/jpeg", c.guessContentType(getTestFile("empty.jpg"))); assertEquals("empty.gif", "image/gif", c.guessContentType(getTestFile("empty.gif"))); assertEquals("empty.js", "text/javascript", c.guessContentType(getTestFile("empty.js"))); // test real files with bad file suffix assertEquals("tiny-png.img", "image/png", c.guessContentType(getTestFile("tiny-png.img"))); assertEquals("tiny-jpg.img", "image/jpeg", c.guessContentType(getTestFile("tiny-jpg.img"))); assertEquals("tiny-gif.img", "image/gif", c.guessContentType(getTestFile("tiny-gif.img"))); // tests XHTML files, types will be determined based on a mixture of file suffixes and contents // note that "xhtml.php" returns content type "text/xml" in Firefox, but "application/xml" is good enough... assertEquals("xhtml.php", "application/xml", c.guessContentType(getTestFile("xhtml.php"))); assertEquals("xhtml.htm", "text/html", c.guessContentType(getTestFile("xhtml.htm"))); assertEquals("xhtml.html", "text/html", c.guessContentType(getTestFile("xhtml.html"))); assertEquals("xhtml.xhtml", "application/xhtml+xml", c.guessContentType(getTestFile("xhtml.xhtml"))); } /** * Test that no encoding disturb file reads from filesystem. * For instance this test failed under Linux with LANG=de_DE.UTF-8 or LANG=C * but worked for LANG=de_DE.ISO-8859-1 * @throws Exception if the test fails */ @Test public void testBinaryFileFromFileSystem() throws Exception { final String testfileName = "tiny-jpg.img"; final File testfile = getTestFile(testfileName); final byte[] directBytes = IOUtils.toByteArray(new FileInputStream(testfile)); final String directStr = hexRepresentation(directBytes); final WebClient client = getWebClient(); final Page testpage = client.getPage(testfile.toURI().toURL()); final byte[] webclientBytes = IOUtils.toByteArray(testpage.getWebResponse().getContentAsStream()); final String webclientStr = hexRepresentation(webclientBytes); assertEquals(directStr, webclientStr); } /** * Helper to make hex diff human easier to read for human eyes * @param digest the bytes * @return the hex representation */ private static String hexRepresentation(final byte[] digest) { final StringBuilder hexString = new StringBuilder(); for (final byte b : digest) { hexString.append(Integer.toHexString(0xFF & b)); hexString.append(" "); } return hexString.toString().trim(); } /** * Gets the file located in testfiles from the file name * @param fileName the file name * @return the file * @throws Exception if a pb occurs */ private File getTestFile(final String fileName) throws Exception { final URL url = getClass().getClassLoader().getResource("testfiles/" + fileName); if (url == null) { throw new FileNotFoundException(fileName); } final File file = new File(new URI(url.toString())); return file; } /** * Test that additional header are correctly transmitted to the web connection. * @throws Exception if something goes wrong */ @Test public void testRequestHeader() throws Exception { final String content = "<html></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(content); client.setWebConnection(webConnection); client.getPage(URL_FIRST); assertNull(webConnection.getLastAdditionalHeaders().get("foo-header")); client.addRequestHeader("foo-header", "foo value"); client.getPage(URL_FIRST); assertEquals("foo value", webConnection.getLastAdditionalHeaders().get("foo-header")); client.removeRequestHeader("foo-header"); client.getPage(URL_FIRST); assertNull(webConnection.getLastAdditionalHeaders().get("foo-header")); } /** * Test that content type is looked in a case insensitive way. * Cf <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>: * "All media type values, subtype values, and parameter names as defined * are case-insensitive". * @throws Exception if something goes wrong */ @Test public void contentTypeCaseInsensitive() throws Exception { final String content = "<html><head>\n" + "<script type='Text/Javascript' src='foo.js'></script>\n" + "</head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse("alert('foo')", 200, "OK", "Text/Javascript"); client.setWebConnection(webConnection); final List<String> collectedAlerts = new ArrayList<>(); client.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final String[] expectedAlerts = { "foo" }; webConnection.setResponse(URL_FIRST, content, "Text/Html"); assertTrue(HtmlPage.class.isInstance(client.getPage(URL_FIRST))); assertEquals(expectedAlerts, collectedAlerts); webConnection.setResponse(URL_FIRST, content, "Text/Xml"); assertTrue(XmlPage.class.isInstance(client.getPage(URL_FIRST))); webConnection.setResponse(URL_FIRST, content, "ApplicaTion/Xml"); assertTrue(XmlPage.class.isInstance(client.getPage(URL_FIRST))); webConnection.setResponse(URL_FIRST, content, "Text/Plain"); assertTrue(TextPage.class.isInstance(client.getPage(URL_FIRST))); webConnection.setResponse(URL_FIRST, "", "Text/JavaScript"); assertTrue(JavaScriptPage.class.isInstance(client.getPage(URL_FIRST))); } /** * Load a JavaScript function from an external file using src references * inside a script element. * * @throws Exception if the test fails */ @Test public void loadFilePageWithExternalJS() throws Exception { final File currentDirectory = new File((new File("")).getAbsolutePath()); final String encoding = (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding(); // JavaScript file final File tmpFileJS = File.createTempFile("test", ".js", currentDirectory); tmpFileJS.deleteOnExit(); FileUtils.writeStringToFile(tmpFileJS, "alert('foo')", encoding); // HTML file final String html = "<html><head></head><body>\n" + "<script language='javascript' type='text/javascript' src='" + tmpFileJS.getName() + "'></script>\n" + "</body></html>"; final File tmpFile = File.createTempFile("test", ".html", currentDirectory); tmpFile.deleteOnExit(); FileUtils.writeStringToFile(tmpFile, html, encoding); final URL fileURL = new URL("file://" + tmpFile.getCanonicalPath()); final WebClient webClient = getWebClient(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); webClient.getPage(fileURL); final String[] expectedAlerts = { "foo" }; assertEquals(expectedAlerts, collectedAlerts); } /** * Verifies that {@link WebClient#getPage(WebWindow, WebRequest)} calls OnBeforeUnload * on the specified window's page, not on the client's "current" page. * @throws Exception if an error occurs */ @Test public void testOnBeforeUnloadCalledOnCorrectPage() throws Exception { final String html = "<html><body onbeforeunload='alert(7)'><iframe></iframe></body></html>"; final List<String> alerts = new ArrayList<>(); loadPage(html, alerts); assertTrue(alerts.isEmpty()); } /** * Verifies that URLs are automatically encoded before being sent to the server, like * regular browsers do (verified by sniffing HTTP headers). * @throws Exception if an error occurs */ @Test public void urlEncoding() throws Exception { final URL url = new URL("http://host/x+y\u00E9/a\u00E9 b?c \u00E9 d"); final HtmlPage page = loadPage(BrowserVersion.FIREFOX_38, "<html></html>", new ArrayList<String>(), url); final WebRequest wrs = page.getWebResponse().getWebRequest(); assertEquals("http://host/x+y%C3%A9/a%C3%A9%20b?c%20%E9%20d", wrs.getUrl()); } /** * Verifies that URLs are automatically encoded before being sent to the server, like * regular browsers do (verified by sniffing HTTP headers). * @throws Exception if an error occurs */ @Test public void urlEncoding2() throws Exception { final URL url = new URL("http://host/x+y\u00E9/a\u00E9 b?c \u00E9 d"); final HtmlPage page = loadPage(INTERNET_EXPLORER_11, "<html></html>", new ArrayList<String>(), url); final WebRequest wrs = page.getWebResponse().getWebRequest(); assertEquals("http://host/x+y%C3%A9/a%C3%A9%20b?c%20\u00E9%20d", wrs.getUrl()); } /** * Test that '+' is not encoded in URLs. * @throws Exception if the test fails */ @Test public void testPlusNotEncodedInUrl() throws Exception { final URL url = new URL("http://host/search/my+category/"); final HtmlPage page = loadPage("<html></html>", new ArrayList<String>(), url); final WebRequest wrs = page.getWebResponse().getWebRequest(); assertEquals("http://host/search/my+category/", wrs.getUrl()); } /** * @throws Exception if an error occurs */ @Test public void cssEnablementControlsCssLoading() throws Exception { final WebClient client = getWebClient(); final MockWebConnection conn = new MockWebConnection(); client.setWebConnection(conn); final String html = "<html>\n" + " <head>\n" + " <link href='" + URL_SECOND + "' rel='stylesheet'></link>\n" + " </head>\n" + " <body onload='alert(document.styleSheets.length)'>\n" + " <div>abc</div>\n" + " </body>\n" + "</html>"; conn.setResponse(URL_FIRST, html); final String css = ".foo { color: green; }"; conn.setResponse(URL_SECOND, css, 200, "OK", "text/css", new ArrayList<NameValuePair>()); final List<String> actual = new ArrayList<>(); client.setAlertHandler(new CollectingAlertHandler(actual)); client.getPage(URL_FIRST); assertEquals(new String[] { "1" }, actual); actual.clear(); client.getOptions().setCssEnabled(false); client.getPage(URL_FIRST); assertEquals(new String[] { "0" }, actual); actual.clear(); client.getOptions().setCssEnabled(true); client.getPage(URL_FIRST); assertEquals(new String[] { "1" }, actual); } /** * @throws Exception if test fails */ @Test public void testGetPageJavascriptProtocol() throws Exception { final WebClient webClient = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse("<html><head><title>Hello World</title></head><body></body></html>"); webClient.setWebConnection(webConnection); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); Page page = webClient.getPage("javascript:void(alert(document.location))"); assertEquals("about:blank", page.getUrl()); assertEquals(new String[] { "about:blank" }, collectedAlerts); collectedAlerts.clear(); page = webClient.getPage(URL_FIRST); final Page page2 = webClient.getPage("javascript:void(alert(document.title))"); assertSame(page, page2); assertEquals(new String[] { "Hello World" }, collectedAlerts); webClient.getPage("javascript:void(document.body.setAttribute('foo', window.screen.availWidth))"); assertEquals("1024", ((HtmlPage) page).getBody().getAttribute("foo")); } /** * @throws Exception if the test fails */ @Test public void testJavaScriptTimeout() throws Exception { final WebClient client = getWebClient(); final long timeout = 2000; final long oldTimeout = client.getJavaScriptTimeout(); client.setJavaScriptTimeout(timeout); try { client.getOptions().setThrowExceptionOnScriptError(false); final String content = "<html><body><script>while(1) {}</script></body></html>"; final MockWebConnection webConnection = new MockWebConnection(); webConnection.setDefaultResponse(content); client.setWebConnection(webConnection); final Exception[] exceptions = { null }; final Thread runner = new Thread() { @Override public void run() { try { client.getPage(URL_FIRST); } catch (final Exception e) { exceptions[0] = e; } } }; runner.start(); runner.join(timeout * 2); if (runner.isAlive()) { runner.interrupt(); fail("Script was still running after timeout"); } assertNull(exceptions[0]); } finally { client.setJavaScriptTimeout(oldTimeout); } } /** * Protects against the regression detailed in bug 1975445. * @throws Exception if an error occurs */ @Test public void testOpenWindowWithNullUrl() throws Exception { final WebClient client = getWebClient(); final WebWindow window = client.openWindow(null, "TestingWindow"); assertNotNull(window); } /** * Basic window tracking testing. * @throws Exception if an error occurs */ @Test public void testBasicWindowTracking() throws Exception { // Create mock web connection. final MockWebConnection conn = new MockWebConnection(); conn.setDefaultResponse("<html></html"); // Make sure a new client start with a single window. final WebClient client = getWebClient(); client.setWebConnection(conn); assertEquals(1, client.getWebWindows().size()); // Make sure the initial window is the current window. final WebWindow window1 = client.getCurrentWindow(); assertSame(window1, client.getCurrentWindow()); assertNotNull(window1); // Make sure that we keep track of a new window when we open it. final WebWindow window2 = client.openWindow(URL_FIRST, "blah"); assertSame(window2, client.getCurrentWindow()); assertEquals(2, client.getWebWindows().size()); assertNotNull(window2); // Make sure that we keep track of another new window when we open it. final WebWindow window3 = client.openWindow(URL_SECOND, "foo"); assertSame(window3, client.getCurrentWindow()); assertEquals(3, client.getWebWindows().size()); assertNotNull(window3); // Close the last window, make sure that the second window becomes the current window. ((TopLevelWindow) window3).close(); assertSame(window2, client.getCurrentWindow()); assertEquals(2, client.getWebWindows().size()); // Close the first window, make sure that the second window is still the current window. ((TopLevelWindow) window1).close(); assertSame(window2, client.getCurrentWindow()); assertEquals(1, client.getWebWindows().size()); // Close the only remaining window, make sure the client still has a current window. ((TopLevelWindow) window2).close(); assertNotNull(client.getCurrentWindow()); assertNotSame(window1, client.getCurrentWindow()); assertNotSame(window2, client.getCurrentWindow()); assertNotSame(window3, client.getCurrentWindow()); assertEquals(1, client.getWebWindows().size()); } /** * Previous window should become current window after current window is closed in onLoad event. * @throws Exception if an error occurs */ @Test public void windowTracking_SpecialCase1() throws Exception { final WebClient webClient = getWebClient(); final MockWebConnection conn = new MockWebConnection(); final String html1 = "<html><head><title>First</title></head>\n" + "<body><form name='form1'>\n" + "<button id='clickme' onClick='window.open(\"" + URL_SECOND + "\");'>Click me</button>\n" + "</form></body></html>"; conn.setResponse(URL_FIRST, html1); final String html2 = "<html><head><title>Second</title></head>\n" + "<body onload='doTest()'>\n" + "<script>\n" + " function doTest() {\n" + " window.close();\n" + " }\n" + "</script></body></html>"; conn.setDefaultResponse(html2); webClient.setWebConnection(conn); final HtmlPage firstPage = webClient.getPage(URL_FIRST); final HtmlButton buttonA = firstPage.getHtmlElementById("clickme"); buttonA.click(); assertNotNull(webClient.getCurrentWindow().getEnclosedPage()); assertEquals("First", ((HtmlPage) webClient.getCurrentWindow().getEnclosedPage()).getTitleText()); } /** * Previous window should become current window after current window is closed while loading the page. * @throws Exception if an error occurs */ @Test public void windowTracking_SpecialCase2() throws Exception { final WebClient webClient = getWebClient(); final MockWebConnection conn = new MockWebConnection(); final String html1 = "<html><head><title>First</title></head>\n" + "<body><form name='form1'>\n" + "<button id='clickme' onClick='window.open(\"" + URL_SECOND + "\");'>Click me</button>\n" + "</form></body></html>"; conn.setResponse(URL_FIRST, html1); final String html2 = "<html><head><title>Third</title>" + "<script type=\"text/javascript\">\n" + " window.close();\n" + "</script></head></html>"; conn.setDefaultResponse(html2); webClient.setWebConnection(conn); final HtmlPage firstPage = webClient.getPage(URL_FIRST); final HtmlButton buttonA = firstPage.getHtmlElementById("clickme"); buttonA.click(); assertNotNull(webClient.getCurrentWindow().getEnclosedPage()); assertEquals("First", ((HtmlPage) webClient.getCurrentWindow().getEnclosedPage()).getTitleText()); } /** * Previous window should become current window after current window is closed. * @throws Exception if an error occurs */ @Test @Alerts(IE = "Third page loaded") public void testWindowTracking_SpecialCase3() throws Exception { final WebClient webClient = getWebClient(); final MockWebConnection conn = new MockWebConnection(); final List<String> collectedAlerts = new ArrayList<>(); webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); final String html1 = "<html><head><title>First</title></head>\n" + "<body>\n" + "<button id='clickme' onClick='window.open(\"" + URL_SECOND + "\");'>Click me</button>\n" + "</body></html>"; conn.setResponse(URL_FIRST, html1); final String html2 = "<html><head><title>Second</title></head>\n" + "<body onUnload='doTest()'>" + "<form name='form1' action='" + URL_THIRD + "'>\n" + "<button id='clickme' type='button' onclick='postBack();'>Submit</button></form>\n" + "<script>\n" + " function doTest() {\n" + " window.close();\n" + " }\n" + " function postBack() {\n" + " var frm = document.forms[0];\n" + " frm.submit();\n" + " }\n" + "</script></body></html>"; conn.setResponse(URL_SECOND, html2); final String html3 = "<html><head><title>Third</title>" + "<script type=\"text/javascript\">\n" + " alert('Third page loaded');\n" + " window.close();\n" + "</script></head></html>"; conn.setResponse(URL_THIRD, html3); conn.setDefaultResponse(html3); webClient.setWebConnection(conn); final HtmlPage firstPage = webClient.getPage(URL_FIRST); final HtmlButton buttonA = firstPage.getHtmlElementById("clickme"); buttonA.click(); final HtmlPage secondPage = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage(); assertEquals("Second", secondPage.getTitleText()); final HtmlButton buttonB = secondPage.getHtmlElementById("clickme"); buttonB.click(); assertEquals("First", ((HtmlPage) webClient.getCurrentWindow().getEnclosedPage()).getTitleText()); assertEquals(getExpectedAlerts(), collectedAlerts); } /** * Bug 2890847: Triggering the creation of an empty frame based on some user action should not * make the empty frame the current window. * @throws Exception if an error occurs */ @Test public void testWindowTracking_SpecialCase4() throws Exception { final WebClient client = getWebClient(); final MockWebConnection conn = new MockWebConnection(); client.setWebConnection(conn); final String html = "<html><head><title>Test</title></head><body>\n" + "<div id='d' onclick='this.innerHTML+=\"<iframe></iframe>\";'>go</div></body></html>"; conn.setResponse(URL_FIRST, html); final HtmlPage page = client.getPage(URL_FIRST); page.getHtmlElementById("d").click(); assertEquals("Test", ((HtmlPage) client.getCurrentWindow().getEnclosedPage()).getTitleText()); } /** * @throws Exception if an error occurs */ @Test public void testOpenWindowWithAboutBlank() throws Exception { final WebClient client = getWebClient(); final WebWindow window = client.openWindow(WebClient.URL_ABOUT_BLANK, "TestingWindow"); assertNotNull(window); } /** * @throws Exception if an error occurs */ @Test public void cssErrorHandler() throws Exception { final WebClient client = getWebClient(); assertTrue(client.getCssErrorHandler() instanceof DefaultCssErrorHandler); final MutableInt errors = new MutableInt(); final StringBuilder errorUri = new StringBuilder(); final ErrorHandler handler = new ErrorHandler() { @Override public void warning(final CSSParseException exception) throws CSSException { errors.increment(); } @Override public void fatalError(final CSSParseException exception) throws CSSException { errors.increment(); } @Override public void error(final CSSParseException exception) throws CSSException { errors.increment(); errorUri.append(exception.getURI()); } }; client.setCssErrorHandler(handler); assertEquals(handler, client.getCssErrorHandler()); final MockWebConnection conn = new MockWebConnection(); conn.setResponse(URL_FIRST, "<html><body><style></style></body></html>"); conn.setResponse(URL_SECOND, "<html><body><style>.x{color:red;}</style></body></html>"); conn.setResponse(URL_THIRD, "<html><body><style>.x{color{}}}</style></body></html>"); client.setWebConnection(conn); final HtmlPage page1 = client.getPage(URL_FIRST); ((HTMLStyleElement) page1.getBody().getFirstChild().getScriptableObject()).getSheet(); assertEquals(0, errors.intValue()); final HtmlPage page2 = client.getPage(URL_SECOND); ((HTMLStyleElement) page2.getBody().getFirstChild().getScriptableObject()).getSheet(); assertEquals(0, errors.intValue()); final HtmlPage page3 = client.getPage(URL_THIRD); ((HTMLStyleElement) page3.getBody().getFirstChild().getScriptableObject()).getSheet(); assertEquals(2, errors.intValue()); assertEquals("http://127.0.0.1:" + PORT + "/third/http://127.0.0.1:" + PORT + "/third/", errorUri.toString()); } /** * Tests that the JavaScript parent scope is set correctly when shuffling windows around. * @throws Exception if test fails */ @Test public void testMaintainJavaScriptParentScope() throws Exception { final String basicContent = "<html><head>" + "<title>basicContentTitle</title>\n" + "</head><body>\n" + "<p>Hello World</p>" + "</body></html>"; final String jsContent = "<html><head>" + "<title>jsContentTitle</title>\n" + "<script>function foo() {alert('Ran Here')}</script>\n" + "<script>function bar() {}</script>\n" + "</head><body onload='bar()'>\n" + "<input type='button' id='button' onclick='foo()'/>" + "</body></html>"; final HtmlPage jsPage = loadPage(jsContent); final WebClient webClient = jsPage.getWebClient(); final WebWindow firstWindow = webClient.getCurrentWindow(); getMockConnection(jsPage).setResponse(URL_SECOND, basicContent); final CollectingAlertHandler alertHandler = new CollectingAlertHandler(); webClient.setAlertHandler(alertHandler); final HtmlButtonInput buttonBefore = jsPage.getHtmlElementById("button"); final WebWindow secondWindow = webClient.openWindow(null, "second window"); webClient.setCurrentWindow(secondWindow); webClient.getPage(URL_SECOND); webClient.setCurrentWindow(firstWindow); final HtmlPage currentPage = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage(); final HtmlButtonInput buttonAfter = currentPage.getHtmlElementById("button"); assertSame(buttonBefore, buttonAfter); buttonAfter.click(); assertEquals(1, alertHandler.getCollectedAlerts().size()); assertEquals("Ran Here", alertHandler.getCollectedAlerts().get(0)); } /** * @throws Exception if test fails */ @Test public void currentWindow() throws Exception { final WebClient client = getWebClient(); final MockWebConnection conn = new MockWebConnection(); final String html = "<html><body onload='document.getElementById(\"f\").src=\"frame.html\";'>" + "<iframe id='f'></iframe></body></html>"; conn.setResponse(URL_FIRST, html); final URL frameUrl = new URL(URL_FIRST.toExternalForm() + "frame.html"); conn.setResponse(frameUrl, "<html><body></body></html>"); conn.setResponse(URL_SECOND, "<html><body></body></html>"); client.setWebConnection(conn); client.getPage(URL_FIRST); assertEquals(2, client.getWebWindows().size()); assertEquals(frameUrl, client.getCurrentWindow().getEnclosedPage().getUrl()); // loading a new page should be done in the top window client.getPage(URL_SECOND); assertTrue(client.getCurrentWindow() instanceof TopLevelWindow); assertEquals(1, client.getWebWindows().size()); } /** * @throws Exception if test fails */ @Test public void currentWindow2() throws Exception { final String html = "<html><head><script>\n" + "function createFrame() {\n" + " var f = document.createElement('iframe');\n" + " f.setAttribute('style', 'width: 0pt; height: 0pt');\n" + " document.body.appendChild(f);\n" + " f.src = \"javascript:''\";\n" + "}\n" + "</script></head>\n" + "<body onload='setTimeout(createFrame, 10)'></body></html>"; final HtmlPage page = loadPage(html); assertTrue(page.getEnclosingWindow() instanceof TopLevelWindow); page.getWebClient().waitForBackgroundJavaScriptStartingBefore(1000); assertSame(page.getEnclosingWindow(), page.getWebClient().getCurrentWindow()); } /** * @throws Exception if an error occurs */ @Test public void testGetTopLevelWindows() throws Exception { final WebClient client = getWebClient(); final MockWebConnection conn = new MockWebConnection(); conn.setResponse(URL_FIRST, "<html><body><iframe></iframe></body></html>"); conn.setResponse(URL_SECOND, "<html><body></body></html>"); client.setWebConnection(conn); assertEquals(1, client.getWebWindows().size()); assertEquals(1, client.getTopLevelWindows().size()); client.getPage(URL_FIRST); assertEquals(2, client.getWebWindows().size()); assertEquals(1, client.getTopLevelWindows().size()); client.getPage(URL_SECOND); assertEquals(1, client.getWebWindows().size()); assertEquals(1, client.getTopLevelWindows().size()); client.openWindow(URL_SECOND, "a"); assertEquals(2, client.getWebWindows().size()); assertEquals(2, client.getTopLevelWindows().size()); client.openWindow(URL_SECOND, "b"); assertEquals(3, client.getWebWindows().size()); assertEquals(3, client.getTopLevelWindows().size()); client.close(); assertEquals(1, client.getWebWindows().size()); assertEquals(1, client.getTopLevelWindows().size()); } /** * Test that the result of getTopLevelWindows() is usable without * getting a ConcurrentModificationException. * * @throws Exception if an error occurs */ @Test public void getTopLevelWindowsJSConcurrency() throws Exception { final String html = "<html><head><title>Toplevel</title></head>\n<body>\n" + "<script>\n" + " setInterval(function() {\n" + " window.open('');\n" + " }, 10);\n" + "</script>\n" + "</body></html>\n"; final WebClient client = getWebClientWithMockWebConnection(); getMockWebConnection().setResponse(URL_FIRST, html); client.getPage(URL_FIRST); final List<TopLevelWindow> windows = client.getTopLevelWindows(); for (int i = 0; i < 100; i++) { for (TopLevelWindow window : windows) { Thread.sleep(13); window.getName(); } } } /** * Regression test for * <a href="http://sourceforge.net/support/tracker.php?aid=2819046>bug 2819046</a>. * * @throws Exception if something goes wrong */ @Test public void urlWithDirectoryUp() throws Exception { final URL url = new URL("http://htmlunit.sf.net/foo.html"); final URL urlWithDirectoryUp = new URL("http://htmlunit.sf.net/bla/../foo.html"); final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(url, ""); client.setWebConnection(webConnection); final Page page = client.getPage(urlWithDirectoryUp); assertEquals(url, page.getUrl()); } /** * Test that close() stops all threads. This wasn't the case as * of HtmlUnit-2.7-SNAPSHOT 11.12.2009. * @throws Exception if test fails */ @Test public void close() throws Exception { final String html = "<html><head></head>\n" + "<body onload='setInterval(addFrame, 1)'>\n" + "<iframe src='second.html'></iframe>\n" + "<script>\n" + "function addFrame() {\n" + " var f = document.createElement('iframe');\n" + " f.src = 'second.html';\n" + " document.body.appendChild(f);\n" + "}\n" + "</script>\n" + "</body></html>"; final String html2 = "<html><head><script>\n" + "function doSomething() {}\n" + "setInterval(doSomething, 100);\n" + "</script>\n" + "</head><body></body></html>"; getMockWebConnection().setResponse(getDefaultUrl(), html); getMockWebConnection().setDefaultResponse(html2); final WebClient webClient = getWebClient(); final int initialJSThreads = getJavaScriptThreads().size(); webClient.setWebConnection(getMockWebConnection()); webClient.getPage(getDefaultUrl()); int nbJSThreads = getJavaScriptThreads().size(); final int nbNewJSThreads = nbJSThreads - initialJSThreads; assertTrue(nbNewJSThreads + " threads", nbNewJSThreads > 0); // close and verify that the WebClient is clean webClient.close(); assertEquals(1, webClient.getWebWindows().size()); nbJSThreads = getJavaScriptThreads().size(); assertEquals(initialJSThreads, nbJSThreads); } /** * Tests that setThrowExceptionOnScriptError also works, * if an exception is thrown from onerror handler. * Regression test for bug 3534371. * * @throws Exception if the test fails */ @Test public void test() throws Exception { final String html = "<html><body>" + "<script type='application/javascript'>" + " window.onerror = function(){ foo.bar() };" + " doit();" + "</script>" + "</body></html>"; final WebClient webClient = getWebClient(); webClient.getOptions().setJavaScriptEnabled(true); webClient.getOptions().setThrowExceptionOnScriptError(false); loadPage(html); } /** * Testcase for issue #1652. * @throws Exception if the test fails */ @Test public void aboutBlankSharedRequest() throws Exception { final WebClient webClient = getWebClient(); final WebWindow firstWindow = webClient.openWindow(WebClient.URL_ABOUT_BLANK, "Window 1"); assertNotNull(firstWindow); final WebRequest firstRequest1 = firstWindow.getEnclosedPage().getWebResponse().getWebRequest(); assertEquals("about:blank", firstRequest1.getUrl().toExternalForm()); firstRequest1.setUrl(UrlUtils.toUrlSafe(WebClient.ABOUT_BLANK + "#anchor")); final WebWindow secondWindow = webClient.openWindow(WebClient.URL_ABOUT_BLANK, "Window 2"); assertNotNull(secondWindow); final WebRequest secondRequest = secondWindow.getEnclosedPage().getWebResponse().getWebRequest(); assertEquals("about:blank", secondRequest.getUrl().toExternalForm()); } /** * @throws Exception if the test fails */ @Test public void closeToClearCache() throws Exception { final WebClient webClient = getWebClient(); final Cache cache = createMock(Cache.class); webClient.setCache(cache); cache.clear(); expectLastCall().atLeastOnce(); replay(cache); webClient.close(); verify(cache); } }