Introduction

A frequent question we get is "how do I test my JavaScript?". There is nothing really specific for using JavaScript, it is automatically processed. So, you just need to .getPage(), find the element to click(), and then check the result. Tests for complex JavaScript libraries are included in HtmlUnit test base, you can find it here which is useful to get an idea.

Usually, you should wait a little, as HtmlUnit can finish before the AJAX response is retrieved from the server, please read this FAQ.

Enable/Disable JavaScript support

JavaScript support is enabled per default like in real browsers.

But: There is one major difference - in the default configuration HtmlUnit will stop JavaScript execution if an unhandled JavaScript error occurs. This is done because HtmlUnit was initially designed for testing where fail early is a good practice.

You can change this to silently (HtmlUnit will still log the exceptions) ignore them (like in real browsers) by setting the option throwExceptionOnScriptError to false.

 final WebClient webClient = new WebClient();
 webClient.getOptions.setThrowExceptionOnScriptError(false);

For some use cases it might be helpful to completely disable the JavaScript support (e.g. for better performance). HtmlUnit offers two way to do this; you can completely disable JavaScript or only temporary.

To disable the JavaScript support (without the possibility to enable it for the WebClient later on) a special WebClient constructor is available. This is the most performance/resource effective solution.

 WebClient webClient = new WebClient(BrowserVersion.FIREFOX, false, null, -1);

By using the WebClientOptions it is possible to disable and re-enable the JavaScript support at any time for a given client. Doing this will only stop executing the script tags and triggering any event listeners.

 final WebClient webClient = new WebClient(BrowserVersion.FIREFOX);
 webClient.getOptions.setJavaScriptEnabled(false);
 ....
 webClient.getOptions.setJavaScriptEnabled(true);

Example: using Document.write()

Lets say that we have a page containing JavaScript that will dynamically write content to the page. The following html will dynamically generate five textfields and place them inside a table. Each textfield will have a unique name created by appending the index to the string "textfield".

<html><head><title>Table sample</title></head><body>
    <form action='/foo' name='form1'>
    <table id="table1">
        <script type="text/javascript">
            for (i = 1; i <= 5; i++) {
                document.write("<tr><td>" + i
                    + "</td><td><input name='textfield" + i
                    + "' type='text'></td></tr>");
            }
        </script>
    </table></form>
</body></html>

We would likely want to test that the five text fields were created so we could start with this.

@Test
public void documentWrite() throws Exception {
    final WebClient webClient = new WebClient();

    final HtmlPage page = webClient.getPage("http://myserver/test.html");
    final HtmlForm form = page.getFormByName("form1");
    for (int i = 1; i <= 5; i++) {
        final String expectedName = "textfield" + i;
        Assert.assertEquals(
            "text", 
            form.<HtmlInput>getInputByName(expectedName).getTypeAttribute());
    }
}

We might also want to check off-by-one errors by ensuring that it didn't create "textfield0" or "textfield6". Trying to get an element that doesn't exist will cause an exception to be thrown so we could add this to the end of the previous test.

try {
    form.getInputByName("textfield0");
    fail("Expected an ElementNotFoundException");
}
catch (final ElementNotFoundException e) {
    // Expected path
}

try {
    form.getInputByName("textfield6");
    fail("Expected an ElementNotFoundException");
}
catch (final ElementNotFoundException e) {
    // Expected path
}

Example: Watching for 'alerts'

Often you want to watch alerts triggered by JavaScript.

<html><head><title>Alert sample</title></head>
<body onload='alert("foo");'>
</body></html>

Alerts are tracked by an AlertHandler which will be called whenever the JavaScript alert() function is called. In the following test, we register an alert handler which just saves all messages into a list. When the page load is complete, we compare that list of collected alerts with another list of expected alerts to ensure they are the same.

@Test
public void alerts() throws Exception {
    final WebClient webClient = new WebClient();

    final List collectedAlerts = new ArrayList();
    webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));

    // Since we aren't actually manipulating the page, we don't assign
    // it to a variable - it's enough to know that it loaded.
    webClient.getPage("http://tciludev01/test.html");

    final List expectedAlerts = Collections.singletonList("foo");
    Assert.assertEquals(expectedAlerts, collectedAlerts);
}

Prompts, Confirms and Status line messages

Handling prompt dialogs, confirm dialogs and status line messages work in the same way as alerts. You register a handler of the appropriate type and it will get notified when that method is called. See WebClient.setPromptHandler(), WebClient.setConfirmHandler() and WebClient.setStatusHandler() for details on these.

Event handlers

Most event handlers are already implemented: onload, onclick, ondblclick, onmouseup, onsubmit, onreadystatechange, ... They will be triggered at the appropriate time just like in a "real browser".

If the event that you wish to test is not yet supported then you can directly invoke it through the ScriptEngine. Note that while the script engine is publicly accessible, we do not recommend using it directly unless you have no other choice. It is much better to manipulate the page as a user would by clicking on elements and shifting the focus around.

Run javascript inside the page/window

Sometimes it is helpfull to execute javascript inside the current page e.g. to get the value of window properties or forcing some javascript functions to run. In general you can do everything you can do with a script tag inside the page and additionally get back the result of the invokation.

String script = "window.name;";
String result = (String) page.executeJavaScript(script).getJavaScriptResult();
}