« Three Part Story | Main | BeanShell and finally »

HttpUnit and JavaScript

A little problem I worked through with HttpUnit and the Rhino JavaScript library while writing some automated tests.

Using the stock httpunit-1.6.1 with js-1.5R4.1.jar (the version of js.jar included in the httpunit-1.6.1 jars directory) I ran into an issue testing a site that included some fairly standard JavaScript code:

if (navigator.plugins && navigator.plugins.length) {
// do something that requires a plugin
}

The above code produces a nasty stack trace something along the lines of:

org.mozilla.javascript.EvaluatorException: Invalid JavaScript value of type [Ljava.lang.Object; (httpunit; line 41)
at org.mozilla.javascript.DefaultErrorReporter.runtimeError(DefaultErrorReporter.java:76)
at org.mozilla.javascript.Context.reportRuntimeError(Context.java:591)
at org.mozilla.javascript.Context.reportRuntimeError(Context.java:630)
at org.mozilla.javascript.Context.reportRuntimeError1(Context.java:606)
at org.mozilla.javascript.ScriptRuntime.errorWithClassName(ScriptRuntime.java:2058)
at org.mozilla.javascript.ScriptRuntime.toBoolean(ScriptRuntime.java:119)
at org.mozilla.javascript.gen.c18.call(httpunit:41)
at org.mozilla.javascript.gen.c18.exec(httpunit)
at org.mozilla.javascript.Context.evaluateReader(Context.java:820)
at org.mozilla.javascript.Context.evaluateString(Context.java:784)
at com.meterware.httpunit.javascript.JavaScript$JavaScriptEngine.executeScript(JavaScript.java:132)
at com.meterware.httpunit.scripting.ScriptableDelegate.runScript(ScriptableDelegate.java:65)
at com.meterware.httpunit.ParsedHTML.interpretScriptElement(ParsedHTML.java:325)
at com.meterware.httpunit.ParsedHTML.access$700(ParsedHTML.java:37)
at com.meterware.httpunit.ParsedHTML$ScriptFactory.recordElement(ParsedHTML.java:489)
at com.meterware.httpunit.ParsedHTML$2.processElement(ParsedHTML.java:706)
at com.meterware.httpunit.NodeUtils$PreOrderTraversal.perform(NodeUtils.java:195)
at com.meterware.httpunit.ParsedHTML.loadElements(ParsedHTML.java:722)
at com.meterware.httpunit.ParsedHTML.getFrames(ParsedHTML.java:1034)
at com.meterware.httpunit.WebResponse.getFrames(WebResponse.java:1098)
at com.meterware.httpunit.WebResponse.getFrameRequests(WebResponse.java:875)
at com.meterware.httpunit.FrameHolder.updateFrames(FrameHolder.java:179)
at com.meterware.httpunit.WebWindow.updateFrameContents(WebWindow.java:252)
at com.meterware.httpunit.WebClient.updateFrameContents(WebClient.java:485)
at com.meterware.httpunit.WebWindow.updateWindow(WebWindow.java:146)
at com.meterware.httpunit.WebWindow.getSubframeResponse(WebWindow.java:130)
at com.meterware.httpunit.WebWindow.getResponse(WebWindow.java:121)
at com.meterware.httpunit.WebWindow.updateWindow(WebWindow.java:144)
at com.meterware.httpunit.WebWindow.getSubframeResponse(WebWindow.java:130)
at com.meterware.httpunit.WebWindow.getResponse(WebWindow.java:121)
at com.meterware.httpunit.WebClient.getResponse(WebClient.java:113)
(... additional lines deleted ...)

My first thought was to switch the version of js.jar (aka Rhino) that I was using. I dropped in the latest version which is js-1.6R2.jar. Better, but now it was spitting out a nasty warning to System.err:

RHINO USAGE WARNING: Missed Context.javaToJS() conversion:
Rhino runtime detected object [Ljava.lang.Object;@15db314 of class [Ljava.lang.Object; where it expected String, Number, Boolean or Scriptable instance. Please check your code for missig Context.javaToJS() call.

I decided it was time to do a little digging into the source. I grabbed the source for httpunit and js and popped them into Eclipse. Turns out that httpunit was returning an Object array for plugins, which was causing the above error. The offending method in com.meterware.httpunit.javascript.JavaScript was part of the Window static nested class:

public Object[] jsGet_plugins() {
return new Object[0];
}

I figured upgrading to the latest js.jar was a good thing so I modified JavaScript.java to compile against js-1.6R2.jar (required removing some checked exceptions) while also putting in a fix for the above plugins issue. It was basically:

private ElementArray _plugins = new ElementArray();
public Scriptable jsGet_plugins() {
return _plugins;
}

A quick recompile of the httpunit jar and my tests were happily running again.

Diff of JavaScript.java (I use Eclipse's code formatting which is why there are bunch of other changes)
New version of JavaScript.java

Comments

I've been living with that ugly error message from HttpUnit for sometime now. I got fed up and found your blog. Sure enough, your code above fixed it. Thanks a lot!
Thanks Daniel. Your fix worked out for me too. I had grabbed the latest httpunit.jar (1.7) and that too had the same issue. I hope you have post this issue in the httpunit bug lists so that they fix it in their future versions.