From 6ddbe25b2e20f171f69b399c7a85dfdae8101ba8 Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Thu, 6 Jul 2023 10:49:44 +0300 Subject: [PATCH 1/5] make TestUtils wait functions cancellable --- .../jetbrains/compose/web/testutils/TestUtils.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt index 38440fcf5bb..b8c1a896a1c 100644 --- a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt +++ b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt @@ -84,12 +84,16 @@ class TestScope : CoroutineScope by MainScope() { * Suspends until [element] observes any change to its html. */ suspend fun waitForChanges(element: HTMLElement = root) { - suspendCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> val observer = MutationObserver { _, observer -> continuation.resume(Unit) observer.disconnect() } observer.observe(element, MutationObserverOptions) + + continuation.invokeOnCancellation { + observer.disconnect() + } } } @@ -97,9 +101,15 @@ class TestScope : CoroutineScope by MainScope() { * Suspends until recomposition completes. */ suspend fun waitForRecompositionComplete() { - suspendCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> waitForRecompositionCompleteContinuation = continuation } + + continuation.invokeOnCancellation { + if (waitForRecompositionCompleteContinuation === continuation) { + waitForRecompositionCompleteContinuation = null + } + } } } From e3834414b0c8d2f41cf7730896ec47178d2e90b4 Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Thu, 6 Jul 2023 10:52:36 +0300 Subject: [PATCH 2/5] add tests for cancellable test utills --- .../src/jsTest/kotlin/TestsForTestUtils.kt | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt b/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt index a8c1cd50a73..45d101d275b 100644 --- a/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt +++ b/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt @@ -79,4 +79,54 @@ class TestsForTestUtils { assertEquals(true, waitForChangesContinued) assertEquals("
Hello World!
", root.outerHTML) } + + @Test + fun waitForChanges_cancels_with_timeout() = runTest { + + var cancelled = false + + val job = launch { + try { + withTimeout(1000) { + waitForChanges(root) + } + } catch (t: TimeoutCancellationException) { + cancelled = true + throw t + } + } + + delay(100) // to check that `waitForChanges` is suspended after delay + assertEquals(false, cancelled) + + delay(1000) // to check that `waitForChanges` is cancelled after timeout + assertEquals(true, cancelled) + + job.join() + } + + @Test + fun waitForRecompositionComplete_cancels_with_timeout() = runTest { + + var cancelled = false + + val job = launch { + try { + withTimeout(1000) { + waitForRecompositionComplete() + } + } catch (t: TimeoutCancellationException) { + cancelled = true + throw t + } + } + + delay(100) // to check that `waitForRecompositionComplete` is suspended after delay + assertEquals(false, cancelled) + + delay(1000) // to check that `waitForRecompositionComplete` is cancelled after timeout + assertEquals(true, cancelled) + + job.join() + } } From 4a4ca9b0fa8e9b8e2ba5cce1245b7266074036a5 Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Thu, 6 Jul 2023 11:32:44 +0300 Subject: [PATCH 3/5] Update TestUtils.kt --- .../org/jetbrains/compose/web/testutils/TestUtils.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt index b8c1a896a1c..255262be78c 100644 --- a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt +++ b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt @@ -103,11 +103,11 @@ class TestScope : CoroutineScope by MainScope() { suspend fun waitForRecompositionComplete() { suspendCancellableCoroutine { continuation -> waitForRecompositionCompleteContinuation = continuation - } - continuation.invokeOnCancellation { - if (waitForRecompositionCompleteContinuation === continuation) { - waitForRecompositionCompleteContinuation = null + continuation.invokeOnCancellation { + if (waitForRecompositionCompleteContinuation === continuation) { + waitForRecompositionCompleteContinuation = null + } } } } From 2f1a782ab63261e9f903ae4647b64585c53f149d Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Thu, 6 Jul 2023 17:36:09 +0300 Subject: [PATCH 4/5] Add import --- .../kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt index 255262be78c..4d8fea0c08e 100644 --- a/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt +++ b/html/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MonotonicFrameClock import kotlinx.browser.document import kotlinx.browser.window +import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.promise From 25e01f31818f90d69c0cf337f57dbbddd2cc464e Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Thu, 6 Jul 2023 17:37:00 +0300 Subject: [PATCH 5/5] Add import --- html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt b/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt index 45d101d275b..b3b27ae8a89 100644 --- a/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt +++ b/html/test-utils/src/jsTest/kotlin/TestsForTestUtils.kt @@ -3,6 +3,8 @@ import androidx.compose.runtime.SideEffect import androidx.compose.runtime.currentRecomposeScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.withTimeout import org.jetbrains.compose.web.testutils.ComposeWebExperimentalTestsApi import org.jetbrains.compose.web.testutils.runTest import kotlin.test.Test