com.gargoylesoftware.htmlunit.WebClient3Test.java Source code

Java tutorial

Introduction

Here is the source code for com.gargoylesoftware.htmlunit.WebClient3Test.java

Source

/*
 * 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.BrowserRunner.Browser.IE;
import static org.junit.Assert.assertArrayEquals;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.zip.Deflater;

import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;

import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts;
import com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented;
import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame;
import com.gargoylesoftware.htmlunit.util.NameValuePair;

/**
 * Tests for {@link WebClient} using WebDriverTestCase.
 *
 * @author Marc Guillemot
 * @author Frank Danek
 * @author Ronald Brill
 */
@RunWith(BrowserRunner.class)
public class WebClient3Test extends WebDriverTestCase {

    /**
     * Regression test for bug 3012067: a null pointer exception was occurring.
     * @throws Exception if an error occurs
     */
    @Test
    public void bug3012067_npe() throws Exception {
        final String html = "<html><body>\n" + "<form action='" + getDefaultUrl() + "#foo' method='post'></form>\n"
                + "<script>\n" + "function doWork() {\n" + "  var f = document.forms[0];\n" + "  f.submit();\n"
                + "  f.submit();\n" + "}\n" + "</script>\n" + "<span id='clickMe' onclick='doWork()'>click</span>\n"
                + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("clickMe")).click();
    }

    /**
     * Ensure that response stream can be read more than one time.
     * @throws Exception if an error occurs
     */
    @Test
    public void readStreamTwice() throws Exception {
        final String html = "<html>\n" + "<body>\n" + "<iframe src='binaryFile.bin'></iframe>\n"
                + "<iframe src='foo.html'></iframe>\n" + "</body></html>";

        final MockWebConnection mockConnection = getMockWebConnection();
        final byte[] binaryContent = new byte[4818];
        final Random random = new Random();
        for (int i = 0; i < binaryContent.length; i++) {
            binaryContent[i] = (byte) (random.nextInt(Byte.MAX_VALUE));
        }
        mockConnection.setDefaultResponse(binaryContent, 200, "OK", "application/octet-stream");
        final URL urlFoo = new URL(getDefaultUrl(), "foo.html");
        mockConnection.setResponse(urlFoo, "<html></html>");

        final WebDriver driver = loadPage2(html);
        final WebElement iframe1 = driver.findElement(By.tagName("iframe"));
        if (driver instanceof HtmlUnitDriver) {
            final HtmlInlineFrame htmlUnitIFrame1 = (HtmlInlineFrame) toHtmlElement(iframe1);
            final WebResponse iframeWebResponse = htmlUnitIFrame1.getEnclosedPage().getWebResponse();
            byte[] receivedBytes = IOUtils.toByteArray(iframeWebResponse.getContentAsStream());
            receivedBytes = IOUtils.toByteArray(iframeWebResponse.getContentAsStream());
            assertArrayEquals(binaryContent, receivedBytes);
        }
    }

    /**
     * Was causing an Exception in IE simulation
     * as of HtmlUnit-2.8-SNAPSHOT on Aug. 04, 2010.
     * @throws Exception if the test fails
     */
    @Test
    public void escapeRequestQuery() throws Exception {
        getMockWebConnection().setDefaultResponse("");

        loadPage2("", new URL(getDefaultUrl(), "foo?a=<b>i</b>"));
    }

    /**
     * Was causing a "java.net.URISyntaxException: Malformed escape pair"
     * as of HtmlUnit-2.12-SNAPSHOT on Nov. 29, 2012.
     * HtmlUnit now escapes the "%%" to "%25%25" to build a valid URL but FF doesn't care
     * and sends the invalid "%%" sequence as it.
     * This will be quite difficult to simulate FF here as HttpClient's HttpRequestBase
     * uses URI and "%%" can't be part of the query string for a URI.
     * @throws Exception if the test fails
     */
    @Test
    @NotYetImplemented
    // FF38 works with real browser
    public void escapeRequestQuery2a() throws Exception {
        getMockWebConnection().setDefaultResponse("");

        final URL url = new URL(getDefaultUrl(), "foo.png?cb=%%RANDOM_NUMBER%%");
        loadPage2("", url);

        assertEquals(url, getMockWebConnection().getLastWebRequest().getUrl());
    }

    /**
     * Was causing a "java.net.URISyntaxException: Malformed escape pair"
     * as of HtmlUnit-2.12-SNAPSHOT on Nov. 29, 2012.
     * This is a simplified version of {@link #escapeRequestQuery2a()} only testing
     * that no exception is thrown. The request performed is not fully correct.
     * This test can be removed once {@link #escapeRequestQuery2a()} runs correctly.
     * @throws Exception if the test fails
     */
    @Test
    public void escapeRequestQuery2b() throws Exception {
        getMockWebConnection().setDefaultResponse("");

        final URL url = new URL(getDefaultUrl(), "foo.png?cb=%%RANDOM_NUMBER%%");
        loadPage2("", url);
    }

    /**
     * Regression test for issue 3193004.
     * Ensure that the click returns once the target page has been loaded into the target window.
     * @throws Exception if an error occurs
     */
    @Test
    public void clickReturnsWhenThePageHasBeenCompleteLoaded() throws Exception {
        final String firstContent = "<html><head>\n" + "<script>window.setInterval(\'',1);</script></head>\n"
                + "<body><a href='" + URL_SECOND + "'>to second</a></body></html>";
        final String secondContent = "<html><body></body></html>";

        final MockWebConnection webConnection = getMockWebConnection();
        webConnection.setResponse(URL_SECOND, secondContent);

        for (int i = 1; i < 100; i++) {
            final WebDriver webDriver = loadPage2(firstContent);
            webDriver.findElement(By.tagName("a")).click();
            assertEquals("Run " + i, URL_SECOND.toExternalForm(), webDriver.getCurrentUrl());
        }
    }

    /**
     * Ensures, that a window opened by an anchor with target attribute is attached
     * to the javascript event loop.
     *
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts({ "open", "first", "second" })
    public void windowOpenedByAnchorTargetIsAttachedToJavascriptEventLoop() throws Exception {
        // TODO [IE11]SINGLE-VS-BULK test runs when executed as single but breaks as bulk
        shutDownRealIE();

        final String firstContent = "<html>" + "<head>" + "<script type='text/javascript'>"
                + "  function info(msg) {" + "    alert(msg);" + "  }" + "</script>" + "</head>" + "<body>"
                + " <a id='testAnchor' href='" + URL_SECOND
                + "' target='_blank' onclick='info(\"open\")'>to second</a>" + "</body></html>";
        final String secondContent = "<html><head>" + "<script type='text/javascript'>" + "  function first() {"
                + "    window.opener.info('first');" + "    window.setTimeout(second, 10);" + "  }"
                + "  function second() {" + "    window.opener.info('second');" + "    window.close();" + "  }"
                + "</script>" + "</head>"

                + "<body onLoad='window.setTimeout(first, 5);'></body></html>";

        getMockWebConnection().setResponse(URL_FIRST, firstContent);
        getMockWebConnection().setResponse(URL_SECOND, secondContent);

        final WebDriver driver = loadPage2(firstContent);
        driver.findElement(By.id("testAnchor")).click();

        verifyAlerts(driver, getExpectedAlerts());
    }

    /**
     * Ensures, that a window opened by a form with target attribute is attached
     * to the javascript event loop.
     *
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts({ "open", "first", "second" })
    public void windowOpenedByFormTargetIsAttachedToJavascriptEventLoop() throws Exception {
        // TODO [IE11]SINGLE-VS-BULK test runs when executed as single but breaks as bulk
        shutDownRealIE();

        final String firstContent = "<html>" + "<head>" + "<script type='text/javascript'>"
                + "  function info(msg) {" + "    alert(msg);" + "  }" + "</script>" + "</head>" + "<body>"
                + "<form action='" + URL_SECOND + "' target='_blank'>"
                + " <input id='testSubmit' type='submit' value='Submit' onclick='info(\"open\")'>" + "</form>"
                + "</body></html>";
        final String secondContent = "<html><head>" + "<script type='text/javascript'>" + "  function first() {"
                + "    window.opener.info('first');" + "    window.setTimeout(second, 10);" + "  }"
                + "  function second() {" + "    window.opener.info('second');" + "    window.close();" + "  }"
                + "</script>" + "</head>"

                + "<body onLoad='window.setTimeout(first, 5);'></body></html>";

        getMockWebConnection().setResponse(URL_FIRST, firstContent);
        getMockWebConnection().setResponse(URL_SECOND, secondContent);

        final WebDriver driver = loadPage2(firstContent);
        driver.findElement(By.id("testSubmit")).click();

        verifyAlerts(driver, getExpectedAlerts());
    }

    /**
     * Ensures, that a window opened by javascript window.open is attached
     * to the javascript event loop.
     *
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts({ "open", "first", "second" })
    public void windowOpenedByJavascriptIsAttachedToJavascriptEventLoop() throws Exception {
        final String firstContent = "<html>" + "<head>" + "<script type='text/javascript'>"
                + "  function info(msg) {" + "    alert(msg);" + "  }" + "</script>" + "</head>" + "<body>"
                + " <a id='testAnchor' href='#'" + "     onclick='info(\"open\");window.open(\"" + URL_SECOND
                + "\", \"Popup\", \"\");'>open window</a>" + "</body></html>";
        final String secondContent = "<html><head>" + "<script type='text/javascript'>" + "  function first() {"
                + "    window.opener.info('first');" + "    window.setTimeout(second, 10);" + "  }"
                + "  function second() {" + "    window.opener.info('second');" + "    window.close();" + "  }"
                + "</script>" + "</head>"

                + "<body onLoad='window.setTimeout(first, 5);'></body></html>";

        getMockWebConnection().setResponse(URL_FIRST, firstContent);
        getMockWebConnection().setResponse(URL_SECOND, secondContent);

        final WebDriver driver = loadPage2(firstContent);
        driver.findElement(By.id("testAnchor")).click();

        verifyAlerts(driver, getExpectedAlerts());
    }

    /**
     * Ensures, that a window opened by javascript and than filled by an form with target attribute
     * is attached to the javascript event loop.
     *
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts({ "open", "first", "second" })
    public void windowOpenedByJavascriptFilledByFormTargetIsAttachedToJavascriptEventLoop() throws Exception {
        final String firstContent = "<html>" + "<head>" + "<script type='text/javascript'>"
                + "  function info(msg) {" + "    alert(msg);" + "  }" + "</script>" + "</head>" + "<body>"
                + "<form action='" + URL_SECOND + "' name='myForm'>"
                + " <input id='testSubmit' type='button' value='Submit' " + "   onclick='info(\"open\");"
                + "   window.open(\"" + URL_SECOND + "\", \"Popup\");" + "   document.myForm.target = \"Popup\";'"
                + " >" + "</form>" + "</body></html>";
        final String secondContent = "<html><head>" + "<script type='text/javascript'>" + "  function first() {"
                + "    window.opener.info('first');" + "    window.setTimeout(second, 10);" + "  }"
                + "  function second() {" + "    window.opener.info('second');" + "    window.close();" + "  }"
                + "</script>" + "</head>"

                + "<body onLoad='window.setTimeout(first, 5);'></body></html>";

        getMockWebConnection().setResponse(URL_FIRST, firstContent);
        getMockWebConnection().setResponse(URL_SECOND, secondContent);

        final WebDriver driver = loadPage2(firstContent);
        driver.findElement(By.id("testSubmit")).click();

        verifyAlerts(driver, getExpectedAlerts());
    }

    /**
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts({ "Executed", "later" })
    // TODO [IE11]ERRORPAGE real IE11 displays own error page if response is to small
    public void execJavascriptOnErrorPages() throws Exception {
        final String errorHtml = "<html>\n" + "<head>\n" + "</head>\n" + "<body>\n"
                + "<script type='text/javascript'>\n" + "  alert('Executed');\n"
                + "  setTimeout(\"alert('later')\", 10);\n" + "</script>\n" + "</body></html>\n";

        final MockWebConnection conn = getMockWebConnection();
        conn.setResponse(URL_FIRST, errorHtml, 404, "Not Found", "text/html", new ArrayList<NameValuePair>());

        loadPageWithAlerts2(URL_FIRST, 42);
    }

    /**
     * This test was failing due to a change made in revision 7104 (not in any release)
     * that was transforming %20 into %2520.
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts("hello")
    public void urlEncodingPercent20() throws Exception {
        final String html = "<html><body>" + "<script src='a%20b.js'></script>" + "</body></html>";

        final MockWebConnection conn = getMockWebConnection();
        conn.setResponse(new URL(getDefaultUrl() + "a%20b.js"), "alert('hello');", "text/javascript");

        loadPageWithAlerts2(html);
    }

    /**
     * Test "deflate" encoding without ZLIB header and checksum fields.
     * This was failing as of HtmlUnit-2.10.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts("modified")
    public void deflateCompressionGZipCompatible() throws Exception {
        // TODO [IE11]SINGLE-VS-BULK test runs when executed as single but breaks as bulk
        shutDownRealIE();

        doTestDeflateCompression(true);
    }

    /**
     * Test "deflate" encoding with ZLIB header and checksum fields.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "modified", IE = "Hello world")
    @NotYetImplemented(IE)
    // IE11 does not support deflate compression anymore but I couldn't find a way to disable it in HttpClient
    public void deflateCompressionNonGZipCompatible() throws Exception {
        doTestDeflateCompression(false);
    }

    private void doTestDeflateCompression(final boolean gzipCompatibleCompression) throws Exception {
        final byte[] input = "document.title = 'modified';".getBytes("UTF-8");

        final byte[] buffer = new byte[100];
        final Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, gzipCompatibleCompression);
        deflater.setInput(input);
        deflater.finish();

        final int compressedDataLength = deflater.deflate(buffer);
        final byte[] content = new byte[compressedDataLength];
        System.arraycopy(buffer, 0, content, 0, compressedDataLength);

        final List<NameValuePair> headers = new ArrayList<>();
        headers.add(new NameValuePair("Content-Encoding", "deflate"));
        headers.add(new NameValuePair("Content-Length", String.valueOf(compressedDataLength)));

        final MockWebConnection conn = getMockWebConnection();
        conn.setResponse(URL_SECOND, content, 200, "OK", "text/javascript", headers);

        final String html = "<html><head>" + "<title>Hello world</title>" + "<script src='" + URL_SECOND
                + "'></script>" + "</head><body><script>alert(document.title)</script></body></html>";
        loadPageWithAlerts2(html);
    }
}