Write jest tests as scala classes and run them within sbt without any hassle.
Build against scala-2.12 and scalajs-0.6.22. (scalajs-0.6.22 speeds up test startup)
- To workaround scala.js issue #2635.
- To provide a better test ability against nodejs + jsdom + CommonJS on scala.js.
- That is: test your scala.js-react project just by
sbt test
Prerequisites:
nodejs(probably higher than v8.7.0)package.json, ornpm initto make onenpm install --save-dev jest-cli
See scala.js doc for file path conventions.
Dependency:
libraryDependencies += "com.github.cuzfrog" %%% "sjest" % "0.2.0" % Test
Provide test Framework(to specify client build info):
val myTestFramework: TestFramework = new TestFramework("sjest.JestFramework")
testFrameworks += myTestFramework
testOptions += Tests.Argument(myTestFramework,
s"-opt.js.path:${(artifactPath in Test in fastOptJS).value}")Scala-jest has to know where the *.opt.js file is.
This can also be set through overriding optJsPath in JestFramework (see below).
Write dom test:
import org.scalajs.dom
object MyTest extends sjest.JestSuite {
test("this is a failed test") {
expect(1 + 1).toBe(5)
}
test("dom test") {
val div = dom.document.createElement("div")
div.setAttribute("id","my-id-is-app")
val body = dom.document.body.appendChild(div)
val found = dom.document.getElementById("my-id-is-app")
expect(found).toBe(div)
}
}Write test with shared local variable:
object MyTestWithSharedVariable extends sjest.JestSuite{
private var marker: Int = 0
beforeEach {
marker += 1
}
describe("outer1") {
describe("inner2") {
test("test2-1") {
marker += 1
println("do some test2-1!")
}
}
test("test2-3") {
marker += 1
println("do some test2-3!")
}
}
afterAll {
println(marker) //4
//Note: assertion here is useless, error here simply gets ignored by jest.
}
}Then sbt test or testOnly like you do in any other scala test framework.
You can pass jest configs directly from console:
test -- --bail --verbose
Configs in JestFramework
class JestFramework {
/** *opt.js full path or path relative to sbt root dir. This is prior to args */
protected def optJsPath: String = ""
/** Generated *.test.js full path or path relative to sbt root dir. */
protected def testJsDir: String = "./target/scala-jests/"
/** Yield test command, given a test.js file path. Jest configs can be put here. */
protected def nodejsCmd(jsTestPath: String): NodejsCmd = (jsTestPath: String) =>
NodejsCmd("node_modules/jest/bin/jest.js", js.Array("--colors", "--bail", jsTestPath))
/** Filter jest output in sbt console */
protected def jestOutputFilter: String => String = defaultFilter
}Arguments configs:
-
-opt.js.path:<path>: *opt.js full path or path relative to sbt root dir. This will be overridden ifoptJsPathin JestFramework has been specified. -
-disableAutoRunTestInSbt(default true): Whether to run actual test by'sbt test'. 'jest xx.test.js' is executed for every test, thus worse performance. One could disable it by set this to false, and manually run jest from command line. -
-silentOnPass(default false): Whether to suppress console output when test suite passes.
these will be stripped from arguments before passed to jest
Scala-jest exposes client tests in *opt.js, and generates *.test.js files to call them,
executed by nodejs' child_process, which then triggers jest.
So scala.js is not involved the when testing is running, only the stdout/err shown in sbt console.
A problem is how to share objects/instances between these processes? Like:
object Global{
var shared_in_multiple_TestSuites = ??? //not working...
}The Global object is in limit scope as every test suite is executed in its own process.
Unfortunately, jesting all *.test.js at once is not working too.
Communication between sub-processes is used to realize inter-test-suite sharing(not implemented yet). This also brings the ability to do global setup/teardown.
class JestFramework {
/** Setup before run */
protected def beforeGlobal(): Any = ()
/** Teardown after run */
protected def afterGlobal(stub: Any): Any = stub
}The result returned from beforeGlobal will be passed as a stub to afterGlobal.
- Dom not exists until run in jest,
that means access of
domoutsidetestblock will getNullPointerException. Usedeforlazy valto overcome this problem:
object MyTest extends sjest.JestSuite{
lazy val div = dom.document.createElement("div")
test("dom test"){...access div here}
}Jest facade is from scalajs-jest
Author: Cause Chung ([email protected])
License: Apache License Version 2.0
