19

I'm using SBT with Play Framework.

I created a custom TaskKey to run JavaScript tests in my project:

import sbt._
import sbt.Process._
import PlayProject._

object ApplicationBuild extends Build {

  val testJsTask = TaskKey[Unit]("testJs", "Run javascript tests.") := {}

  val main = PlayProject("xxx", 1.0, Seq())
    .settings(defaultScalaSettings: _*)
    .settings(testJsTask)
}

So far so good.

I want to run this testJsTask always when someone executes the test task.

I guess it should be something as follows:

test in Test <<= (test in Test).dependsOn(testJsTask)

I've no idea how it should be defined exactly. How to add a dependency to an existing task like 'test' or 'build'?

UPDATE

After changes proposed by @Christian the build definition looks as follows:

object ApplicationBuild extends Build {
  val testJsTask = TaskKey[Unit]("testJs", "Run tests for javascript client.")
  def testJs = {}

  val main = PlayProject("xxx", 1.0, Seq())
    .settings(defaultScalaSettings: _*)
    .settings(testJsTask := testJs)

  (test in Test) <<= (test in Test) dependsOn (testJs)
}

Unfortunately, the solution doesn't work either:

[error] /xxx/project/Build.scala:21: not found: value test
[error]   (test in Test) <<= (test in Test) dependsOn (testJs)
[error]    ^
[error] one error found
[error] {file:/xxx/project/}default-f468ae/compile:compile: Compilation failed
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
Piotr Kukielka
  • 3,792
  • 3
  • 32
  • 40

3 Answers3

14

This is one way to do it:

Define the task key:

val testJsTask = TaskKey[Unit]("testJs", "Run javascript tests.")    

Define the task in your projects settings:

testJsTask <<= testJs

Make test dependent on it:

(test in Test) <<= (test in Test) dependsOn (testJs)

testJs can be defined as follows:

  def testJs = (streams) map { (s) => {
    s.log.info("Executing task testJs")
    // Your implementation
  }

[EDIT] You have to define the task dependencies within the projects settings. For a "normal" project, you would do it the following way:

  lazy val testProject = Project(
    "testProject",
    file("testProject"),
    settings = defaultSettings ++ Seq(
      testJsTask <<= testJs,
      (test in Test) <<= (test in Test) dependsOn (testJsTask)
    )
  )
Christian
  • 4,543
  • 1
  • 22
  • 31
  • 1
    Somehow this looks wrong on incomplete to me. What I want to do is ensure, that when someone will run 'test' command, then except all other test it will execute also testJs. Also I see you didn't used ':= ' symbol at all, which I know is needed when building Tasks - or am I wrong?. EDIT: I see your edit, now it starts to make more sense, I'll try it right away ;) – Piotr Kukielka Dec 19 '11 at 07:13
  • 1
    You can directly define a task with :=. I prefer the other possibility, because then I can separate the task keys from the actual tasks. – Christian Dec 19 '11 at 07:19
  • I still have the same problem as before: Build.scala:19: not found: value test. [error] (test in Test) <<= (test in Test) dependsOn (testJsTask) – Piotr Kukielka Dec 19 '11 at 07:19
  • Could you post your current build script? – Christian Dec 19 '11 at 07:20
  • I never used the play framework, but maybe a PlayProject does not have (test in Test)? – Christian Dec 19 '11 at 07:27
  • In PlayProject source code I don't see any changes for tests unlucky (btw. https://github.com/playframework/Play20/wiki/SettingsSBT). Also, I edited my first post. – Piotr Kukielka Dec 19 '11 at 07:33
  • This answer is outdated. As of SBT 1.1.0-RC1, the key line to make `test` dependent on `testJs` should be: `(Test / test) := ((Test / test) dependsOn testJs).value` – arussell84 Dec 05 '17 at 13:36
13

Play 2.2.x uses SBT 0.13 (see What’s new in Play 2.2). That brings some new means of composing tasks in build.sbt itself (without resorting to a Scala file in project/ subdirectory).

If you happen to use Play 2.2.x you could define the dependency between the tasks in build.sbt as follows:

lazy val testJsTask = taskKey[Unit]("Run JavaScript tests.")

testJsTask := {
  println("Running JavaScript tests...")
  java.util.concurrent.TimeUnit.SECONDS.sleep(3)
  println("...done.")
}

test in Test := {
  testJsTask.value
  (test in Test).value
}

See Tasks in the official documentation of SBT for more details.

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
  • 1
    Does this run the tasks sequentially or in concurrently? – sksamuel Aug 13 '14 at 16:30
  • Sequentially. First testJsTask, then test task. – htomek Jan 21 '16 at 10:14
  • 3
    As far is I understand this is not correct @htomek http://www.scala-sbt.org/release/docs/Custom-Settings.html#Execution+semantics+of+tasks Use `Def.sequential()` to run tasks in order http://www.scala-sbt.org/release/docs/Howto-Sequencing.html – trudolf Jan 24 '17 at 05:39
0

For me using dependsOn syntax didn't work. Instead I used tests' setup functionality of sbt.

With your example it would be something like the following:

val testJsTask = TaskKey[Unit]("testJs", "Run javascript tests.")

testJsTask := {
  // ...whatever logic
}

// then inside your project settings
Test / testOptions += Tests.Setup(() => testJsTask.value)

Please notice the .value at the end. Without it would be referencing function without invoking it.

vasigorc
  • 882
  • 11
  • 22