Problem is that if I do test in Test <<= (taskA, taskB) { (A, B) => A doFinally B or test in Test := (taskB dependsOn taskA).value and taskA is forked, then sbt execution doesn't continue to taskB and get's stuck indefinitely. It's caused by doFinally/dependsOn, because they probably makes it a single-threaded sequential execution. But I can't find any other way to order those 2 tasks, to make them run sequentially.
So far I've gotten this far :
lazy val startServer = taskKey[Unit]("Start PingPong Server before running Scala-JS tests")
lazy val jvm =
     project.in(file("jvm"))
        fork in (Test, runMain) := true
        startServer := {
          (runMain in Test).toTask(" com.example.PingPong").value
        }
      )
lazy val js =
    project.in(file("js"))
       test in Test <<= (startServer in Project("jvm", file("jvm")), test in(Test, fastOptStage)) {
         (startServer, test) => startServer doFinally test
       }
     )
The sbt execution stops on a task startServer that spawns a thread, even a daemon one. I tried fork in startServer := true but it didn't help.
I also tried dependsOn, but it also blocks :
test in Test := {
  (test in(Test, fastOptStage)).dependsOn(startServer in Project("jvm", file("jvm"))).value
}
If I do not start the server in the main class PingPong, it behaves as expected. Also if I do this, it works but it has a random order of execution and I don't know how to enforce it without doFinally.
test in Test := {
  (startServer in Project("jvm", file("jvm"))).value
  (test in(Test, fastOptStage)).value
}
I think I'm gonna have to try sbt-sequential or fork a new process.