ZeroClipboard: TypeError on 'in' keyword

30 views
Skip to first unread message

Gabriel Bezerra

unread,
Apr 14, 2015, 11:12:59 PM4/14/15
to mozill...@googlegroups.com
Hi,

I'm developing with ScalaJS and Rhino is one of the options available there for running tests -- the easiest one, actually. If you are in ScalaJS group, you have probably seen the discussion about this issue in this thread: https://groups.google.com/forum/#!topic/scala-js/aEI-SNfJh2E

I've just started using the ZeroClipboard library in my project and now I can't run JS tests anymore. Can you check whether this is a problem in Rhino or in ZeroClipboard?

This is what is reported in my test output:

$ sbt test
[... JVM tests run fine...]

[trace] Stack trace suppressed: run last scalajs/test:loadedTestFrameworks for the full output.
[error] (scalajs/test:loadedTestFrameworks) Exception while running JS code: TypeError: Can't use 'in' on a non-object. (/home/gabriel/.ivy2/cache/org.webjars/zeroclipboard/jars/zeroclipboard-2.2.0.jar#META-INF/resources/webjars/zeroclipboard/2.2.0/ZeroClipboard.js#223)

The top of the stack trace:

at scala.sys.package$.error(package.scala:27)
at org.scalajs.jsenv.rhino.RhinoJSEnv.org$scalajs$jsenv$rhino$RhinoJSEnv$$internalRunJS(RhinoJSEnv.scala:168)
at org.scalajs.jsenv.rhino.RhinoJSEnv$Runner.run(RhinoJSEnv.scala:60)
at org.scalajs.sbtplugin.FrameworkDetector.detect(FrameworkDetector.scala:64)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$40.apply(ScalaJSPluginInternal.scala:455)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$40.apply(ScalaJSPluginInternal.scala:440)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)

Such exception has not appeared any browser I've used to test my project.

This is the code in Rhino where the exception is being thrown:



* The in operator.
*
* This is a new JS 1.3 language feature. The in operator mirrors
* the operation of the for .. in construct, and tests whether the
* rhs has the property given by the lhs. It is different from the
* for .. in construct in that:
* <BR> - it doesn't perform ToObject on the right hand side
* <BR> - it returns true for DontEnum properties.
* @param a the left hand operand
* @param b the right hand operand
*
* @return true if property name or element number a is a property of b
*/
public static boolean in(Object a, Object b, Context cx)
{
if (!(b instanceof Scriptable)) {
throw typeError0("msg.in.not.object");
}
return hasObjectElem((Scriptable)b, a, cx);
}


This is the code in ZeroClipboard that is making Rhino throw the exception:


/**
* Get the current script's URL.
*
* @returns String or `undefined`
* @private
*/
var _getCurrentScriptUrl = function() {
var jsPath, scripts, i;
if (_document.currentScript && (jsPath = _document.currentScript.src)) {
return jsPath;
}
scripts = _document.getElementsByTagName("script");
if (scripts.length === 1) {
return scripts[0].src || undefined;
}
if ("readyState" in scripts[0]) {
for (i = scripts.length; i--; ) {
if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
return jsPath;
}
}
}
if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) {
return jsPath;
}
if (jsPath = _getCurrentScriptUrlFromError()) {
return jsPath;
}
return undefined;
};

Line 223 is the predicate of the third if statement ("readyState" in scripts[0])

Best regards,
Gabriel.

Harshad RJ

unread,
Apr 15, 2015, 12:59:40 AM4/15/15
to mozill...@googlegroups.com
​Hi,​

On Wed, Apr 15, 2015 at 8:42 AM, Gabriel Bezerra <gabriel...@gmail.com> wrote:

Line 223 is the predicate of the third if statement ("readyState" in scripts[0])

​My hunch is that the `scripts​` array is empty. Hence `scripts[0]` evaluates to `undefined` and the `in` operator correctly throws an exception when its RHS is `undefined`.

This effect may not be happening on ​other browsers because the DOM might be having atleast one `script` element and hence picking a different path of execution. But while running the ScalaJS code, the test harness is probably just evaluating the script by calling rhino API directly (without creating a script tag in the dom).

If my analysis is right, the best solution for the problem might be ​a change in the ZeroClipboard code. It should check the size of the array before using the `in` operator.

For the record, ScalaJS works fine in gngr (a browser powered by Rhino).
​​
​best,​
--

Gabriel Bezerra

unread,
Apr 16, 2015, 1:00:10 AM4/16/15
to mozill...@googlegroups.com
Thanks a lot, Harshad.

Your analysis makes total sense. I've just tried to check the length of the collection before trying to access the element and it worked out.

I'll send a pull request to ZeroClipboard.

Gabriel.
Reply all
Reply to author
Forward
0 new messages