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?
$ 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$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])
Gabriel.