Browse Source

Reuse renderComposable in tests (#1732)

This also deprecates renderTestComposable
pull/1750/head
Shagen Ogandzhanian 3 years ago committed by GitHub
parent
commit
b71a5161a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      web/core/src/jsTest/kotlin/DomSideEffectTests.kt
  2. 1
      web/core/src/jsTest/kotlin/elements/InputsGenerateCorrectHtmlTests.kt
  3. 1
      web/test-utils/build.gradle.kts
  4. 73
      web/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt

1
web/core/src/jsTest/kotlin/DomSideEffectTests.kt

@ -2,7 +2,6 @@ package org.jetbrains.compose.web.core.tests
import androidx.compose.runtime.* import androidx.compose.runtime.*
import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Div
import org.jetbrains.compose.web.renderComposable
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.dom.clear import kotlinx.dom.clear
import org.jetbrains.compose.web.testutils.* import org.jetbrains.compose.web.testutils.*

1
web/core/src/jsTest/kotlin/elements/InputsGenerateCorrectHtmlTests.kt

@ -5,7 +5,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import org.jetbrains.compose.web.attributes.* import org.jetbrains.compose.web.attributes.*
import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.dom.*
import org.jetbrains.compose.web.renderComposable
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLTextAreaElement import org.w3c.dom.HTMLTextAreaElement
import kotlin.test.Test import kotlin.test.Test

1
web/test-utils/build.gradle.kts

@ -30,6 +30,7 @@ kotlin {
val jsMain by getting { val jsMain by getting {
dependencies { dependencies {
implementation(project(":internal-web-core-runtime")) implementation(project(":internal-web-core-runtime"))
implementation(project(":web-core"))
implementation(kotlin("stdlib-js")) implementation(kotlin("stdlib-js"))
} }
} }

73
web/test-utils/src/jsMain/kotlin/org/jetbrains/compose/web/testutils/TestUtils.kt

@ -1,13 +1,30 @@
package org.jetbrains.compose.web.testutils package org.jetbrains.compose.web.testutils
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
import androidx.compose.runtime.ControlledComposition
import androidx.compose.runtime.MonotonicFrameClock
import androidx.compose.runtime.Recomposer
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.browser.window import kotlinx.browser.window
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.promise
import kotlinx.dom.clear import kotlinx.dom.clear
import org.jetbrains.compose.web.internal.runtime.* import org.jetbrains.compose.web.internal.runtime.ComposeWebInternalApi
import org.w3c.dom.* import org.jetbrains.compose.web.internal.runtime.DomApplier
import org.jetbrains.compose.web.internal.runtime.DomNodeWrapper
import org.jetbrains.compose.web.internal.runtime.GlobalSnapshotManager
import org.jetbrains.compose.web.internal.runtime.JsMicrotasksDispatcher
import org.jetbrains.compose.web.renderComposable
import org.w3c.dom.Element
import org.w3c.dom.HTMLElement
import org.w3c.dom.MutationObserver
import org.w3c.dom.MutationObserverInit
import org.w3c.dom.asList
import org.w3c.dom.get
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
@ -27,7 +44,7 @@ class TestScope : CoroutineScope by MainScope() {
* It's used as a parent element for the composition. * It's used as a parent element for the composition.
* It's added into the document's body automatically. * It's added into the document's body automatically.
*/ */
val root = "div".asHtmlElement() val root = document.createElement("div") as HTMLElement
private var waitForRecompositionCompleteContinuation: Continuation<Unit>? = null private var waitForRecompositionCompleteContinuation: Continuation<Unit>? = null
private val childrenIterator = root.children.asList().listIterator() private val childrenIterator = root.children.asList().listIterator()
@ -49,46 +66,15 @@ class TestScope : CoroutineScope by MainScope() {
fun composition(content: @Composable () -> Unit) { fun composition(content: @Composable () -> Unit) {
root.clear() root.clear()
renderTestComposable(root = root) { renderComposable(
root = root, monotonicFrameClock = TestMonotonicClockImpl(
onRecomposeComplete = this::onRecompositionComplete
)
) {
content() content()
} }
} }
/**
* Use this method to test the composition mounted at [root]
*
* @param root - the [Element] that will be the root of the DOM tree managed by Compose
* @param content - the Composable lambda that defines the composition content
*
* @return the instance of the [Composition]
*/
@OptIn(ComposeWebInternalApi::class)
@ComposeWebExperimentalTestsApi
fun <TElement : Element> renderTestComposable(
root: TElement,
content: @Composable () -> Unit
): Composition {
GlobalSnapshotManager.ensureStarted()
val context = TestMonotonicClockImpl(
onRecomposeComplete = this::onRecompositionComplete
) + JsMicrotasksDispatcher()
val recomposer = Recomposer(context)
val composition = ControlledComposition(
applier = DomApplier(DomNodeWrapper(root)),
parent = recomposer
)
composition.setContent @Composable {
content()
}
CoroutineScope(context).launch(start = CoroutineStart.UNDISPATCHED) {
recomposer.runRecomposeAndApplyChanges()
}
return composition
}
/** /**
* @return a reference to the next child element of the root. * @return a reference to the next child element of the root.
* Subsequent calls will return next child reference every time. * Subsequent calls will return next child reference every time.
@ -177,9 +163,6 @@ fun runTest(block: suspend TestScope.() -> Unit): dynamic {
return scope.promise { block(scope) } return scope.promise { block(scope) }
} }
@ComposeWebExperimentalTestsApi
fun String.asHtmlElement() = document.createElement(this) as HTMLElement
private object MutationObserverOptions : MutationObserverInit { private object MutationObserverOptions : MutationObserverInit {
override var childList: Boolean? = true override var childList: Boolean? = true
override var attributes: Boolean? = true override var attributes: Boolean? = true

Loading…
Cancel
Save