From 8b14f4b15c20b7fe40b1b337dde5084ab4e60077 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 16 Dec 2022 19:06:19 +0100 Subject: [PATCH] [Wasm] Mocha test framework support --- .../kotlin/kotlin/test/JasmineLikeAdapter.kt | 40 ++++++++++++++++--- .../src/main/kotlin/kotlin/test/TestApi.kt | 15 +++++-- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt index 8f72b624a80..7e95e835a5e 100644 --- a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt +++ b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt @@ -6,19 +6,29 @@ package kotlin.test import kotlin.test.FrameworkAdapter +import kotlin.js.Promise // Need to wrap into additional lambdas so that js launcher will work without Mocha or any other testing framework @JsFun("(name, fn) => describe(name, fn)") -internal external fun describe(name: String, fn: () -> Unit) +private external fun describe(name: String, fn: () -> Unit) @JsFun("(name, fn) => xdescribe(name, fn)") -internal external fun xdescribe(name: String, fn: () -> Unit) +private external fun xdescribe(name: String, fn: () -> Unit) @JsFun("(name, fn) => it(name, fn)") -internal external fun it(name: String, fn: () -> Any?) +private external fun it(name: String, fn: () -> Any?) @JsFun("(name, fn) => xit(name, fn)") -internal external fun xit(name: String, fn: () -> Any?) +private external fun xit(name: String, fn: () -> Any?) + +@JsFun("(e) => { throw e }") +private external fun jsThrow(jsException: Dynamic) + +@JsFun("(message, stack) => { const e = new Error(); e.message = message; e.stack = stack; return e; }") +private external fun throwableToJsError(message: String, stack: String): Dynamic + +private fun Throwable.toJsError(): Dynamic = + throwableToJsError(message ?: "", stackTraceToString()) /** * [Jasmine](https://github.com/jasmine/jasmine) adapter. @@ -33,11 +43,29 @@ internal class JasmineLikeAdapter : FrameworkAdapter { } } + private fun callTest(testFn: () -> Any?): Any? = + try { + (testFn() as? Promise<*>)?.catch { exception -> + val jsException = exception + .toThrowableOrNull() + ?.let { it.toJsError() } + ?: exception + Promise.reject(jsException) as Dynamic + } + } catch (exception: Throwable) { + jsThrow(exception.toJsError()) + null + } + override fun test(name: String, ignored: Boolean, testFn: () -> Any?) { if (ignored) { - xit(name, testFn) + xit(name) { + callTest(testFn) + } } else { - it(name, testFn) + it(name) { + callTest(testFn) + } } } } \ No newline at end of file diff --git a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/TestApi.kt b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/TestApi.kt index a91e5d5c71a..79372f97692 100644 --- a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/TestApi.kt +++ b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/TestApi.kt @@ -30,14 +30,23 @@ internal fun setAdapter(adapter: FrameworkAdapter) { */ internal fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) { - currentAdapter.suite(name, ignored, suiteFn) + adapter().suite(name, ignored, suiteFn) } internal fun test(name: String, ignored: Boolean, testFn: () -> Any?) { - currentAdapter.test(name, ignored, testFn) + adapter().test(name, ignored, testFn) } -internal var currentAdapter: FrameworkAdapter = TeamcityAdapter() +internal var currentAdapter: FrameworkAdapter? = null + +@JsFun("() => typeof describe === 'function' && typeof it === 'function'") +private external fun isJasmine(): Boolean + +internal fun adapter(): FrameworkAdapter { + val result = currentAdapter ?: if (isJasmine()) JasmineLikeAdapter() else TeamcityAdapter() + currentAdapter = result + return result +} // This is called from the js-launcher alongside wasm start function @JsExport