This is a Gradle plugin that adds functionality to the Gradle Scala plugin:
-
compile, run, and test Scala code using JVM, Scala.js, and Scala Native backends
-
shared ("cross-compile") code between backends
-
include sources for specific Scala version
-
run the sbt test frameworks this plugin supports (see Test Frameworks)
-
access Scala backend and Scala version data from the build script.
Plugin integrates with:
-
Gradle test task configuration, test filtering, tagging, logging and reporting
-
IntelliJ test running and reporting
-
IntelliJ Scala plugin to correctly handle sources shared between backends.
Plugin works with:
-
Gradle9.8.1 -
Scala.js1.22.0 -
Scala Native0.5.12 -
Node.js26.10.0.
Plugin:
-
adds necessary backend-specific dependencies
-
adds necessary backend-specific
Scalacompiler plugins (for main and test code) -
adds necessary backend-specific
Scalacompiler parameters -
for
Scala.jsandScala Native, addslinktasks -
for
Scala.js, retrieves and installs the configured version of Node.js -
for
Scala.js, installs the configuredNode.jsmodules usingnpm -
augments the
testtask to run those sbt test frameworks -
includes sources and resources shared between backends
-
includes sources and resources for specific Scala version
-
configures project artifacts to include shared code when needed
-
configures names of the project artifact in accordance with the accepted conventions
-
exposes, via
scalaBackendextension, data about the Scala backend and Scala version for use in the build script.
Plugin is written in Scala 3, but the project that the plugin is applied to can use Scala 3, 2.13 or 2.12; however, plugin is not compatible with Gradle plugins written in Scala 2.12.
Gradle build file snippets below use the Groovy syntax, not the Kotlin one.
Accompanying example project that shows off some of the plugin’s capabilities is available: cross-compile-example.
Three builds cover the usual cases.
Plugin id is org.podval.tools.scalajs.
Previously, id org.podval.tools.scalajs was used; it is still available.
plugins {
id 'org.podval.tools.scala' version '2.3.0'
}
scala.scalaVersion = '3.10.0'
dependencies {
testImplementation scalaBackend.testFramework(org.podval.tools.test.framework.MUnit)
}Do not call useJUnit, useTestNG, or useJUnitPlatform on test.
The plugin registers its own test framework.
Put the backend in gradle.properties (or pass -Porg.podval.tools.backend=js).
build.gradle cannot select it.
See Two extensions named scalaBackend.
org.podval.tools.backend=js
scalaVersion=3.10.0plugins {
id 'org.podval.tools.scala' version '2.3.0'
}
scala.scalaVersion = scalaVersion
link {
moduleInitializers {
main {
className = 'example.Main'
}
}
}./gradlew run links and runs that main class on Node.js.
Backend directories have to be Gradle projects.
The settings plugin includes js, jvm, native, shared, and partial shares such as js-native.
// settings.gradle
plugins {
id 'org.podval.tools.scala.settings' version '2.3.0'
}
scalaBackend.includeBackendProjects()// build.gradle — the mixed project
plugins {
id 'org.podval.tools.scala' version '2.3.0'
}
scala.scalaVersion = '3.10.0'
scalaBackend {
useArtifactSuffix = false
}// js/build.gradle — one backend
dependencies {
testImplementation scalaBackend.testFramework(org.podval.tools.test.framework.MUnit)
}The mixed project’s scalaBackend block only carries useArtifactSuffix.
Each backend project inherits that value.
jvm, js, native, and the dependency helpers exist on the backend project, in js/build.gradle and its siblings.
For a submodule rather than the root, include 'core' before includeBackendProjects().
Plugin is published on the Gradle Plugin Portal; to apply it to a Gradle project:
plugins {
id 'org.podval.tools.scala' version '2.3.0'
}(Plugin id org.podval.tools.scala can also be used.)
Plugin will automatically apply the Scala plugin to the project, so there is no need to manually list id 'scala' in
the plugins block - but there is no harm in it either.
The same project plugin is also published as org.podval.tools.scala.
A settings plugin, org.podval.tools.scala.settings, selects the default backend and can include backend projects.
Apply it in settings.gradle.
This scalaBackend is not the project extension.
See Two extensions named scalaBackend.
plugins {
id 'org.podval.tools.scala.settings' version '2.3.0'
}Project using the plugin has to specify a version of Scala for the Scala Gradle plugin to use.
One way to do it is to add Scala library dependency explicitly, and let the Scala plugin infer the Scala version
from it:
dependencies {
implementation "org.scala-lang:scala3-library_3:3.10.0"
}Another way is to set the Scala version on the Scala plugin’s extension scala, and let the Scala plugin add
appropriate Scala library dependency automatically:
scala.scalaVersion = scalaVersionThe latter approach:
-
is cleaner
-
is the future: the old, inference-based approach is going away (slowly; deprecated in Gradle 9)
-
allows the Scala version to be consistent across the modules of a multi-module project by using a
gradle.propertiesfile:
scalaVersion=3.10.0-
allows the Scala version to be overridden from the command line:
$ ./gradlew -PscalaVersion={version-scala}
Plugin assumes that the project uses the explicit approach; no assumptions are made about the name of the property.
Starting with Scala 3.8.0, the Scala library is built for Java 17.
When the project uses Scala 3.8 or newer, the plugin adds -release:17 to each ScalaCompile task that does not
already set -release or -java-output-version.
Plugin does not support building for multiple Scala versions at the same time using only Gradle (unlike the Gradle Scala Multi-Version Plugin): I believe that "build matrix" belongs in the Continuous Integration tools, not in build tools.
Plugin does provide, in a Gradle-native way, functionality that helps build for different Scala versions one at a time from outside Gradle; see Sources Specific to Scala Version, Scala Backend Extension.
To run tests for specific Scala version (for instance, in a CI pipeline):
./gradlew clean check -PscalaVersion=3.10.0To run tests for multiple Scala versions:
for v in '3.10.0' '2.13.18' '2.12.21'; do ./gradlew clean check -PscalaVersion=$v; doneTo publish artifacts for multiple Scala versions:
for v in '3.10.0' '2.13.18' '2.12.21'; do ./gradlew clean publish -PscalaVersion=$v; doneAlongside the usual Scala source root scala, as in src/main/scala and src/test/scala, plugin includes sources from
Scala source roots specific to the Scala version in use; for Scala version x.y.z, additional Scala source roots are:
-
scala-x.y.z -
scala-x.y -
scala-x.
Similarly, alongside the usual resource root resources, as in src/main/resources and src/test/resources, plugin
includes resources from resource roots specific to the Scala version in use; for Scala version x.y.z, additional
resource roots are:
-
resources-x.y.z -
resources-x.y -
resources-x.
Additional Scala sources and resources are included both in Scala compilation and archives that package Scala sources.
This applies to Scala sources shared between the backends too.
Since only sources and resources appropriate to the Scala version in use are added, to work on the version-specific sources and resources in the IDE, you need to set the Gradle property that selects the Scala version and re-load the project in the IDE.
Plugin automatically adds to various Gradle configurations dependencies needed to support the backend used (if they were not added explicitly).
Unless you want to override versions of some of those dependencies, the only dependencies you need to add to the project are the test framework(s) that you use.
As usual, artifact names have suffixes corresponding to the Scala version: _3, _2.13 or _2.12.
For the artifacts compiled by the non-JVM backends, before the Scala version another suffix indicating the backend is
inserted: for Scala.js - _sjs1, for Scala Native - _native0.5.
A release such as 3.10.0 or 2.13.18 uses that binary suffix.
Any other version uses the full Scala version: 3.8.0-RC1 becomes _3.8.0-RC1, and _sjs1_3.8.0-RC1 or
_native0.5_3.8.0-RC1 on the other backends.
The same string is the Scala suffix in dependency notation.
scalaBinaryVersion stays the binary prefix.
For details on what dependencies are relevant for which backend, see: Scala.js Dependencies, Scala Native Dependencies, Test Frameworks Dependencies.
The name scalaBackend is used twice.
The two objects are not the same type, and an assignment that works on one does nothing, or fails, on the other.
The settings extension is created by org.podval.tools.scala.settings, in settings.gradle.
It has backend (a string: js, jvm, native, or the longer names Scala.js, Scala Native, and JVM) and
includeBackendProjects().
That backend value is the default for a single-backend build.
A project property, including -P, overrides it.
build.gradle runs too late to choose the backend: task classes are already selected.
The project extension is created by the plugin on a project that has one backend.
Its backend property is that backend, already chosen.
Assigning scalaBackend.backend = 'js' in build.gradle does not switch backends.
The booleans jvm, js, and native report the choice.
So do name (JVM, Scala.js, Scala Native) and sourceRoot (jvm, js, native).
On a mixed project the project extension only has useArtifactSuffix.
scalaBackend.jvm on that project fails.
The booleans and the dependency helpers are on js, jvm, and native.
On a single-backend project, the project extension exposes the Scala version and the Scala backend. Build scripts use it to declare dependencies for that backend and that Scala version.
The extension exposes:
-
boolean properties:
jvm,js,native,scala3,nonJvmJUnit4present -
the Scala version:
scalaVersion,scalaBinaryVersion,scala2BinaryVersion -
the backend:
name,sourceRoot,suffix,backendVersion -
testFramework(frameworkClass)andtestFramework(frameworkClass, version), whereframeworkClassis one of the classes listed under Test Frameworks (for exampleorg.podval.tools.test.framework.MUnit) -
scalaDependency(group, artifact, version)andscalaDependency(group, artifact, version, transformer) -
useArtifactSuffix, defaulttrue, controls the suffix of the artifacts this project produces. Set it in the build script, or in anafterEvaluateblock written in that same build script. The plugin reads it at the end of this project’s configuration, after that block, and before other projects can resolve this project’s jar. On a mixed build, set it on the mixed project, in that project’s build script or in itsafterEvaluate. The parent is configured before backend children. Each backend inherits the value. A value in the backend project’s own build script, including itsafterEvaluate, wins. AnafterEvaluateregistered from inside a build-scriptafterEvaluatedoes not quietly lose. The flag is already finalized, and the assignment fails configuration withIllegalStateException(The value for %s is final and cannot be changed any further.). When the value is omitted ortrue, the main jar, the sources jar, and the javadoc jar usesuffix, and a Maven publication whoseartifactIdis still the project name is published with that suffix. When it isfalse, those jars and thatartifactIduse the project name and no suffix. Scala.js and Scala Native jars do not get ajsornativeappendix in either mode.suffixremains the suffix used in dependency notation and does not follow this flag.
scalaBackend {
useArtifactSuffix = false
}Transformer can indicate that a particular dependency is:
-
only available for Scala 3:
scala3() -
only available for Scala 2:
scala2() -
only available for JVM:
jvm() -
a Scala compiler plugin:
scalaCompilerPlugin() -
a compound version such as
3.10.0+1.22.0:versionCompound();
The snippets in the rest of this manual are Groovy.
Kotlin keeps the is prefix that Groovy drops, so the booleans are isJvm, isJs, isNative, and isScala3.
A Scala.js test project.
scalaBackend.backend here is the settings extension.
In build.gradle.kts, scalaBackend is the project extension.
// settings.gradle.kts
plugins {
id("org.podval.tools.scala.settings") version "2.3.0"
}
scalaBackend.backend.set("js")// build.gradle.kts
plugins {
id("org.podval.tools.scala") version "2.3.0"
}
scala {
scalaVersion.set(providers.gradleProperty("scalaVersion"))
}
dependencies {
testImplementation(scalaBackend.testFramework(org.podval.tools.test.framework.MUnit::class.java))
implementation(scalaBackend.scalaDependency("org.scala-js", "scalajs-dom", "2.8.1"))
}scalaDependency’s transformer is a Groovy `Closure, so a Kotlin lambda does not match it.
The three-argument method above is the one to call from Kotlin.
When a transformer is required, pass a KotlinClosure1 that returns the ScalaDependency:
import org.gradle.kotlin.dsl.KotlinClosure1
import org.podval.tools.build.ScalaDependency
scalaBackend.scalaDependency(
"org.scala-js",
"scalajs-library",
"1.22.0",
KotlinClosure1<ScalaDependency, ScalaDependency>({ it.scala2().jvm() })
)The plugin already adds that library dependency. The closure form is for a dependency you declare yourself.
scalaBackend {
useArtifactSuffix.set(false)
}
link {
moduleKind.set("CommonJSModule")
moduleInitializers {
create("main") {
className.set("example.Main")
}
}
}
node {
version.set("26.10.0")
modules.set(listOf("jsdom"))
}On a mixed build, includeBackendProjects() is called on the settings extension:
// settings.gradle.kts
scalaBackend.includeBackendProjects()Plugin can be applied to:
-
JVM-only project (Single Backend: JVM)
-
Scala.jsorScala Nativeproject (Single Backend: Scala.js or Scala Native) -
mixed-backend project with some sources shared between the backends (Mixed backends).
Plugin, its name notwithstanding, provides benefits even if applied to a project that uses only Scala, without Scala.js or Scala Native, namely: the supported sbt test frameworks (see Test Frameworks).
For the list of test frameworks supported by the plugin, see Test Frameworks.
To use the plugin in such a way, build.gradle file for the project, in addition to applying the plugin and setting the
Scala version, needs to list in the dependencies.testImplementation the test framework(s) used.
Configuration of the test task cannot have useJUnit.
Any Gradle plugins providing integration with specific test frameworks must be removed from the project: plugin itself provides integration with test frameworks, in some cases - better than the dedicated test-framework-specific plugins ;)
Sources under src are processed with one specific backend; backend used is selected by the project property
org.podval.tools.backend.
The value of this property is treated as case-insensitive.
Set this property in gradle.properties, or pass it with -P.
Setting it in build.gradle won’t work.
If this property is set to Scala.js or js, Scala.js backend is used.
If this property is set to Scala Native or native, the Scala Native backend is used.
If this property is set to JVM or not set at all, JVM backend is used, making this setup equivalent to the
Single Backend: JVM one.
The same choice can be made on the settings extension scalaBackend, in settings.gradle.
A project property, including one passed with -P, overrides that value.
build.gradle cannot choose the backend: the plugin selects task classes while it is applied, before the rest of the
build script runs.
plugins {
id 'org.podval.tools.scala.settings' version '2.3.0'
}
scalaBackend {
backend = 'js'
}backend in that block is a string on the settings extension.
It is not the project extension’s backend.
See Two extensions named scalaBackend.
For example, to use Scala.js backend for the project, put the following into the gradle.properties file of the
project:
org.podval.tools.backend=jsPlugin supports using multiple backends in the same project with some sources shared between some of them.
This mode is triggered when at least one of the directories containing backend-specific sources - js, jvm, native -
exists.
All backends do not have to be used all the time; with only one backend used, this setup is equivalent to the
Single Backend: Scala.js or Scala Native one (and if that backend is jvm - to the Single Backend: JVM one).
Backend-specific directories must also be included as projects in the settings.gradle file.
After the projects that own those directories are included, scalaBackend.includeBackendProjects() includes each child
directory named js, jvm, native, shared, or a partial share such as js-native.
It does not rename projects.
Call it at the end of settings.gradle.
plugins {
id 'org.podval.tools.scala.settings' version '2.3.0'
}
include 'core'
scalaBackend.includeBackendProjects()When core/js exists, that call includes :core:js.
To share sources (include them in the backend-specific compilation together with the backend-specific sources) between
all the backends, place them in the directory shared - or directly in the src directory of the overall
mixed-backend project; to avoid confusion, only one of those locations should be used, although plugin currently does
not enforce this restriction :)
To share sources between some of the backends (partial sharing), place them in a directory with the name listing the backends the sources are to be shared between:
-
in any order
-
separated by
- -
with optional
shared-prefix -
jvm-js-nativeandshared-jvm-js-nativeare not allowed - usesharedinstead -
shared-jvm,shared-jsandshared-nativeare not allowed - usejvm,js,nativeinstead -
jvm-jvmand other duplicate backend names are not allowed -
js-nativeandnative-jsand other pairs of directories that share sources between the same set of backends are not allowed - pick one ;)
Shared directories must also be included as projects in the settings.gradle file; strictly speaking, they do not
have to be for the Gradle build to work correctly, but for the shared sources to be recognized in IntelliJ they must
be; for simplicity, plugin requires that they always are.
Gradle project names of the subprojects can be changed, but the directory names (js, jvm, native, shared,
js-jvm, shared-js-native) cannot: plugin looks up the subprojects by their directory names, not by their project
names.
Build script for the overall project (or module) is where:
-
plugin is applied
-
Scala version is set
-
useArtifactSuffixis set, once, for every backend project -
any build logic that applies to the overall project resides.
Build scripts in the backend-specific directories are where:
-
backend-specific dependencies (including test frameworks) are added
-
backend-specific tasks (including
linkandtest) are configured -
any build logic that applies only to specific backend resides.
Shared directories hold sources fully or partially shared between the backends.
There is no need (nor point) to have a build.gradle file in any of the shared directories: they are just containers
for the sources shared between the backends.
In this mode, plugin:
-
applies itself to subprojects, backend-specific and shared (so there is no need to apply it manually in the subproject’s
build.gradle) -
propagates the Scala version set in the overall project’s
build.gradleto subprojects (so there is no need to set it manually in the subproject’sbuild.gradle) -
configures appropriate backend for each of the backend-specific subprojects
-
disables all source and archive tasks and unregisters all Scala sources in the overall project
-
disables all tasks in the
sharedsubproject.
Project layout for such setup is:
project (7)
+--- settings.gradle (1)
+--- build.gradle (2)
+--- src (4)
+--- shared
| \--- src (4)
+--- js-jvm
| \--- src (5)
+--- js-native
| \--- src (5)
+--- jvm-native
| \--- src (5)
+--- js
| +--- build.gradle (3)
| \--- src (6)
+--- jvm
| +--- build.gradle (3)
| \--- src (6)
\--- native
+--- build.gradle (3)
\--- src (6)-
settings file where backend-specific and shared subprojects are included
-
build script of the overall project
-
build scripts of the backend-specific projects
-
sources shared between all backends
-
sources shared between some backends
-
sources specific to a backend
-
srchere is shared between all backends, the same role asshared/src. Use one of the two.
Publish from the command line.
When the build runs inside IntelliJ, the plugin adds an implementation dependency from each backend project to its
shared projects so navigation works.
That dependency is written into the POM if you publish from the IDE.
When running on JVM, plugin adds SBT Test Interface org.scala-sbt:test-interface:1.0 to the testRuntimeOnly
configuration: it is used by the plugin to run the tests, and is normally brought in by the test frameworks themselves,
but since ScalaTest does not bring it in, plugin adds it.
dependencies {
testRuntimeOnly 'org.scala-sbt:test-interface:1.0'
}If org.scala-js:scalajs-library dependency is specified explicitly, plugin uses its version for other Scala.js
dependencies that it adds.
Plugin creates scalajs configuration for Scala.js dependencies used by the plugin itself.
The table below lists what is added to what configurations.
| Name | group:artifact | Backend | Configuration | Notes |
|---|---|---|---|---|
Compiler Plugin |
org.scala-js:scalajs-compiler |
JVM Scala 2 |
scalaCompilerPlugins |
only for Scala 2 |
JUnit Compiler Plugin |
org.scala-js:scalajs-junit-test-plugin |
JVM Scala 2 |
testScalaCompilerPlugins |
only for Scala 2 and only if JUnit4 for Scala.js is used |
Linker |
org.scala-js:scalajs-linker |
JVM Scala 2 |
scalajs |
|
Node.js JavaScript environment with JSDOM |
org.scala-js:scalajs-env-jsdom-nodejs |
JVM Scala 2 |
scalajs |
|
Test Adapter |
org.scala-js:scalajs-sbt-test-adapter |
JVM Scala 2 |
scalajs |
|
Scala Library for Scala.js |
org.scala-lang:scala3-library |
Scala.js |
implementation |
only for Scala 3 |
Library |
org.scala-js:scalajs-library |
JVM Scala 2 |
implementation |
|
DOM Library |
org.scala-js:scalajs-dom |
Scala.js |
implementation |
|
Test Bridge |
org.scala-js:scalajs-test-bridge |
JVM Scala 2 |
testRuntimeOnly |
scalaDependency and pluginDependency build the same notations.
The plugin adds these dependencies itself.
The same methods declare a dependency of your own:
dependencies {
implementation scalaBackend.scalaDependency('org.scala-js', 'scalajs-library', '1.22.0', {it.scala2().jvm()}) // sets scalaBackend.backendVersion
implementation scalaBackend.scalaDependency('org.scala-js', 'scalajs-dom', '2.8.1')
if (scalaBackend.scala3) {
implementation scalaBackend.scalaDependency('org.scala-lang', 'scala3-library', scalaBackend.scalaVersion, {it.scala3()})
}
scalajs scalaBackend.pluginDependency('org.scala-js', 'scalajs-linker', scalaBackend.backendVersion, {it.scala2()})
scalajs scalaBackend.pluginDependency('org.scala-js', 'scalajs-sbt-test-adapter', scalaBackend.backendVersion, {it.scala2()})
scalajs scalaBackend.pluginDependency('org.scala-js', 'scalajs-env-jsdom-nodejs', '1.1.1', {it.scala2()})
if (!scalaBackend.scala3) {
scalaCompilerPlugins scalaBackend.scalaDependency('org.scala-js', 'scalajs-compiler', scalaBackend.backendVersion, {it.scala2().scalaCompilerPlugin()})
}
if (!scalaBackend.scala3 && scalaBackend.nonJvmJUnit4present) {
testScalaCompilerPlugins scalaBackend.scalaDependency('org.scala-js', 'scalajs-junit-test-plugin', scalaBackend.backendVersion, {it.scala2().scalaCompilerPlugin()})
}
testRuntimeOnly scalaBackend.scalaDependency('org.scala-js', 'scalajs-test-bridge', scalaBackend.backendVersion, {it.scala2().jvm()})
}To support Scala.js, Scala compiler needs to be configured to produce both the class and sjsir files.
If the project uses Scala 3, all it takes is to pass -scalajs option to the Scala compiler, since Scala 3 compiler has
Scala.js support built in:
tasks.withType(ScalaCompile) {
scalaCompileOptions.with {
additionalParameters = [ '-scalajs' ]
}
}Plugin automatically adds this option to the main and test Scala compilation tasks if it is not present.
If the project uses Scala 2, Scala.js compiler plugin dependency needs to be declared:
dependencies {
scalaCompilerPlugins "org.scala-js:scalajs-compiler_$scalaVersion:1.22.0"
}Plugin does this automatically unless a dependency on org.scala-js:scalajs-compiler is declared explicitly.
If the project uses Scala 2 and JUnit 4 for Scala.js, a JUnit Scala compiler plugin is also needed ([junit4-scalajs-scalanative]):
dependencies {
testScalaCompilerPlugins "org.scala-js:scalajs-junit-test-plugin_$scalaVersion:1.22.0"
}Plugin adds this automatically also.
There is no need to add -Xplugin: Scala compiler parameters for the compiler plugins.
For linking of the main code, plugin adds link task of type
org.podval.tools.scalajs.ScalaJSLinkTask.Main; all
tasks of this type automatically depend on the classes task.
For linking of the test code, plugin adds testLink task of type
org.podval.tools.scalajs.ScalaJSLinkTask.Test; all
tasks of this type automatically depend on the testClasses task.
Link tasks expose a property JSDirectory that points to a directory with the resulting JavaScript, so that it can be,
for example, copied where needed:
link.doLast {
project.sync {
from link.JSDirectory
into jsDirectory
}
}Link tasks have a number of properties that can be used to configure linking. Configurable properties with their defaults are:
link {
optimization = 'Fast' // one of: 'Fast', 'Full'
moduleKind = 'NoModule' // one of: 'NoModule', 'ESModule', 'CommonJSModule'
moduleSplitStyle = 'FewestModules' // one of: 'FewestModules', 'SmallestModules', 'SmallModulesFor'
// when using `specs2` testing framework, '2018' and later is required:
// it supports regular expressions used in many matchers using strings
esVersion = '2015' // one of '2015'..'2026'
smallModulesFor = [] // list of packages; relevant only when moduleSplitStyle = 'SmallModulesFor'
prettyPrint = false
useWebAssembly = false // emit WebAssembly (see below for constraints)
useJSPI = false // enable js.async / js.await (needs a JSPI-capable JS engine)
}Setting optimization to Full enables:
-
Semantics.optimized -
checkIR -
the Closure Compiler, unless
moduleKindisESModule(Closure does not support ES modules, and Scala.js has deprecated this use).
When useWebAssembly = true, the following are required (see https://www.scala-js.org/doc/project/webassembly.html):
-
moduleKind = 'ESModule'-moduleSplitStyle = 'FewestModules'-esVersionof at least'2022'
useJSPI enables Scala.js JSPI (js.async / js.await) and needs a JS engine that supports JSPI.
Environment variables SCALAJS_USE_WEBASSEMBLY and SCALAJS_USE_JSPI can override the defaults.
For ScalaJSLinkTask.Main tasks, a list of module initializers may also be configured:
moduleInitializers {
main {
className = '<fully qualified class name>'
mainMethodName = 'main'
mainMethodHasArgs = false
}
}Name of the module initializer ('main' in the example above) becomes the module id.
Plugin adds run task for running the main code (if it is an application and not a library); this task automatically
depends on the link task.
Additional tasks of type
org.podval.tools.scalajs.ScalaJSRunTask.Main can be
added manually.
Set linkTask to the link task that produces the JavaScript.
The plugin does not look through dependsOn while the task runs.
tasks.register('runDebug', org.podval.tools.scalajs.ScalaJSRunTask.Main) {
linkTask = tasks.named('link')
}link and test are cacheable.
run is not.
Both run and test tasks have a property jsEnv that selects a JavaScript environment to use:
run {
jsEnv = 'Node.js' // one of: 'Node.js', 'Node.js+DOM'
}PhantomJS is not supported: the project has been abandoned since 2018.
Selenium is not supported: the project seems to be abandoned.
Playwright ('io.github.gmkumar2005:scala-js-env-playwright_2.13:{version-scala-js-env-playwright}') is not supported: the project publishes artifacts only for Scala 2.12.
For running Scala.js code and tests, plugin uses Node.js.
Plugin adds node extension to the project.
This extension can be used to specify the version of Node.js to use and Node modules to install:
node {
version = '26.10.0'
modules = []
}If the Node.js version is not specified, the plugin uses the Node.js already installed on the machine, or, if none is
available, installs the default version (26.10.0).
If a version is specified, the plugin installs that version.
That choice is made when nodeSetup runs, not during configuration.
The nodeSetup task installs Node.js and runs npm init and npm install.
run, test, node, and npm depend on nodeSetup.
link does not.
node and npm are not cacheable.
package.json and node_modules stay in the project root.
Node.js distributions are installed under ~/.gradle/nodejs.
If you are using Node.js+DOM JavaScript environment (org.scala-js:scalajs-env-jsdom-nodejs), you need 'jsdom'
module.
To get better traces, one can add source-map-support module.
If package.json does not exist, nodeSetup runs npm init private.
Plugin adds tasks node and npm for executing node and npm commands using the same version of Node.js that is
used by the plugin; those tasks can be used from the command line like this:
./gradlew npm --npm-arguments 'version'
./gradlew node --node-arguments '...'If org.scala-native:scala3lib (for Scala 3) or org.scala-native:scalalib (for Scala 2) dependency is specified
explicitly, plugin uses its version for all the Scala Native dependencies that it adds.
Plugin creates scalanative configuration for Scala Native dependencies used by the plugin itself.
The table below lists what is added to what configurations.
| Name | group:artifact | Backend | Configuration | Notes |
|---|---|---|---|---|
Compiler Plugin |
org.scala-native:nscplugin |
JVM |
scalaCompilerPlugins |
|
JUnit Compiler Plugin |
org.scala-native:junit-plugin |
JVM |
testScalaCompilerPlugins |
only if JUnit4 for Scala Native is used |
Linker |
org.scala-native:tools |
JVM |
scalanative |
|
Test Adapter |
org.scala-native:test-runner |
JVM |
scalanative |
|
Library |
org.scala-native:scala3lib |
Scala Native |
implementation |
only for Scala 3 |
Library |
org.scala-native:scalalib |
Scala Native |
implementation |
only for Scala 2 |
Test Bridge |
org.scala-native:test-interface |
Scala Native |
testRuntimeOnly |
|
Native Library |
org.scala-native:nativelib |
Scala Native |
implementation |
|
C Library |
org.scala-native:clib |
Scala Native |
implementation |
|
Posix Library |
org.scala-native:posixlib |
Scala Native |
implementation |
|
Windows Library |
org.scala-native:windowslib |
Scala Native |
implementation |
|
Java Library |
org.scala-native:javalib |
Scala Native |
implementation |
|
Aux Library |
org.scala-native:auxlib |
Scala Native |
implementation |
scalaDependency and pluginDependency build the same notations.
versionCompound() produces the scalaVersion+nativeVersion form used by scala3lib and scalalib.
The plugin adds these dependencies itself:
dependencies {
if (scalaBackend.scala3) {
implementation scalaBackend.scalaDependency('org.scala-native', 'scala3lib', '0.5.12', {it.scala3().versionCompound()}) // sets scalaBackend.backendVersion
} else {
implementation scalaBackend.scalaDependency('org.scala-native', 'scalalib', '0.5.12', {it.scala2().versionCompound()}) // sets scalaBackend.backendVersion
}
implementation scalaBackend.scalaDependency('org.scala-native', 'nativelib', scalaBackend.backendVersion)
implementation scalaBackend.scalaDependency('org.scala-native', 'clib', scalaBackend.backendVersion)
implementation scalaBackend.scalaDependency('org.scala-native', 'posixlib', scalaBackend.backendVersion)
implementation scalaBackend.scalaDependency('org.scala-native', 'javalib', scalaBackend.backendVersion)
implementation scalaBackend.scalaDependency('org.scala-native', 'windowslib', scalaBackend.backendVersion)
implementation scalaBackend.scalaDependency('org.scala-native', 'auxlib', scalaBackend.backendVersion)
scalanative scalaBackend.pluginDependency('org.scala-native', 'tools', scalaBackend.backendVersion)
scalanative scalaBackend.pluginDependency('org.scala-native', 'test-runner', scalaBackend.backendVersion)
scalaCompilerPlugins scalaBackend.scalaDependency('org.scala-native', 'nscplugin', scalaBackend.backendVersion, {it.scalaCompilerPlugin()})
if (scalaBackend.nonJvmJUnit4present) {
testScalaCompilerPlugins scalaBackend.scalaDependency('org.scala-native', 'junit-plugin', scalaBackend.backendVersion, {it.scalaCompilerPlugin()})
}
testRuntimeOnly scalaBackend.scalaDependency('org.scala-native', 'test-interface', scalaBackend.backendVersion)
}To support Scala Native, Scala compiler needs to be configured to produce both the class and nir files.
The Scala Native compiler plugin dependency needs to be declared:
dependencies {
scalaCompilerPlugins "org.scala-native:nscplugin_$scalaVersion:0.5.12"
}Plugin does this automatically unless a dependency on org.scala-native:nscplugin is declared explicitly.
If the project uses JUnit 4 for Scala Native, a JUnit Scala compiler plugin is also needed ([junit4-scalajs-scalanative]):
dependencies {
testScalaCompilerPlugins "org.scala-native:junit-plugin_$scalaVersion:0.5.12"
}Plugin adds this automatically also.
There is no need to add -Xplugin: Scala compiler parameters for the compiler plugins.
For linking of the main code, plugin adds link task of type
org.podval.tools.scalanative.ScalaNativeLinkTask.Main
; all tasks of this type automatically depend on the classes task.
For linking of the test code, plugin adds testLink task of type
org.podval.tools.scalanative.ScalaNativeLinkTask.Test
; all tasks of this type automatically depend on the testClasses task.
Link tasks expose a property NativeDirectory that points to a directory with the Scala Native Linker output, so that
it can be copied where needed.
Link tasks have a number of properties that can be used to configure linking. Configurable properties with their defaults are:
link {
mode = 'debug' // one of: 'debug', 'release-fast', 'release-size', 'release-full'
lto = 'none' // one of: 'none', 'thin', 'full'
gc = 'immix' // one of: 'none', 'boehm', 'immix', 'commix'
optimize = false
}If not set explicitly, properties are set from the environment variables:
-
mode -
SCALANATIVE_MODE- lto -SCALANATIVE_LTO- gc -SCALANATIVE_GC- optimize -SCALANATIVE_OPTIMIZE
For ScalaNativeLinkTask.Main tasks, property mainClass may also be configured.
This is the class that will be run.
Plugin adds run task for running the main code (if it is an application and not a library); this task automatically
depends on the link task.
Additional tasks of type
org.podval.tools.scalanative.ScalaNativeRunTask.Main
can be added manually.
Set linkTask to the link task that produces the binary.
The plugin does not look through dependsOn while the task runs.
tasks.register('runDebug', org.podval.tools.scalanative.ScalaNativeRunTask.Main) {
linkTask = tasks.named('link')
}link and test are cacheable.
run is not.
Test task added by the plugin is derived from the normal Gradle test task, and can be configured in the traditional
way - with some limitations:
-
plugin applies its own Gradle test framework (
useSbt) to each test task; re-configuring the Gradle test framework (viauseJUnit,useTestNGoruseJUnitPlatform) is not supported -
isScanForTestClassesmust be at its default valuetrue. -
Scala.js and Scala Native tests must run in the same JVM where they are discovered, so they are not forked, and forking configuration is ignored.
Dry run (test.dryRun=true or --test-dry-run command line option) is supported.
Test filtering and tagging are supported to the extent that the individual test frameworks support them; see Test Filtering, Test Tagging and Test Frameworks.
If there is a need to have test runs with different configurations, more testing tasks can be added manually.
For JVM, the type of the test task is
org.podval.tools.jvm.JvmTestTask.
Any such task will automatically depend on the testClasses task (and testRuntimeClassPath).
For Scala.js the type of the test task is
org.podval.tools.scalajs.ScalaJSRunTask.Test.
Such test tasks have to depend on a ScalaJSLinkTask.Test task.
The test task added by the plugin does it automatically; for manually added tasks this dependency has to be added
manually.
For Scala Native the type of the test task is
org.podval.tools.scalanative.ScalaNativeRunTask.Test.
Such test tasks have to depend on a ScalaNativeLinkTask.Test task.
The test task added by the plugin does it automatically; for manually added tasks this dependency has to be added
manually.
Gradle filters tests with three sets of patterns.
includeTestsMatching and excludeTestsMatching are set on the test task.
--tests is the command-line set.
IntelliJ sends two of these patterns: selected.package.* for a package, and fully.qualified.TestClass for a class.
A single test method is fully.qualified.TestClass.test.
Inclusion rules:
-
If neither inclusions nor exclusions are specified, every test is included.
-
If only inclusions are specified, a test must match one of them.
-
If only exclusions are specified, a test must match none of them.
-
If both inclusions and exclusions are specified, a test must match one inclusion and no exclusion.
-
If both the build script and
--testsspecify inclusions, a test must match both.
When both the build script and --tests name test cases, a case is kept only when it satisfies both sides, and two
wildcard patterns that do not contain each other select nothing.
The following patterns specify test classes to run:
-
"*": all tests, just as if no includes are specified -
"*IntegrationTest": classes whose names end with "IntegrationTest" -
"Scala*": classes whose name starts with "Scala" -
"org.podval.tools.test.Scala*": classes in specified package whose name starts with "Scala" -
"org.podval.tools.test.*": tests in specified package (used by IntelliJ Idea, see Testing in IntelliJ) -
"org.podval.tools.test.ScalaTest": tests in specified class (used by IntelliJ Idea, see Testing in IntelliJ).
All these patterns work as intended.
The following patterns specify test cases to run:
-
"org.podval.tools.test.SomeTestClass.success": specified test case in specified class (used by IntelliJ Idea, see Testing in IntelliJ) -
"org.podval.tools.test.SomeTestClass.succ*": test cases whose names start with "succ" in specified class.
How much of a test-case pattern a framework honors is described with that framework below. The sbt selector limits are in the implementation notes.
Names of the tags to include and exclude in the run are specified in:
test {
useSbt {
includeCategories = ["itag1", "itag2"]
excludeCategories = ["etag1", "etag2"]
}
}Inclusion rules are:
-
if no inclusions nor exclusions are specified, all tests are included.
-
if only inclusions are specified, only tests tagged with one of them are included.
-
if only exclusions are specified, only tests not tagged with any of them are included.
-
if both inclusions and exclusions are specified, only tests tagged with one of the inclusions and not tagged with any of the exclusions are included.
When running some test methods explicitly included by a filter, I do not want to see skipped methods mentioned in the test report just as I do not want to see other skipped test classes there.
I do want to see tests explicitly ignored in code (e.g., in ScalaTest, or JUnit4’s falsified assumptions).
During a dry run, though, I want to see everything that was skipped, including test classes that were skipped
entirely; for such, a test case named dry run is reported as skipped.
Some test frameworks have a notion of nested test suites, where nesting test class aggregates nested test classes.
Plugin supports such a scenario and, when test framework involved provides sufficient information about the tests run, attributes test cases from the nested suites to them: test report will have no test cases for the nesting class; instead, test cases will be reported for the nested classes they belong to.
In the following, it is assumed that the IDE is configured to use Gradle to run tests etc.
On JVM, whatever you can run from Idea you can also debug; Scala.js code runs on Node.js, so there is no debugging it - breakpoints have no effect; nor do they on Scala Native.
As with any other Gradle project imported into Idea, you can run Gradle tasks.
IntelliJ lets you run objects with main methods using either:
-
object node in the project tree or - gutter icon in the object’s file
On Scala.js or Scala Native, objects can not be run this way: the code needs to be compiled and linked for the
appropriate backend.
This is what the run task added by the plugin is for.
As usual, when you run tests:
-
results are displayed in tree form - test counts are displayed.
Note: if the test name in the sbt.testing.Event that IntelliJ receives starts with the name of the type the test
belongs to, IntelliJ drops this prefix - probably to accommodate JUnit4, which incorrectly prepends all test names with
the name of their class.
As a result, for frameworks that have a notion of named suite (ZIO Test and ScalaCheck), if the name of the suite is the
same as the name of the type, incorrectly IntelliJ drops it.
As usual, you can run all tests from the project tree using any of the nodes:
<root>
src
test
scalaAs usual, you can run all tests from a package using the package’s node in the project tree. Idea supplies Gradle test filter "selected.package.*".
As usual, you can run individual test class for the frameworks Idea recognizes using either:
-
test’s node in the project tree or - gutter icon in the test’s file
Idea supplies Gradle test filter "fully.qualified.TestClass".
As usual, you can run individual test in a test class for the frameworks Idea recognizes using:
-
gutter icon in the test’s file
Idea supplies Gradle test filter "fully.qualified.TestClass.test".
From the test frameworks this plugin supports, Idea recognizes:
-
JUnit4 - JUnit4 for Scala.js - JUnit4 for Native
Scala plugin for Idea recognizes:
-
MUnit - ScalaTest - Specs2 - uTest
Weaver Test test objects are recognized by IntelliJ as tests (because weaver.RunnableSuite is annotated with
org.junit.runner.RunWith): you get a gutter icon for the test object, which lets you run or debug it, and reflects the
results of the previous run; there are no gutter icons for the individual tests, and even if there were, Weaver Test
ignores test selectors ;)
ScalaCheck and ZIO Test are not recognized by the Scala Plugin: no gutter icon for the test class nor individual
tests in it are available, Run and Debug commands are not available in the context menu of the test classes node in the
Project tree and of the gutter icon of the test class.
Since Hedgehog and ZIO Test tests are objects with main method, they can be run from Idea (on JVM), but there is no
test result tree nor test counts displayed, and since Gradle is not involved, no test reports.
Plugin replaces the test task with one that runs the sbt test frameworks listed below.
A framework that is not in that list is not picked up from the classpath.
Several of the listed frameworks can be used at the same time.
Various test frameworks are listed or recognized by:
| Framework | Recognized by sbt | Recognized by IntelliJ IDEA | Recognized by IntelliJ Scala Plugin | Listed by Scala.js | Works with this Plugin |
|---|---|---|---|---|---|
no |
no |
no |
yes |
yes |
|
no |
no |
no |
yes |
no: defunct |
|
yes |
no |
no |
no |
yes |
|
yes |
yes |
no |
yes |
yes; reimplemented for Scala.js and Scala Native |
|
no |
yes |
no |
no |
no: own test discovery; no point: JVM only |
|
no |
no |
no |
yes |
no: defunct |
|
yes |
yes |
yes |
yes |
||
no |
no |
no |
yes |
no: defunct |
|
yes |
no |
no |
yes |
yes |
|
no |
no |
no |
yes |
yes |
|
yes |
no |
yes |
yes |
yes |
|
no |
no |
no |
yes |
no: defunct |
|
specs |
yes |
no |
no |
no |
no: defunct, use specs2 |
yes |
no |
yes |
no |
yes |
|
no |
yes |
no |
no |
no: SBT interface defunct; no point: JVM only |
|
no |
no |
yes |
yes |
yes |
|
yes |
yes |
no |
no |
yes |
|
yes |
no |
no |
no |
yes |
Framework-specific information for the frameworks that are supported follows.
| Name | group:artifact | Backends | Version | Notes |
|---|---|---|---|---|
JUnit4 |
com.github.sbt:junit-interface |
jvm |
0.13.3 |
Java |
JUnit4 for Scala.js |
org.scala-js:scalajs-junit-test-runtime |
js |
1.22.0 |
Scala 2 |
JUni4 for Scala Native |
org.scala-native:junit-runtime |
native |
0.5.12 |
|
AirSpec |
org.wvlet.airframe:airspec |
jvm, js, native |
2026.2.2 |
Scala Native only on Scala 3 |
Hedgehog |
qa.hedgehog:hedgehog-sbt |
jvm, js, native |
0.15.0 |
|
MUnit |
org.scalameta:munit |
jvm, js, native |
1.3.6 |
|
ScalaCheck |
org.scalacheck:scalacheck |
jvm, js, native |
1.20.0 |
|
Scalaprops |
com.github.scalaprops:scalaprops |
jvm |
0.11.1 |
currently not supported on Scala.js nor Scala Native |
ScalaTest |
org.scalatest:scalatest |
jvm, js, native |
3.2.20 |
|
specs2 |
org.specs2:specs2-core |
jvm, js, native |
5.9.1 |
latest that supports Scala 2: 4.23.0 |
uTest |
com.lihaoyi:utest |
jvm, js, native |
0.9.5 |
|
Weaver Test |
org.typelevel:weaver-cats |
jvm, js, native |
0.13.0 |
|
ZIO Test |
dev.zio:zio-test-sbt |
jvm, js, native |
2.1.26 |
testFramework builds the notation for one of the frameworks above.
Pass the framework class, and optionally a version.
Omit the version to use the version shipped with this plugin:
import org.podval.tools.jvm.JUnit4Jvm
import org.podval.tools.scalajs.JUnit4ScalaJS
import org.podval.tools.scalanative.JUnit4ScalaNative
import org.podval.tools.test.framework.*
dependencies {
if (scalaBackend.jvm) {
testImplementation scalaBackend.testFramework(JUnit4Jvm, '0.13.3')
}
if (scalaBackend.js) {
testImplementation scalaBackend.testFramework(JUnit4ScalaJS, '1.22.0')
}
if (scalaBackend.native) {
testImplementation scalaBackend.testFramework(JUnit4ScalaNative, '0.5.12')
}
if (!scalaBackend.native || scalaBackend.scala3) {
testImplementation scalaBackend.testFramework(AirSpec, '2026.2.2')
}
testImplementation scalaBackend.testFramework(Hedgehog, '0.15.0')
testImplementation scalaBackend.testFramework(MUnit, '1.3.6')
testImplementation scalaBackend.testFramework(ScalaCheck, '1.20.0')
if (scalaBackend.jvm) {
testImplementation scalaBackend.testFramework(Scalaprops, '0.11.1')
}
testImplementation scalaBackend.testFramework(ScalaTest, '3.2.20')
if (!scalaBackend.scala3) {
testImplementation scalaBackend.testFramework(Specs2, '4.23.0')
} else {
testImplementation scalaBackend.testFramework(Specs2, '5.9.1')
}
testImplementation scalaBackend.testFramework(UTest, '0.9.5')
testImplementation scalaBackend.testFramework(WeaverTest, '0.13.0')
testImplementation scalaBackend.testFramework(ZioTest, '2.1.26')
}You do not have to specify test framework versions explicitly; to use the latest versions available at the time the version of the plugin you are using was released, above can be simplified further:
import org.podval.tools.jvm.JUnit4Jvm
import org.podval.tools.scalajs.JUnit4ScalaJS
import org.podval.tools.scalanative.JUnit4ScalaNative
import org.podval.tools.test.framework.*
dependencies {
if (scalaBackend.jvm) {
testImplementation scalaBackend.testFramework(JUnit4Jvm)
}
if (scalaBackend.js) {
testImplementation scalaBackend.testFramework(JUnit4ScalaJS)
}
if (scalaBackend.native) {
testImplementation scalaBackend.testFramework(JUnit4ScalaNative)
}
if (!scalaBackend.native || scalaBackend.scala3) {
testImplementation scalaBackend.testFramework(AirSpec)
}
testImplementation scalaBackend.testFramework(Hedgehog)
testImplementation scalaBackend.testFramework(MUnit)
testImplementation scalaBackend.testFramework(ScalaCheck)
if (scalaBackend.jvm) {
testImplementation scalaBackend.testFramework(Scalaprops)
}
testImplementation scalaBackend.testFramework(ScalaTest)
testImplementation scalaBackend.testFramework(Specs2)
testImplementation scalaBackend.testFramework(UTest)
testImplementation scalaBackend.testFramework(WeaverTest)
testImplementation scalaBackend.testFramework(ZioTest)
}JUnit4 SBT interface (com.github.sbt:junit-interface) is a separate project from JUnit4 itself; SBT interface
dependency brings in the underlying framework dependency junit:junit transitively; its version can be overridden in
the Gradle build script.
-
test filtering: works fine
-
ignoring a test: not supported
-
assumptions: if falsified, result in a test being skipped:
org.junit.Assume.assumeTrue(false);
Tag tests with classes or traits that do not have to be derived from anything JUnit4 -specific; in the Gradle build
file, excludeCategories and includeCategories list fully-qualified names of tagging classes or traits:
trait IncludedTest
trait ExcludedTest
@org.junit.experimental.categories.Category(Array(
classOf[org.podval.tools.test.IncludedTest],
classOf[org.podval.tools.test.ExcludedTest]
))
@Test def excluded(): Unit = ()JUnit4 uses an annotation on the nesting suite to indicate that it contains nested suites:
@org.junit.runner.RunWith(classOf[org.junit.runners.Suite])and another annotation that lists the nested suites:
@org.junit.runners.Suite.SuiteClasses(Array(
classOf[JUnit4Nested]
))For example, JUnit4Nesting contains JUnit4Nested:
@org.junit.runner.RunWith(classOf[org.junit.runners.Suite])
@org.junit.runners.Suite.SuiteClasses(Array(
classOf[JUnit4Nested]
))
class JUnit4Nesting {
}
import org.junit.Test
import org.junit.Assert.assertTrue
final class JUnit4Nested {
@Test def success(): Unit = assertTrue("should be true", true)
@Test def failure(): Unit = assertTrue("should be true", false)
}By default, JUnit4 's sbt framework
ignores the
org.junit.runners.Suite runner; plugin supplies an appropriate argument to enable it.
By default, JUnit4 does not produce summary of the test run; plugin supplies an appropriate argument to enable it.
JUnit4 for Scala.js is a framework distinct from JUnit4: it is a partial translation/re-implementation of JUnit4 circa 2015 and has different capabilities.
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
ignoring tests: not supported
-
assumptions: not supported;
JUnit4 for Scala Native is a framework distinct from JUnit4: it is a port of the JUnit4 for Scala.js, which is a partial translation/re-implementation of JUnit4 circa 2015 and has different capabilities.
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
ignoring tests: not supported
-
assumptions: not supported;
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
assumptions: not supported
-
ignoring a test: not supported;
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
assumptions: not supported
-
ignoring a test: not supported;
-
test filtering: works fine on
JVM; onScala.js, does not support test case selectors and runs all test cases in the class -
nested suites: not supported
-
assumptions: not supported
-
ignoring a test works:
test("test".ignore) {};
MUnit uses JUnit internally, and transitively brings in the underlying framework dependency (whose version can be overridden in the Gradle build script):
-
on JVM -
junit:junit -
on Scala.js -
org.scala-js:scalajs-junit-test-runtime -
on Scala Native -
org.scala-native:junit-runtime.
By default, MUnit does not produce summary of the test run; plugin supplies an appropriate argument to enable it.
MUnit is based on JUnit4, so it supports the Category -based exclusion and inclusion; since on Scala.js MUnit uses
JUnit4 for Scala.js, which does not support this mechanism, MUnit does not support it either.
Plugin does not use Category -based mechanism; MUnit provides a different, Tag -based mechanism, and that is what
plugin uses.
Tag tests with values that are instances of munit.Tag:
val include = new munit.Tag("org.podval.tools.test.ExcludedTest")
val exclude = new munit.Tag("org.podval.tools.test.ExcludedTest")
test("excluded".tag(include).tag(exclude)) {}When tagging classes used for inclusion/exclusion are not available, MUnit crashes with a ClassNotFound.
-
test filtering functionality is not available
-
test tagging: not supported, but if it is used via another test framework - like
ScalaTestorspecs2- test tagging mechanisms provided by that framework can be used -
assumptions: not supported
-
ignoring a test: not supported;
In ScalaCheck, nesting is accomplished by using org.scalacheck.Properties.include():
object ScalaCheckNesting extends org.scalacheck.Properties("ScalaCheckNesting") {
include(ScalaCheckNested)
}
object ScalaCheckNested extends org.scalacheck.Properties("ScalaCheckNested") {
property("success") = org.scalacheck.Prop.passed
property("failure") = org.scalacheck.Prop.falsified
}With ScalaCheck, nested test cases are attributed to the nesting suite - and there is nothing that can be done about it, since ScalaCheck itself does not keep information about which class a property belongs to.
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
assumptions: not supported
-
ignoring a test:
Property.forAll { … }.ignore("…");
-
test filtering: works fine
-
assumptions: not supported
-
ignoring a test:
ignore should "be ignored";
Tag tests with objects that extend org.scalatest.Tag:
object Include extends org.scalatest.Tag("org.podval.tools.test.IncludedTest")
object Exclude extends org.scalatest.Tag("org.podval.tools.test.ExcludedTest")
"excluded" should "not run" taggedAs(Include, Exclude) in { true shouldBe false }-
test filtering: works fine
-
nested suites: not supported
-
assumptions: not supported
-
ignoring a test: not supported;
-
test filtering: does not support test case selectors and runs all test cases in the class.
-
test tagging: not supported
-
assumptions: not supported
-
ignoring a test: not supported;
-
test filtering: does not support test case selectors and runs all test cases in the class
-
test tagging: not supported
-
nested suites: not supported
-
assumptions: not supported
-
ignoring a test: not supported;
-
test filtering: treats specific test case inclusions as wildcards, and instead of running just the named test cases runs all whose names contain the specified string, because the only test case name-based filtering that ZIO Test supports is "search terms", which work as wildcards
-
ignoring a test:
test("ignored") { … } @@ zio.test.TestAspect.ignore -
assumption:
test("assumption") { … } @@ zio.test.TestAspect.ifProp("property")(string ⇒ false)
Tag tests with tag names using TestAspect.tag:
test("tagged") { ... } @@ TestAspect.tag(
"org.podval.tools.test.IncludedTest",
"org.podval.tools.test.ExcludedTest"
)import zio.test._
object ZIOTestNesting extends ZIOSpecDefault {
override def spec: Spec[TestEnvironment, Any] = suite("ZIOTestNesting")(
ZIOTestNested.spec
)
}
object ZIOTestNested extends ZIOSpecDefault {
override def spec: Spec[TestEnvironment, Any] = suite("ZIOTestNested")(
test("success") { assertTrue(1 == 1) },
test("failure") { assertTrue(1 == 0) },
)
}How the plugin is put together, and the history of that work, is in Implementation notes.