Using JUnit to test JavaScript

In this article I am going to show you how you can unit test your JavaScript files using nothing but JUnit.

Given the following files:

index.html

<!DOCTYPE html>  
<html>  
    <head>
        <meta charset="ISO-8859-1">
        <title>Index</title>
        <script src="main.js"></script>
        <script src="view.js"></script>
    </head>
    <body>
    </body>
</html>  

main.js

if(!Example) {  
    var Example = function() {
        var that = {
                get stuff() {
                    return stuff;
                }
        };
        var stuff = 1;
        that.incrementStuff = function() {
            ++stuff;
        };
        return that;
    };
}

view.js

(function() {
    window.addEventListener("load", function() {
        var example = Example();
        example.incrementStuff();
        example.incrementStuff();
        example.incrementStuff();
        example.incrementStuff();
        var body = document.querySelector("body");
        var div = document.createElement("div");
        var stuff = example.stuff;
        div.textContent = stuff;
        body.appendChild(div);
    });
})();

When you browse to the index.html file, you should see something like this:

View in browser

I am using Eclipse, and you can add a link to the JavaScript file you want to test like this:

Link file

Place the linked file next to the JUnit test.

Package Explorer

Here is the JUnit test case:

package com._4thex.junit;

import static org.hamcrest.CoreMatchers.equalTo;  
import static org.junit.Assert.assertThat;

import java.io.InputStream;  
import java.io.InputStreamReader;

import javax.script.Invocable;  
import javax.script.ScriptEngine;  
import javax.script.ScriptEngineManager;

import org.junit.Before;  
import org.junit.Test;

public class MainTests {

    private ScriptEngine engine;

    @Before
    public void setUp() throws Exception {
        engine = new ScriptEngineManager().getEngineByName("JavaScript");
        InputStream javaScript = this.getClass().getResourceAsStream("main.js");
        engine.eval(new InputStreamReader(javaScript));
    }

    @Test
    public void test() throws Exception {
        Invocable invocable = (Invocable) engine;
        Object example = invocable.invokeFunction("Example");
        invocable.invokeMethod(example, "incrementStuff");
        engine.put("example", example);
        engine.eval("var stuff = example.stuff;");
        Object stuff = engine.get("stuff");
        assertThat((double)stuff, equalTo(2.0d));
    }

}

We get the JavaScript file in the setUp method using the getResourceAsStream method.

In the test we use the invokeFunction method on the engine cast to an Invocable to call the Example function in the main.js JavaScript file.

Invocable invocable = (Invocable) engine;  
Object example = invocable.invokeFunction("Example");  

Then we call the incrementStuff method on the Example object, using the invokeMethod.

invocable.invokeMethod(example, "incrementStuff");  

Next we define a global variable in JavaScript named example to hold the Example object we just constructed, using the put method on the engine.

engine.put("example", example);  

Now we get the stuff property of Example using the eval and get methods on engine.

engine.eval("var stuff = example.stuff;");  
Object stuff = engine.get("stuff");  

Finally we can assert that the value of the stuff property should be 2 at this point.

assertThat((double)stuff, equalTo(2.0d));  

This is what it looks like when we run the test in Eclipse:
Running the test

You might argue that your JavaScript is harder to test, but it is totally OK to change your JavaScript to make it testable.

Check out the documentation for the javax.script package here: (http://docs.oracle.com/javase/7/docs/api/index.html?javax/script/package-summary.html)

Another good resource is here: (http://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/index.html)

The example here is using Java7, and JUnit 4. There may be differences if you are using Java8.