Generates JUnit bootstrapper objects for Scala.js.
On the JVM, JUnit uses run-time reflection to list and invoke JUnit-related
methods. They are identified by annotations such as @Test
, @Before
,
etc. In Scala.js, there is no such reflection for methods and annotations,
so a different strategy is used: this phase performs the necessary
inspections at compile-time, and generates a so-called bootstrapper object
where all those metadata have been reified.
With an example: given the following JUnit test class:
class MyTest {
@Before def myBefore(): Unit = ...
@Before def otherBefore(): Unit = ...
@Test def syncTest(): Unit = ...
@Test def asyncTest(): Future[Try[Unit]] = ...
@Ignore @Test def ignoredTest(): Unit = ...
}
object MyTest {
@AfterClass def myAfterClass(): Unit = ...
}
this phase generates the following bootstrapper module class:
object MyTest$scalajs$junit$bootstrapper extends Object with Bootstrapper {
def beforeClass(): Unit = {
// nothing, since there is no @BeforeClass method in object MyTest
}
def afterClass(): Unit = {
MyTest.myAfterClass()
}
def before(instance: Object): Unit = {
// typically 0 or 1, but also support 2 or more
instance.asInstanceOf[MyTest].myBefore()
instance.asInstanceOf[MyTest].otherBefore()
}
def after(instance: Object): Unit = {
// nothing, since there is no @After method in class MyTest
}
def tests(): Array[TestMetadata] = Array(
new TestMetadata("syncTest", false, new org.junit.Test()),
new TestMetadata("asyncTest", false, new org.junit.Test()),
new TestMetadata("ignoredTest", true, new org.junit.Test()),
)
def invokeTest(instance: Object, name: String): Future[Unit] = {
val castInstance: MyTest = instance.asInstanceOf[MyTest]
if ("syncTest".equals(name))
Future.successful(scala.util.Success(castInstance.syncTest()))
else if ("asyncTest".equals(name))
castInstance.asyncTest() // asyncTest() already returns a Future[Try[Unit]]
else if ("ignoredTest".equals(name))
Future.successful(scala.util.Success(castInstance.ignoredTest()))
else
throw new NoSuchMethodException(name)
}
def newInstance(): Object = new MyTest()
}
Note that the support for test methods returning Future
s is specific to
Scala.js, and not advertised as a public feature. It is necessary to test
some things in Scala.js itself, but outside users should use a testing
framework with official asynchronous support instead.
Because Booststrapper
is annotated with @EnableReflectiveInstantiation
,
the run-time implementation of JUnit for Scala.js can load the bootstrapper
module using scala.scalajs.reflect.Reflect
, and then use the methods of
Bootstrapper, which are implemented in the bootstrapper object, to perform
test discovery and invocation.
TODO At the moment, this phase does not handle @Test
annotations with
parameters, notably the expected exception class. This should be handled at
some point in the future.
- Companion:
- object
Value members
Concrete methods
Inherited methods
Can this transform change the base types of a type?
Can this transform change the base types of a type?
- Inherited from:
- Phase
Can this transform create or delete non-private members?
Can this transform create or delete non-private members?
- Inherited from:
- Phase
Can this transform change the parents of a class?
Can this transform change the parents of a class?
- Inherited from:
- Phase
Check what the phase achieves, to be called at any point after it is finished.
Check what the phase achieves, to be called at any point after it is finished.
- Inherited from:
- Phase
The sequence position of this phase in the given context where 0 is reserved for NoPhase and the first real phase is at position 1. -1 if the phase is not installed in the context.
The sequence position of this phase in the given context where 0 is reserved for NoPhase and the first real phase is at position 1. -1 if the phase is not installed in the context.
- Inherited from:
- Phase
Output should be checkable by TreeChecker
Output should be checkable by TreeChecker
- Inherited from:
- Phase
Is this phase the standard typerphase? True for TyperPhase, but not for other first phases (such as FromTasty or Parser). The predicate is tested in some places that perform checks and corrections. It's different from ctx.isAfterTyper (and cheaper to test).
Is this phase the standard typerphase? True for TyperPhase, but not for other first phases (such as FromTasty or Parser). The predicate is tested in some places that perform checks and corrections. It's different from ctx.isAfterTyper (and cheaper to test).
- Inherited from:
- Phase
If set, use relaxed typing for all phases in group
If set, use relaxed typing for all phases in group
- Inherited from:
- MiniPhase
List of names of phases that should precede this phase
List of names of phases that should precede this phase
- Inherited from:
- Phase
List of names of phases that should have finished their processing of all compilation units before this phase starts
List of names of phases that should have finished their processing of all compilation units before this phase starts
- Inherited from:
- MiniPhase
Transform tree using all transforms of current group (including this one)
Transform tree using all transforms of current group (including this one)
- Inherited from:
- MiniPhase
Transform single node using all transforms following the current one in this group
Transform single node using all transforms following the current one in this group
- Inherited from:
- MiniPhase
Transform tree using all transforms following the current one in this group
Transform tree using all transforms following the current one in this group
- Inherited from:
- MiniPhase