Wow. Getting tests to run for a JS target in a mu...
# multiplatform
n
Wow. Getting tests to run for a JS target in a multiplatform project is difficult: it’s not documented, and there are no examples in the kotlin-examples repo, and Gradle is opaque even with a Kotlin build script. Anyone got a small example of a multiplatform project that runs the tests for both the JVM and JS platforms?
💯 2
i
n
Thanks. That’s not exactly a small example, though. What am I meant to look at in there?
There are lots of dependencies and plugins added to that project.
i
it's pretty small as far as practical examples ago. look at the usage of
id 'com.github.salomonbrys.gradle.kotlin.js.mpp-tests.node'
in the plugins and then the JS configuration block in the targets
Copy code
fromPreset(presets.js, 'js') {
            tasks[compilations.main.compileKotlinTaskName].kotlinOptions.moduleKind = "umd"
            kotlinJsNodeTests {
                thisTarget(js) {
                    engine = mocha
                }
            }
            mavenPublication {
                artifactId = 'arbor-js'
            }
        }
n
Do you know of a minimal example project? E.g. just using kotlin-multiplatform plugin?
i
that's not really possible
n
Why?
i
you can't run tests without an environment to run tests in and kotlin is unopinionated about platform targets
in this project I'm using node to run the tests
n
Obvs…
to run the tests for the JVM, I use the JVM. To run the tests for JS I use Node. That’s not a problem.
i
right, that's the example of how to do it then unless you want to manually write all the tasks to do things like grab node, set it up, copy the tests, run the node tasks, process the unit tests, etc
kotlin mpp does not provide any facilities for testing js
n
Is the stuff that com.github.salomonbrys.gradle.kotlin.js.mpp-tests.node does going to be supported by kotlin-multiplatform?
i
no, much like they don't support running android test or ios tests. They may suggest how to do it but that's not inside the scope of mpp itself
jvm only works because the kotlin plugin already wires that up so mpp gets it for free
for instance, how do you run tests for wasm or arm generated code? They are unopinionated about those as well.
n
I don’t care about it’s opinion. I’d be happy it provided convenient defaults, and the ability to target different configuraitons — just like it does with the JVM. By default it runs on JUnit, but I can configure the test framework, the JVM version it uses, etc.
i
yes because kotlin (jvm) has an opinion on testing, mpp does not
n
But the Kotlin JS compiler does have an opinion on testing. More so than the Kotlin JVM compiler, because test code is targetted to the test framework by the compiler
“main” and “test” modules generate quite different JS
i
kotlin examples are the same thing im showing you https://github.com/JetBrains/kotlin-examples/blob/master/gradle/js-tests/qunit/build.gradle that is use the gradle node plugin which
com.github.salomonbrys.gradle.kotlin.js.mpp-tests.node
builds upon (it uses that same plugin)
kotlin js is not opinionated about testing they just have an example showing how you could do it
n
Yeah. I’m using the gradle node plugin.
i
right, that's not jetbrains though
n
Sure. But it’s more active and has more developers than the mpp-tests.node plugin. The worry is, when mpp evolves, will mpp-tests.node keep up? It’s a hard sell.
i
More so than the Kotlin JVM compiler, because test code is targetted to the test framework by the compiler
that's not the case, you define amd/umd/js but qunit and others are what you are passing to the node plugin
all that plugin does is copy the files for you and place them into the correct spots. You don't have to use it. Much like all the node plugin does is provide some convenience but it doesn't really do anything magical other than give some easy configuration.
n
I mean… if I compile a Kotlin module, it gets compiled to plain ol’ JS functions if it’s a main module, and to test code if it’s a test module.
The output is quite different.
“all that plugin does is copy the files for you and place them into the correct spots. You don’t have to use it.” <-- Agreed. That’s what I’m looking for examples of.
i
Read the plugin code then, it breaks down to basically 3 gradle tasks. Copying the files, configuration of node, running the tests. Basically the same thing as that kotlin js project I linked but modified for the requirements of the mpp task graph and outputs.
g
This is example without additional plugins (except node, also see root build.gradle, there are test dependencies for js): https://github.com/gildor/knel/blob/master/js-test.gradle
It based on some example from @Deactivated User, but I couldn't find original repo Also, I would say that I agree, that It would be great to have support of popular test frameworks for JS out of the box (or even only 1 particular) with browser and node targets to run tests. Because now it's quite cumbersome to configure
i
I would like to see official support but outside of the MPP plugin. As an Android dev I'm extremely weary of "do everything" plugins.
g
But how do you want do this without plugin?
Plugin is just a way to extend features of Gradle, this is whole point of Gradle and any other build tool
i
As separate plugins as it is now
g
Yes, it can be additional plugin, one per each test framework, I agree
But this plugin still should have some integreation with MPP or/and with kotlin.platform.js plugin
i
Sure and we have that right now
It's not jetbrains but it works fine short of code coverage
n
@gildor Thanks — that’s exactly what I’m looking for.
A quick question: why does the build file use
kotlin.targets.fromPreset(presets.jvm, "jvm")
etc. instead of
jvm("jvm")
, etc.?
The documentation shows the latter syntax, but I’ve seen a number of projects on GitHub that use the former syntax. Is there a reason why?
g
The later is new DSL, from 1.3.20 I believe
n
That explains it. Thanks again.
g
New MPP is under active development, so a lot of things could changed
n
Yes. Unfortunately your js test tasks don’t work in 1.3.21. I’m back to the same error that made me start this thread.
That’s the risk of being on the bleeding edge 😄
g
what kind error do you have?
n
Copy code
A problem occurred evaluating script.
> Cannot access first() element from an empty Iterable
From the argument passed to Mocha:
relativePath("${jsCompilations.test.output.classesDirs.first()}/${project.name}_test.js")
I’ll clone your project and see if it builds when I upgrade the kotlin mpp version
g
Yeah, something changed in task output
n
The error could well be caused by other funky stuff in my build
I’ve got it running the tests (and failing where behaviour differs from the JVM, which is great). Thanks for your help
I had to change the argument to Mocha to be
relativePath(jsCompilations.test.output.allOutputs.first()) + "/${project.name}_test.js"
And found that I’d not specified the module type for generated JS modules. I assumed it would default to UMD, and that UMD would be compatible with CommonJS, but unless I specified “umd” for the main JS module and “commonjs” for the test JS module, Mocha would not find the kotlin stdlib when running the tests.
No idea why. It’s just magic to me at this point.
g
By default there is no module system, so it make sense
n
Ah. That does make sense.
Thanks all. I now have a passing build on both JVM and JS platforms. https://travis-ci.org/npryce/hamkrest/builds/495569560
👍 1