Fix Promise.await() never resuming if the promise rejected with a non-Throwable (#4120)
diff --git a/kotlinx-coroutines-core/js/src/Promise.kt b/kotlinx-coroutines-core/js/src/Promise.kt
index f84338a..5eb93d3 100644
--- a/kotlinx-coroutines-core/js/src/Promise.kt
+++ b/kotlinx-coroutines-core/js/src/Promise.kt
@@ -63,5 +63,5 @@
public suspend fun <T> Promise<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
this@await.then(
onFulfilled = { cont.resume(it) },
- onRejected = { cont.resumeWithException(it) })
+ onRejected = { cont.resumeWithException(it as? Throwable ?: Exception("Non-Kotlin exception $it")) })
}
diff --git a/kotlinx-coroutines-core/js/test/PromiseTest.kt b/kotlinx-coroutines-core/js/test/PromiseTest.kt
index 319778d..f9cb0ed 100644
--- a/kotlinx-coroutines-core/js/test/PromiseTest.kt
+++ b/kotlinx-coroutines-core/js/test/PromiseTest.kt
@@ -83,4 +83,27 @@
if (seq != 1) error("Unexpected result: $seq")
}
}
+
+ @Test
+ fun testAwaitPromiseRejectedWithNonKotlinException() = GlobalScope.promise {
+ lateinit var r: (dynamic) -> Unit
+ val toAwait = Promise<dynamic> { _, reject -> r = reject }
+ val throwable = async(start = CoroutineStart.UNDISPATCHED) {
+ assertFails { toAwait.await() }
+ }
+ r("Rejected")
+ assertContains(throwable.await().message ?: "", "Rejected")
+ }
+
+ @Test
+ fun testAwaitPromiseRejectedWithKotlinException() = GlobalScope.promise {
+ lateinit var r: (dynamic) -> Unit
+ val toAwait = Promise<dynamic> { _, reject -> r = reject }
+ val throwable = async(start = CoroutineStart.UNDISPATCHED) {
+ assertFails { toAwait.await() }
+ }
+ r(RuntimeException("Rejected"))
+ assertIs<RuntimeException>(throwable.await())
+ assertEquals("Rejected", throwable.await().message)
+ }
}
diff --git a/kotlinx-coroutines-core/wasmJs/test/PromiseTest.kt b/kotlinx-coroutines-core/wasmJs/test/PromiseTest.kt
index 6355043..e72e661 100644
--- a/kotlinx-coroutines-core/wasmJs/test/PromiseTest.kt
+++ b/kotlinx-coroutines-core/wasmJs/test/PromiseTest.kt
@@ -84,4 +84,27 @@
null
}
}
+
+ @Test
+ fun testAwaitPromiseRejectedWithNonKotlinException() = GlobalScope.promise {
+ lateinit var r: (JsAny) -> Unit
+ val toAwait = Promise<JsAny?> { _, reject -> r = reject }
+ val throwable = async(start = CoroutineStart.UNDISPATCHED) {
+ assertFails { toAwait.await<JsAny?>() }
+ }
+ r("Rejected".toJsString())
+ assertIs<JsException>(throwable.await())
+ }
+
+ @Test
+ fun testAwaitPromiseRejectedWithKotlinException() = GlobalScope.promise {
+ lateinit var r: (JsAny) -> Unit
+ val toAwait = Promise<JsAny?> { _, reject -> r = reject }
+ val throwable = async(start = CoroutineStart.UNDISPATCHED) {
+ assertFails { toAwait.await<JsAny?>() }
+ }
+ r(RuntimeException("Rejected").toJsReference())
+ assertIs<RuntimeException>(throwable.await())
+ assertEquals("Rejected", throwable.await().message)
+ }
}