Browse Source
* web: move DomApplier, GlobalSnapshotManager, JsMicrotasksDispatcher to dedicated module This will allow reusing them in test-utils module. * web: move TestUtils.kt to a dedicated module Use test-utils module in web-core as a dependency Co-authored-by: Oleksandr Karpovich <oleksandr.karpovich@jetbrains.com>sync/2021-08-26
Oleksandr Karpovich
3 years ago
committed by
GitHub
43 changed files with 351 additions and 115 deletions
@ -0,0 +1,33 @@
|
||||
plugins { |
||||
kotlin("multiplatform") |
||||
id("org.jetbrains.compose") |
||||
} |
||||
|
||||
|
||||
kotlin { |
||||
js(IR) { |
||||
browser() { |
||||
testTask { |
||||
testLogging.showStandardStreams = true |
||||
useKarma { |
||||
useChromeHeadless() |
||||
useFirefox() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
sourceSets { |
||||
val commonMain by getting { |
||||
dependencies { |
||||
implementation(compose.runtime) |
||||
implementation(kotlin("stdlib-common")) |
||||
} |
||||
} |
||||
val jsMain by getting { |
||||
dependencies { |
||||
implementation(kotlin("stdlib-js")) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,4 @@
|
||||
package org.jetbrains.compose.web.internal.runtime |
||||
|
||||
@RequiresOptIn("This API is internal and is likely to change in the future.") |
||||
annotation class ComposeWebInternalApi |
@ -1,11 +1,12 @@
|
||||
package org.jetbrains.compose.web |
||||
package org.jetbrains.compose.web.internal.runtime |
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher |
||||
import kotlinx.coroutines.Runnable |
||||
import kotlin.coroutines.CoroutineContext |
||||
import kotlin.js.Promise |
||||
|
||||
internal class JsMicrotasksDispatcher : CoroutineDispatcher() { |
||||
@ComposeWebInternalApi |
||||
class JsMicrotasksDispatcher : CoroutineDispatcher() { |
||||
override fun dispatch(context: CoroutineContext, block: Runnable) { |
||||
Promise.resolve(Unit).then { block.run() } |
||||
} |
@ -0,0 +1,42 @@
|
||||
plugins { |
||||
kotlin("multiplatform") |
||||
id("org.jetbrains.compose") |
||||
} |
||||
|
||||
|
||||
repositories { |
||||
mavenCentral() |
||||
} |
||||
|
||||
kotlin { |
||||
js(IR) { |
||||
browser() { |
||||
testTask { |
||||
testLogging.showStandardStreams = true |
||||
useKarma { |
||||
useChromeHeadless() |
||||
useFirefox() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
sourceSets { |
||||
val commonMain by getting { |
||||
dependencies { |
||||
implementation(kotlin("stdlib-common")) |
||||
} |
||||
} |
||||
val jsMain by getting { |
||||
dependencies { |
||||
implementation(project(":internal-web-core-runtime")) |
||||
implementation(kotlin("stdlib-js")) |
||||
} |
||||
} |
||||
val jsTest by getting { |
||||
dependencies { |
||||
implementation(kotlin("test-js")) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,4 @@
|
||||
package org.jetbrains.compose.web.testutils |
||||
|
||||
@RequiresOptIn("This API is experimental and is likely to change in the future.") |
||||
annotation class ComposeWebExperimentalTestsApi |
@ -0,0 +1,82 @@
|
||||
import androidx.compose.runtime.RecomposeScope |
||||
import androidx.compose.runtime.SideEffect |
||||
import androidx.compose.runtime.currentRecomposeScope |
||||
import kotlinx.coroutines.delay |
||||
import kotlinx.coroutines.launch |
||||
import org.jetbrains.compose.web.testutils.ComposeWebExperimentalTestsApi |
||||
import org.jetbrains.compose.web.testutils.runTest |
||||
import kotlin.test.Test |
||||
import kotlin.test.assertEquals |
||||
|
||||
@OptIn(ComposeWebExperimentalTestsApi::class) |
||||
class TestsForTestUtils { |
||||
|
||||
@Test |
||||
fun waitForRecompositionComplete_suspends_and_continues_properly() = runTest { |
||||
var recomposeScope: RecomposeScope? = null |
||||
|
||||
composition { |
||||
recomposeScope = currentRecomposeScope |
||||
} |
||||
delay(100) // to let the initial composition complete |
||||
|
||||
var waitForRecompositionCompleteContinued = false |
||||
|
||||
val job = launch { |
||||
waitForRecompositionComplete() |
||||
waitForRecompositionCompleteContinued = true |
||||
} |
||||
|
||||
delay(100) // to check that `waitForRecompositionComplete` is suspended after delay |
||||
assertEquals(false, waitForRecompositionCompleteContinued) |
||||
|
||||
delay(100) |
||||
// we made no changes during 100 ms, so `waitForRecompositionComplete` should remain suspended |
||||
assertEquals(false, waitForRecompositionCompleteContinued) |
||||
|
||||
recomposeScope!!.invalidate() // force recomposition |
||||
job.join() |
||||
|
||||
assertEquals(true, waitForRecompositionCompleteContinued) |
||||
} |
||||
|
||||
@Test |
||||
fun waitForChanges_suspends_and_continues_properly() = runTest { |
||||
var waitForChangesContinued = false |
||||
|
||||
var recomposeScope: RecomposeScope? = null |
||||
var showText = "" |
||||
|
||||
composition { |
||||
recomposeScope = currentRecomposeScope |
||||
|
||||
SideEffect { |
||||
root.innerText = showText |
||||
} |
||||
} |
||||
|
||||
assertEquals("<div></div>", root.outerHTML) |
||||
|
||||
val job = launch { |
||||
waitForChanges(root) |
||||
waitForChangesContinued = true |
||||
} |
||||
|
||||
delay(100) // to check that `waitForChanges` is suspended after delay |
||||
assertEquals(false, waitForChangesContinued) |
||||
|
||||
// force recomposition and check that `waitForChanges` remains suspended as no changes occurred |
||||
recomposeScope!!.invalidate() |
||||
waitForRecompositionComplete() |
||||
assertEquals(false, waitForChangesContinued) |
||||
|
||||
// Make changes and check that `waitForChanges` continues |
||||
showText = "Hello World!" |
||||
recomposeScope!!.invalidate() |
||||
waitForRecompositionComplete() |
||||
|
||||
job.join() |
||||
assertEquals(true, waitForChangesContinued) |
||||
assertEquals("<div>Hello World!</div>", root.outerHTML) |
||||
} |
||||
} |
Loading…
Reference in new issue