Unable to use futures in scala.js - Rhino was unable to load the scala.js class
When I use futures in Scala.js, at least in tests, they never get executed and I can't wait for them.
Given this simple test:
package example
import utest._
import utest.framework.{Test, TestSuite}
import utest.util.Tree
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
import scala.language.postfixOps
import scala.scalajs.concurrent.JSExecutionContext.Implicits.queue
object SomeFutureTest extends TestSuite {
override def tests: Tree[Test] =
TestSuite {
'runs_future {
val eventualString: Future[String] = Future[String] {
"foo"
}
Await.result(eventualString, 5 seconds)
}
}
}
when i run test
on sbt console i get:
JavaException: org.scalajs.jsenv.rhino.ScalaJSCoreLib$ClassNotFoundException:
Rhino was unable to load Scala.js class: ju_concurrent_locks_AbstractQueuedSynchronizer
when i do a nasty hack instead of Await
this:
while(!future.isCompleted) {}
it works forever.
Doesn't Await work in Scala.js? Can't you use futures and Await
their results in tests?
EDIT: it works with scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
instead queue
, but this calls futures in sync.
source to share
Really Await
doesn't work in Scala.js. It cannot, since it is a blocking API and there is no such thing as blocking in the JS framework.
For this reason, test environments are supported in a Future
special way by allowing the test itself to return Future
its execution. The test framework is then responsible for maintaining the asynchrony until the final display of the unit test results.
As documented in its Readme , uTest supports this. In your case, this will give:
TestSuite {
'runs_future {
val eventualString: Future[String] = Future[String] {
"foo"
}
for (theString <- eventualString) yield {
assert(theString == "foo")
// and/or:
theString
}
}
}
If you're more comfortable with the notation map
, here's the equivalent:
TestSuite {
'runs_future {
val eventualString: Future[String] = Future[String] {
"foo"
}
eventualString map { theString =>
assert(theString == "foo")
// and/or:
theString
}
}
}
source to share