Unit testing in Kotlin/JS


#1

A recent 1.1.4-eap-33 release provides improvements to the core library kotlin.test and the compiler. The changes include out-of-the-box support for Jasmine, Mocha, and Jest, and an experimental way to plug in a custom unit testing framework.

Usage

A simple test might look like so:

package foo
import kotlin.test.*

class Test {
  @Test fun bar() {
    assertEquals(4, 2 * 2)
  }

  @Ignore fun baz() {
    fail("Doesn't work")
  }
}

Mark the test functions with the kotlin.test.Test annotation. To run the tests pass a compiled .js file to a unit testing framework. No configuration is required for supported frameworks. The kotlin-test-js library detects the framework at runtime and uses the corresponding API. The details of using other unit testing framework will be documented later.

The other new annotation is kotlin.test.Ignore. Classes and test functions marked with this annotation are treated as ‘pending’ by the unit testing frameworks (meaning that they don’t execute).

Please check out the sample Gradle projects for QUnit, Jasmine, Mocha, Jest, Karma, frontend-plugin, and Tape. The last one shows how to add support for a custom unit testing framework. To run the tests in each of the sample projects, execute the following command:

./gradlew test

There is also a sample project for IntelliJ IDEA. To run the tests in the IDE you need the Ultimate version with NodeJs plugin installed.

Breaking changes

If you are already using the kotlin-test-js library with QUnit the changes should not affect you except for some rare cases:

  • The QUnitAsserter class has been removed, so the library update will affect your setup if you are using it.
  • Annotation org.junit.Test is deprecated, but still supported. It is a type alias to kotlin.test.Test now. Its parameter name was removed.

Kotlin 1.1.4 EAP
#2

Looking at samples and kjsm files in kotlin-test-js it seem like there is no async test support in api. Please consider adding such api (via callbacks and/or promises), it is essential for js testing.


#3

Your Tape link points to frontend-plugin instead of https://github.com/JetBrains/kotlin-examples/tree/master/gradle/js-tests/tape


#5

Fixed. Thanks!


#6

Nice work, guys! Just a question. Did this test library support asynchronous tests (when we return a promise)?


#7

Hi!

Thanks for moving forward with improving support of unit-testing of Kotlin/JS code.

I’ve been looking through the examples, and ufortunately I cannot find any examples using Maven. Does these improvements only affects Gradle projects?

Regards,
Jørund


#8

Thanks! Asynchronous tests are not supported yet. Feel free to upvoute the feature request


#9

Thanks Jørund! It should work for Maven as well. In order to compile the tests all you need is to have kotlin.test library as a dependency. Afterwards just use the compiled output normally with the testing framework of your choice.


#10

Thank you for your feedback! Please upvote the feature request. Feel free to contribute any particular use-cases and pain points there as well.


#11

As a temporal workaround for asynchronous tests you can do this:

https://github.com/korlibs/korio/commit/66c0799e11ef2907b2c765d326925fbc3b642074#diff-c197962302397baf3a4cc36463dce5eaR97

This reads the original .js file, search for test('...', false, function() { ... }) pattern and replaces it.
If the test function returns a js Promise, it returns it to the JS test framework, if not, it sets to null global.testPromise and then tries to read it before returning the test function.
That allows you to create unit tests that returns Unit/void compatible with junit.

And with an actual fun you can create something compatible with js unit test frameworks + junit.

https://github.com/korlibs/korio/commit/66c0799e11ef2907b2c765d326925fbc3b642074#diff-bfd9c14e9409d2e9178b873330d62eceR322


#12

This doesn’t work well at all with multi-platform builds. As best I can tell, the process of copying modules into the kotlin2js destinationDir breaks other dependent libraries. Is there any support beyond this planned? It all seems very minimally designed and the different libraries and plugins (front-end plugin, etc) don’t work well together at all.


#13

Thank you for the feedback. We are aware of some of the shortcomings, and do intend to fix them. So may I ask you to be a bit more specific, so that we don’t miss something?

What is the use case that’s broken?

Could you provide an example? Also please note that in the examples the modules are copied from kotlin2js destinationDir, not into. Also this is just one possible way to configure tests on Node, there is a number of other options. If you share your case, maybe I could suggest a solution.

Could you expand on this as well?

Sorry for asking so many questions, but unless I understand, how you are using it and what is causing the pain, we won’t be able to take it into account when designing the fix.


#14

@steamstreet Hi! Looking back my questions might have sounded a bit aggressive. Sorry for that =)

I am genuinely interested in the specific things that don’t work well at this moment. I know about some of them - complicated setup (especially multiplatform async tests), non-uniform IDE support, etc. Problem is, most of the feedback comes from our library team, in particular kotlinx.coroutines. That means we might be not aware of some particular problems they have not encountered.

We are planning to have an internal discussion about those in about a week or two. Would you like to share your use cases and pain points, so that we make sure to take them into account?

Also if you miss some features or experience of some other language/framework/etc., you are welcome to share that as well =)