Get hands-on training for JIRA Software, Confluence, and more at Atlassian Summit Europe. Register now ›

For the Atlassian Gadget project, we use JsUnit and Rhino to make Javascript Unit tests running as part of the Atlassian Gadget Maven build. However, the JsUnit could only prints test results onto standard out. And it still seems very hard to fix the jsunit-maven-plugin to use env.js properly. I could wrote an adapter class that intercept the call to Rhino’s main function, and redirect the output to a disk file. (maybe even format it into Surefire xml format.) But it would be nicer to take advantage of the existing JUnit, Surefire, Maven integration.
Based on what we have already, I wrote a special JUnit test case and a runner for it. The runner executes all the JsUnit tests and reports the passing and failure as a JUnit4 test case.
One test for all (Js tests)
The test case uses its own runner and it only has one test function:

@RunWith(RhinoJsUnitRunner.class)
public class RhinoJsUnitTest
{
@Test
public void JsUnitTriggerTest() throws IOException
{
final String path = System.getProperty(“jsunit.entrypoint”);
runJsUnitInRhino(path);
}
}

Calling Rhino
In the runJsUnitInRhino() function, I created a separate process to run Rhino, because Rhino keeps calling System.exit() which terminates the build process. And the benefit of having a separate process is that I can collect the test result in Rhino’s standard output stream. The test result looks like this:

Running com.atlassian.gadgets.test.RhinoJsUnitTest
INFO: [Tue Sep 15 2009 16:15:40 GMT-0700 (PDT)] {ENVJS} adding value to history: file:/Users/scai/Code/AG-svn/trunk/dashboard-plugin/src/test/resources/index.html
INFO: [Tue Sep 15 2009 16:15:40 GMT-0700 (PDT)] {ENVJS} Sucessfully loaded document at file:/Users/scai/Code/AG-svn/trunk/dashboard-plugin/src/test/resources/index.html
Loading tests.
TestRunner (6 test cases available)
> Starting test suite “AllTests”
=> Starting test suite “ParamTest”
— Running test 1: “ParamTest.testStandardMessage”
— Running test 2: “ParamTest.testMessageWithParameters”
Starting test suite “CookieTest”
— Running test 3: “CookieTest.testEraseDefinedCookieSucceed”
— Running test 4: “CookieTest.testValueSaveReadSucceed”
— Running test 5: “CookieTest.testChangeSavedValueSucceed”
— Running test 6: “CookieTest.testValueReadUndefinedCookieGetDefaultValue”
<= Completed test suite "CookieTest"
< Completed test suite "AllTests"
6 tests successful in 0.024 seconds.

Having these information, I can write a simple line parser to retrieve per-test result. Then the next step is to post the pass/fail event to JUnit and they will all be collected by Surefire.
Reporting to JUnit
In order to get the Notifier reference, I override the general JUnit4 runner:

public static class RhinoJsUnitRunner extends BlockJUnit4ClassRunner
{
public RhinoJsUnitRunner(java.lang.Class klass) throws InitializationError
{
super(klass);
}
@Override
public void run(RunNotifier notifier)
{
runNotifier = notifier;
super.run(notifier);
}
}

The new runner intercepts the {{run}} method and saves the notifier reference, so that we could do the following event forwarding:

private static void pass()
{
if(currentTest != null)
{
runNotifier.fireTestFinished(currentTest);
currentTest = null;
}
}
private static void fail(String details)
{
Failure failure = new Failure(currentTest, new RuntimeException(details));
runNotifier.fireTestFailure(failure);
}

That’s all we need to run JsUnit tests as normal JUnit4 tests.
SystemProperty in Maven
There is one tricky part in starting the Rhino Shell. Rhino Shell evaluates scripts either from a given file path or from the standard input. We have to use the file path, because our “test.js” is only an entry point. It loads in more Javascript files using eval() method. Using standard input will require merging all the required Javascript into one big file.
In order to tell JUnit where to find our entry point, I had to explicitly configure the Surefire plugin in the pom.xml to store the path onto system properties.

maven-surefire-plugin

jsunit.entrypoint
${basedir}/src/test/javascript/test.js

junit:junit-dep

I tried setting the value inside the Maven Properties subtree, but the value was not passed to JUnit. It’s only available to references within the pom.xml.
Now, the JsUnit tests are running like normal JUnit4 tests.
jsunit.png

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now