Search code examples
scalasbtscala.jsutest

sbt play cross build project setup: uTest runner doesn't seperate client/server projects correctly


I'm using an build.sbt which has cross compile settings and basically is an adapted version of "Play with scala-js example" and having some trouble getting a clean setup for my tests. Specifically, when running my server tests, my client tests also get executed (which is something that I want to avoid).

I followed the instructions from Cannot get uTest to see my tests and added

libraryDependencies += "com.lihaoyi" %%% "utest" % "0.3.0"

My tests for some reason didn't get executed until I added

testFrameworks += new TestFramework("utest.runner.Framework")

to every project definition. Also not adding

"com.lihaoyi" %% "utest" % "0.3.1" % "test"

to the server side triggers a series of

not found: object utest [error] import utest._ -style errors.

To my impression I shouldn't have to add these additional settings at all if having a clean setup. Here's my sbt file:

import sbt.Project.projectToRef
lazy val clients = Seq(client)
lazy val scalaV = "2.11.7"

lazy val server = (project in file("server")).settings(
  scalaVersion := scalaV,
  scalaJSProjects := clients,
  pipelineStages := Seq(scalaJSProd/*, gzip*/),
  resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases",
  libraryDependencies ++= Seq(
    "com.vmunier" %% "play-scalajs-scripts" % "0.3.0",
    "be.doeraene" %% "scalajs-pickling-play-json" % "0.4.0"
  ),
  testFrameworks += new TestFramework("utest.runner.Framework")
).enablePlugins(PlayScala).
  aggregate(clients.map(projectToRef): _*).
  dependsOn(sharedJvm)

lazy val client = (project in file("client")).settings(
  scalaVersion := scalaV,
  persistLauncher := true,
  persistLauncher in Test := false,
  libraryDependencies ++= Seq(
    "org.scala-js" %%% "scalajs-dom" % "0.8.0"
  ),
  testFrameworks += new TestFramework("utest.runner.Framework")
).enablePlugins(ScalaJSPlugin, ScalaJSPlay).
  dependsOn(sharedJs)

lazy val shared = (crossProject.crossType(CrossType.Pure) in file("shared")).
  settings(scalaVersion := scalaV,
    libraryDependencies ++= Seq(
    "com.lihaoyi" %%% "utest" % "0.3.1",
    "be.doeraene" %%% "scalajs-pickling-core" % "0.4.0",
    "com.lihaoyi" %%% "pprint" % "0.3.6"
    ),
    testFrameworks += new TestFramework("utest.runner.Framework")
  ).

  jsConfigure(_ enablePlugins ScalaJSPlay)
lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js

// loads the Play project at sbt startup
onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value

And here a summary of my problems:

  • when I run client/test, only client tests are executed
  • when running play-with-scalajs-example/test, client + shared tests are executed
  • and strangely when running server/test my server AND client tests are executed

How could I modify my project setup to

  • find my server tests when running server/test
  • running all tests when running play-with-scalajs-example/test
  • and additionally including the shared tests when running server/test or client test?

And on another node, is there a way to disable scalatest? It leads to a rather unreadable testoutput:

[info] 1/2     TestSimpleServerSuite.absolutely simple test on the server side          Success
[info] 2/2     TestSimpleServerSuite            Success
[info] utest
[info] -----------------------------------Results-----------------------------------
[info] 
[info] 
[info] Tests: 0
[info] Passed: 0
[info] Failed: 0
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[info] 1/2     TestSimpleClientSuite.absolutely simple test on the client side          Success
[info] 2/2     TestSimpleClientSuite            Success
[info] 1/2     SimpleClient.TestSimpleClientSuite.absolutely simple test on the client side             Success
[info] 2/2     SimpleClient.TestSimpleClientSuite               Success
[info] ScalaCheck
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] ScalaTest
[info] Run completed in 1 second, 751 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] No tests were executed.
[info] utest
[info] -----------------------------------Results-----------------------------------
[info] SimpleClient.TestSimpleClientSuite               Success
[info]     absolutely simple test on the client side            Success
[info] TestSimpleClientSuite            Success
[info]     absolutely simple test on the client side            Success
[info] 
[info] Tests: 4
[info] Passed: 4
[info] Failed: 0
[info] Passed: Total 4, Failed 0, Errors 0, Passed 4
[success] Total time: 11 s, completed 16.10.2015 03:25:59

Thanks a bunch and kind regards


Solution

  • sjrd's comment about removing aggregate pointed me to right path. Removing it stopped

    server/test
    

    from executing both server and client tests. As sjrd pointed out, the aggregate function used also runs every task that is run on server on the client.

    Aggregation means that running a task on the aggregate project will also run it on the aggregated projects. (See: sbt doc)

    As I also wanted to run shared tests on both client and server project when running test, I modified the aggregate function for the server project definition and added an additional aggregate to the client project definition. :

    Server def.:

    lazy val server = (project in file("server")).settings(
      scalaVersion := scalaV,
      scalaJSProjects := clients,
      pipelineStages := Seq(scalaJSProd/*, gzip*/),
      resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases",
      libraryDependencies ++= Seq(
        "com.vmunier" %% "play-scalajs-scripts" % "0.3.0",
        "be.doeraene" %% "scalajs-pickling-play-json" % "0.4.0",
        "com.lihaoyi" %% "utest" % "0.3.1" % "test"
      ),
      testFrameworks += new TestFramework("utest.runner.Framework")
    ).enablePlugins(PlayScala).
      /*
       * Executes shared tests compiled to JVM with server/test
       */
      aggregate(projectToRef(sharedJvm)). // Former: aggregate(clients.map(projectToRef): _*). before
      dependsOn(sharedJvm)
    

    Client def.:

    lazy val client = (project in file("client")).settings(
      scalaVersion := scalaV,
      persistLauncher := true,
      persistLauncher in Test := false,
      libraryDependencies ++= Seq(
        "org.scala-js" %%% "scalajs-dom" % "0.8.0"
      ),
      testFrameworks += new TestFramework("utest.runner.Framework")
    ).enablePlugins(ScalaJSPlugin, ScalaJSPlay).
      /*
       * Executes shared tests compiled to JS with client/test
       */
      aggregate(projectToRef(sharedJs)).
      dependsOn(sharedJs)
    

    When running tests with play-with-scalajs-example/test now runs all tests, including the shared tests both compiled seperately for JS and JVM.

    As for having to explicitly include the utest dependencies, it seems that client and server projects don't derive from crossProject and are thus disconnected - will look into finding a better way of handling that.