Scala.js version of the sbt testing interface that provides a standardized API for test frameworks to integrate with SBT and run tests in a Scala.js (JavaScript) environment
npx @tessl/cli install tessl/maven-org-scala-js--scalajs-test-interface@1.19.0The Scala.js Test Interface provides a standardized API for test frameworks to integrate with SBT and run tests in JavaScript environments compiled by Scala.js. It serves as the bridge between SBT's testing infrastructure and JavaScript-based test execution, enabling test frameworks to define test discovery patterns, execute tests asynchronously, handle test events, and support distributed testing across worker processes.
build.sbt: libraryDependencies += "org.scala-js" %%% "scalajs-test-interface" % "1.19.0"import sbt.testing._For specific components:
import sbt.testing.{Framework, Runner, Task, TaskDef, Event, EventHandler}
import sbt.testing.{Logger, Status, Fingerprint, Selector}import sbt.testing._
import scala.scalajs.reflect.annotation.EnableReflectiveInstantiation
// Implement a test framework
@EnableReflectiveInstantiation
class MyTestFramework extends Framework {
def name(): String = "MyTestFramework"
def fingerprints(): Array[Fingerprint] = Array(
new SubclassFingerprint {
def isModule() = false
def superclassName() = "MyTestSuite"
def requireNoArgConstructor() = true
}
)
def runner(args: Array[String], remoteArgs: Array[String],
testClassLoader: ClassLoader): Runner = {
new MyTestRunner(args, remoteArgs, testClassLoader)
}
def slaveRunner(args: Array[String], remoteArgs: Array[String],
testClassLoader: ClassLoader, send: String => Unit): Runner = {
new MyWorkerRunner(args, remoteArgs, testClassLoader, send)
}
}
// Create and execute test tasks
class MyTestRunner(args: Array[String], remoteArgs: Array[String],
testClassLoader: ClassLoader) extends Runner {
def tasks(taskDefs: Array[TaskDef]): Array[Task] = {
taskDefs.map(taskDef => new MyTask(taskDef))
}
def done(): String = "Tests completed"
// ... other required methods
}The Scala.js Test Interface is built around several key components:
Framework trait with fingerprints for test class identificationRunner manages test lifecycle and creates executable Task instancesEvent and EventHandler provide structured test result reportingslaveRunner enables distributed testing across JavaScript workersexecute methods support both synchronous and asynchronous (continuation-based) executionCore interface for implementing test frameworks with support for test discovery, runner creation, and worker-based distributed testing.
trait Framework {
def name(): String
def fingerprints(): Array[Fingerprint]
def runner(args: Array[String], remoteArgs: Array[String],
testClassLoader: ClassLoader): Runner
def slaveRunner(args: Array[String], remoteArgs: Array[String],
testClassLoader: ClassLoader, send: String => Unit): Runner
}Test execution system providing task creation, lifecycle management, and support for both synchronous and asynchronous JavaScript execution.
trait Runner {
def tasks(taskDefs: Array[TaskDef]): Array[Task]
def done(): String
def remoteArgs(): Array[String]
def args: Array[String]
def receiveMessage(msg: String): Option[String]
def serializeTask(task: Task, serializer: TaskDef => String): String
def deserializeTask(task: String, deserializer: String => TaskDef): Task
}
trait Task {
def tags(): Array[String]
def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[Task]
def execute(eventHandler: EventHandler, loggers: Array[Logger],
continuation: Array[Task] => Unit): Unit
def taskDef(): TaskDef
}Test discovery system using fingerprints to identify test classes through annotations or inheritance patterns.
trait Fingerprint
trait AnnotatedFingerprint extends Fingerprint {
def isModule(): Boolean
def annotationName(): String
}
trait SubclassFingerprint extends Fingerprint {
def isModule(): Boolean
def superclassName(): String
def requireNoArgConstructor(): Boolean
}Event system for reporting test results, progress, and metadata with support for different test selection patterns.
trait Event {
def fullyQualifiedName(): String
def fingerprint(): Fingerprint
def selector(): Selector
def status(): Status
def throwable(): OptionalThrowable
def duration(): Long
}
trait EventHandler {
def handle(event: Event): Unit
}Thread-safe logging interface supporting multiple log levels and ANSI color codes for user-facing messages.
trait Logger {
def ansiCodesSupported(): Boolean
def error(msg: String): Unit
def warn(msg: String): Unit
def info(msg: String): Unit
def debug(msg: String): Unit
def trace(t: Throwable): Unit
}final class TaskDef private (
_fullyQualifiedName: String,
_fingerprint: Fingerprint,
_explicitlySpecified: Boolean,
_selectors: Array[Selector]
) extends Serializable {
def fullyQualifiedName(): String
def fingerprint(): Fingerprint
def explicitlySpecified(): Boolean
def selectors(): Array[Selector]
}
final class OptionalThrowable(exception: Throwable) extends Serializable {
def this()
def isDefined(): Boolean
def isEmpty(): Boolean
def get(): Throwable
}class Status private (name: String, ordinal: Int) extends Enum[Status](name, ordinal)
object Status {
final val Success: Status
final val Error: Status
final val Failure: Status
final val Skipped: Status
final val Ignored: Status
final val Canceled: Status
final val Pending: Status
def values(): Array[Status]
def valueOf(name: String): Status
}abstract sealed class Selector
final class SuiteSelector extends Selector with Serializable
final class TestSelector(testName: String) extends Selector with Serializable {
def testName(): String
}
final class NestedSuiteSelector(suiteId: String) extends Selector with Serializable {
def suiteId(): String
}
final class NestedTestSelector(suiteId: String, testName: String) extends Selector with Serializable {
def suiteId(): String
def testName(): String
}
final class TestWildcardSelector(testWildcard: String) extends Selector with Serializable {
def testWildcard(): String
}