Repository: arkivanov/Decompose
Pull request #894 (2025-06-22 10:14:51)

Extracted decompose-test-utils module


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a new test utilities module, providing reusable utilities for testing.
- **Refactor**
  - Updated import paths in test files to use the new test utilities module.
  - Made several test utility functions and classes publicly accessible for broader use in tests.
- **Chores**
  - Added build configuration and manifest files for the new test utilities module.
  - Updated project settings to include the new module.
- **Style**
  - Removed unnecessary semicolons in a web module utility file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Patch:
diff --git a/decompose/build.gradle.kts b/decompose/build.gradle.kts
index 20b31c41..c511d63f 100644
--- a/decompose/build.gradle.kts
+++ b/decompose/build.gradle.kts
@@ -61,8 +61,8 @@ kotlin {
         }
 
         common.test.dependencies {
+            implementation(project(":decompose-test-utils"))
             implementation(deps.jetbrains.kotlinx.kotlinxCoroutinesCore)
-            implementation(deps.jetbrains.kotlinx.kotlinxSerializationJson)
         }
 
         android.main.dependencies {
diff --git a/decompose/src/webMain/kotlin/com/arkivanov/decompose/router/stack/Utils.kt b/decompose/src/webMain/kotlin/com/arkivanov/decompose/router/stack/Utils.kt
index 8dfa3cfb..15c9da5f 100644
--- a/decompose/src/webMain/kotlin/com/arkivanov/decompose/router/stack/Utils.kt
+++ b/decompose/src/webMain/kotlin/com/arkivanov/decompose/router/stack/Utils.kt
@@ -22,10 +22,10 @@ internal fun <T> List<T>.findFirstDifferentIndex(other: List<T>): Int {
     val minSize = min(size, other.size)
 
     if (minSize <= 0) {
-        return -1;
+        return -1
     }
 
-    var i = 0;
+    var i = 0
     while ((i < minSize) && (this[i] == other[i])) {
         i++
     }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1d7d85a7..72e971cd 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -27,6 +27,7 @@ pluginManagement {
 
 if (!startParameter.projectProperties.containsKey("check_publication")) {
     include(":decompose")
+    include(":decompose-test-utils")
     include(":extensions-compose")
     include(":extensions-compose-experimental")
     include(":extensions-android")


Test patch:
diff --git a/decompose-test-utils/.gitignore b/decompose-test-utils/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/decompose-test-utils/.gitignore
@@ -0,0 +1,1 @@
+/build
\ No newline at end of file
diff --git a/decompose-test-utils/build.gradle.kts b/decompose-test-utils/build.gradle.kts
new file mode 100644
index 00000000..c7bf62bc
--- /dev/null
+++ b/decompose-test-utils/build.gradle.kts
@@ -0,0 +1,36 @@
+import com.arkivanov.gradle.bundle
+import com.arkivanov.gradle.dependsOn
+import com.arkivanov.gradle.setupBinaryCompatibilityValidator
+import com.arkivanov.gradle.setupMultiplatform
+import com.arkivanov.gradle.setupPublication
+import com.arkivanov.gradle.setupSourceSets
+
+plugins {
+    id("kotlin-multiplatform")
+    id("com.android.library")
+    id("kotlinx-serialization")
+    id("com.arkivanov.gradle.setup")
+}
+
+setupMultiplatform()
+
+android {
+    namespace = "com.arkivanov.decompose.testutils"
+}
+
+kotlin {
+    setupSourceSets {
+        all {
+            languageSettings {
+                optIn("com.arkivanov.decompose.InternalDecomposeApi")
+                optIn("com.arkivanov.decompose.ExperimentalDecomposeApi")
+            }
+        }
+
+        common.main.dependencies {
+            implementation(project(":decompose"))
+            implementation(deps.jetbrains.kotlinx.kotlinxSerializationCore)
+            implementation(deps.jetbrains.kotlinx.kotlinxSerializationJson)
+        }
+    }
+}
diff --git a/decompose-test-utils/src/androidMain/AndroidManifest.xml b/decompose-test-utils/src/androidMain/AndroidManifest.xml
new file mode 100644
index 00000000..5c3d3655
--- /dev/null
+++ b/decompose-test-utils/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest/>
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestComponentContext.kt b/decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestComponentContext.kt
similarity index 81%
rename from decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestComponentContext.kt
rename to decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestComponentContext.kt
index a4766723..497b9732 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestComponentContext.kt
+++ b/decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestComponentContext.kt
@@ -1,5 +1,8 @@
-package com.arkivanov.decompose
+package com.arkivanov.decompose.testutils
 
+import com.arkivanov.decompose.ComponentContext
+import com.arkivanov.decompose.ComponentContextFactory
+import com.arkivanov.decompose.DefaultComponentContext
 import com.arkivanov.essenty.backhandler.BackDispatcher
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
 import com.arkivanov.essenty.lifecycle.Lifecycle
@@ -8,7 +11,7 @@ import com.arkivanov.essenty.lifecycle.create
 import com.arkivanov.essenty.lifecycle.destroy
 import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
 
-internal class TestComponentContext(
+class TestComponentContext(
     override val lifecycle: LifecycleRegistry = LifecycleRegistry(Lifecycle.State.RESUMED),
     override val stateKeeper: StateKeeperDispatcher = StateKeeperDispatcher(),
     override val instanceKeeper: InstanceKeeperDispatcher = InstanceKeeperDispatcher(),
@@ -19,7 +22,7 @@ internal class TestComponentContext(
         ComponentContextFactory(::DefaultComponentContext)
 }
 
-internal fun TestComponentContext.recreate(isConfigurationChange: Boolean = false): TestComponentContext {
+fun TestComponentContext.recreate(isConfigurationChange: Boolean = false): TestComponentContext {
     val oldLifecycleState = lifecycle.state
 
     if (oldLifecycleState == Lifecycle.State.INITIALIZED) {
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestUtils.kt b/decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestUtils.kt
similarity index 90%
rename from decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestUtils.kt
rename to decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestUtils.kt
index 1844743d..6cbb74bb 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/TestUtils.kt
+++ b/decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestUtils.kt
@@ -1,12 +1,13 @@
-package com.arkivanov.decompose
+package com.arkivanov.decompose.testutils
 
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.essenty.statekeeper.StateKeeper
 import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
+import kotlin.reflect.KProperty
 import kotlinx.serialization.json.Json
 import kotlinx.serialization.serializer
-import kotlin.reflect.KProperty
 
+@PublishedApi
 internal val json =
     Json {
         allowStructuredMapKeys = true
@@ -19,7 +20,7 @@ inline fun <reified T : Any> StateKeeper.register(key: String, noinline supplier
 inline fun <reified T : Any> StateKeeper.consume(key: String): T? =
     consume(key = key, strategy = serializer<T>())
 
-internal inline fun <reified T> T.serializeAndDeserialize(): T {
+inline fun <reified T> T.serializeAndDeserialize(): T {
     val serializer = serializer<T>()
 
     return json.decodeFromString(serializer, json.encodeToString(serializer, this))
diff --git a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/DefaultComponentContextBuilderTest.kt b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/DefaultComponentContextBuilderTest.kt
index 117415ba..1a823453 100644
--- a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/DefaultComponentContextBuilderTest.kt
+++ b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/DefaultComponentContextBuilderTest.kt
@@ -1,6 +1,8 @@
 package com.arkivanov.decompose
 
 import com.arkivanov.decompose.router.TestInstance
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.essenty.backhandler.BackCallback
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import org.junit.runner.RunWith
diff --git a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentMultipleTest.kt b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentMultipleTest.kt
index 65a798dc..53aa41e6 100644
--- a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentMultipleTest.kt
+++ b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentMultipleTest.kt
@@ -1,6 +1,8 @@
 package com.arkivanov.decompose
 
 import com.arkivanov.decompose.router.TestInstance
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.essenty.backhandler.BackCallback
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import org.junit.runner.RunWith
diff --git a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentSingleTest.kt b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentSingleTest.kt
index 445fcf4b..701aad69 100644
--- a/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentSingleTest.kt
+++ b/decompose/src/androidUnitTest/kotlin/com/arkivanov/decompose/RetainedComponentSingleTest.kt
@@ -1,6 +1,8 @@
 package com.arkivanov.decompose
 
 import com.arkivanov.decompose.router.TestInstance
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.essenty.backhandler.BackCallback
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import org.junit.runner.RunWith
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/ChildContextWithLifecycleTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/ChildContextWithLifecycleTest.kt
index 4655d74d..39f61f67 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/ChildContextWithLifecycleTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/ChildContextWithLifecycleTest.kt
@@ -3,6 +3,8 @@ package com.arkivanov.decompose
 import com.arkivanov.decompose.backhandler.TestBackDispatcher
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.essenty.backhandler.BackCallback
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
 import com.arkivanov.essenty.instancekeeper.getOrCreate
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildControllerTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildControllerTest.kt
index ae136624..ce1d841e 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildControllerTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildControllerTest.kt
@@ -3,16 +3,17 @@ package com.arkivanov.decompose.router.children
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.TestBackCallback
 import com.arkivanov.decompose.TestBackCallback.Event
-import com.arkivanov.decompose.TestComponentContext
 import com.arkivanov.decompose.assertEvents
 import com.arkivanov.decompose.assertNoEvents
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks
-import com.arkivanov.decompose.recreate
 import com.arkivanov.decompose.router.Component
 import com.arkivanov.decompose.router.TestInstance
-import com.arkivanov.decompose.serializeAndDeserialize
+import com.arkivanov.decompose.testutils.TestComponentContext
+import com.arkivanov.decompose.testutils.recreate
+import com.arkivanov.decompose.testutils.serializeAndDeserialize
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import com.arkivanov.essenty.lifecycle.Lifecycle
+import kotlinx.serialization.builtins.serializer
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertFalse
@@ -21,7 +22,6 @@ import kotlin.test.assertNotSame
 import kotlin.test.assertNull
 import kotlin.test.assertSame
 import kotlin.test.assertTrue
-import kotlinx.serialization.builtins.serializer
 
 @Suppress("TestFunctionName")
 class ChildControllerTest {
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBackPressedTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBackPressedTest.kt
index 3319ee86..88bfd3ce 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBackPressedTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBackPressedTest.kt
@@ -4,11 +4,11 @@ import com.arkivanov.decompose.TestBackCallback
 import com.arkivanov.decompose.TestBackCallback.Event.OnBack
 import com.arkivanov.decompose.assertEvents
 import com.arkivanov.decompose.assertNoEvents
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.children.ChildNavState.Status.CREATED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.RESUMED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.STARTED
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.backhandler.BackCallback
 import kotlin.test.Test
 import kotlin.test.assertContentEquals
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBasicTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBasicTest.kt
index 0a4f9259..1b4b0c4d 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBasicTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenBasicTest.kt
@@ -2,13 +2,13 @@ package com.arkivanov.decompose.router.children
 
 import com.arkivanov.decompose.DecomposeExperimentFlags
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.router.children.ChildNavState.Status.CREATED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.RESUMED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.STARTED
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import com.arkivanov.essenty.lifecycle.destroy
 import com.arkivanov.essenty.lifecycle.doOnDestroy
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenLifecycleTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenLifecycleTest.kt
index 3cd611c3..80bc7c66 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenLifecycleTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenLifecycleTest.kt
@@ -1,11 +1,11 @@
 package com.arkivanov.decompose.router.children
 
 import com.arkivanov.decompose.DecomposeExperimentFlags
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.children.ChildNavState.Status.CREATED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.RESUMED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.STARTED
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.Lifecycle
 import com.arkivanov.essenty.lifecycle.destroy
 import com.arkivanov.essenty.lifecycle.stop
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenRetainedInstanceTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenRetainedInstanceTest.kt
index 3bdeb692..c82b2463 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenRetainedInstanceTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenRetainedInstanceTest.kt
@@ -2,13 +2,13 @@ package com.arkivanov.decompose.router.children
 
 import com.arkivanov.decompose.DecomposeExperimentFlags
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.router.children.ChildNavState.Status.CREATED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.RESUMED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.STARTED
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import kotlin.test.Test
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
index 7cee2364..2d94eec8 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/ChildrenSavedStateTest.kt
@@ -2,14 +2,14 @@ package com.arkivanov.decompose.router.children
 
 import com.arkivanov.decompose.DecomposeExperimentFlags
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.consume
-import com.arkivanov.decompose.getValue
-import com.arkivanov.decompose.register
 import com.arkivanov.decompose.router.children.ChildNavState.Status.CREATED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.DESTROYED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.RESUMED
 import com.arkivanov.decompose.router.children.ChildNavState.Status.STARTED
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.getValue
+import com.arkivanov.decompose.testutils.register
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertFalse
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/TransientNavStateSaverTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/TransientNavStateSaverTest.kt
index 66acb54e..c5f75f8b 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/TransientNavStateSaverTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/children/TransientNavStateSaverTest.kt
@@ -1,6 +1,6 @@
 package com.arkivanov.decompose.router.children
 
-import com.arkivanov.decompose.serializeAndDeserialize
+import com.arkivanov.decompose.testutils.serializeAndDeserialize
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertNull
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsBackButtonTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsBackButtonTest.kt
index 38ee45f0..fb262e5b 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsBackButtonTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsBackButtonTest.kt
@@ -2,10 +2,10 @@ package com.arkivanov.decompose.router.items
 
 import com.arkivanov.decompose.TestBackCallback
 import com.arkivanov.decompose.TestBackCallback.Event.OnBack
-import com.arkivanov.decompose.TestComponentContext
 import com.arkivanov.decompose.assertEvents
 import com.arkivanov.decompose.assertNoEvents
 import com.arkivanov.decompose.router.items.Items.ActiveLifecycleState
+import com.arkivanov.decompose.testutils.TestComponentContext
 import kotlin.test.Test
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsLazinessTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsLazinessTest.kt
index e900d32e..3b4ace1f 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsLazinessTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsLazinessTest.kt
@@ -1,8 +1,8 @@
 package com.arkivanov.decompose.router.items
 
-import com.arkivanov.decompose.TestComponentContext
 import com.arkivanov.decompose.router.Component
 import com.arkivanov.decompose.router.items.Items.ActiveLifecycleState
+import com.arkivanov.decompose.testutils.TestComponentContext
 import com.arkivanov.essenty.lifecycle.Lifecycle
 import kotlin.test.Test
 import kotlin.test.assertEquals
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsNavigationTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsNavigationTest.kt
index 8c51aef3..e4a78d69 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsNavigationTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsNavigationTest.kt
@@ -1,6 +1,5 @@
 package com.arkivanov.decompose.router.items
 
-import com.arkivanov.decompose.TestComponentContext
 import com.arkivanov.decompose.router.items.Items.ActiveLifecycleState
 import com.arkivanov.decompose.router.items.LazyComponentState.CREATED
 import com.arkivanov.decompose.router.items.LazyComponentState.DESTROYED
@@ -8,6 +7,7 @@ import com.arkivanov.decompose.router.items.LazyComponentState.PENDING
 import com.arkivanov.decompose.router.items.LazyComponentState.REMOVED
 import com.arkivanov.decompose.router.items.LazyComponentState.RESUMED
 import com.arkivanov.decompose.router.items.LazyComponentState.STARTED
+import com.arkivanov.decompose.testutils.TestComponentContext
 import kotlin.test.Test
 
 @Suppress("TestFunctionName")
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsRetainedInstanceTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsRetainedInstanceTest.kt
index ef66662f..65468021 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsRetainedInstanceTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsRetainedInstanceTest.kt
@@ -1,9 +1,9 @@
 package com.arkivanov.decompose.router.items
 
-import com.arkivanov.decompose.TestComponentContext
-import com.arkivanov.decompose.recreate
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.router.items.Items.ActiveLifecycleState
+import com.arkivanov.decompose.testutils.TestComponentContext
+import com.arkivanov.decompose.testutils.recreate
 import com.arkivanov.essenty.instancekeeper.getOrCreate
 import kotlin.test.Test
 import kotlin.test.assertFalse
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsSavedStateTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsSavedStateTest.kt
index b1d6f5d6..fc5a3330 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsSavedStateTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/items/LazyItemsSavedStateTest.kt
@@ -1,11 +1,11 @@
 package com.arkivanov.decompose.router.items
 
-import com.arkivanov.decompose.TestComponentContext
-import com.arkivanov.decompose.consume
-import com.arkivanov.decompose.recreate
-import com.arkivanov.decompose.register
 import com.arkivanov.decompose.router.children.transientNavStateSaver
 import com.arkivanov.decompose.router.items.Items.ActiveLifecycleState
+import com.arkivanov.decompose.testutils.TestComponentContext
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.recreate
+import com.arkivanov.decompose.testutils.register
 import kotlin.test.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertNull
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesBackButtonTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesBackButtonTest.kt
index f856792d..e4b9ba97 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesBackButtonTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesBackButtonTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.backhandler.BackDispatcher
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesClearTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesClearTest.kt
index 0893be40..54e6fd0a 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesClearTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesClearTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesIntegrationTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesIntegrationTest.kt
index 83e2a329..18367c68 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesIntegrationTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesIntegrationTest.kt
@@ -2,8 +2,8 @@ package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.essenty.backhandler.BackDispatcher
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSavedStateTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSavedStateTest.kt
index 278dfc72..c1503dd5 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSavedStateTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSavedStateTest.kt
@@ -1,8 +1,8 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectFirstTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectFirstTest.kt
index d35cb62b..036aecaa 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectFirstTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectFirstTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectLastTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectLastTest.kt
index c8d74fd4..a10f434e 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectLastTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectLastTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectNextTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectNextTest.kt
index 08501eb5..a5849240 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectNextTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectNextTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectPrevTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectPrevTest.kt
index 8c0cf093..97d67bb9 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectPrevTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectPrevTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectTest.kt
index 8ad1f01a..90d15dc3 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSelectTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.LifecycleRegistry
 import com.arkivanov.essenty.lifecycle.resume
 import kotlin.test.BeforeTest
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSetItemsTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSetItemsTest.kt
index f463c30c..b8e13b54 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSetItemsTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/pages/ChildPagesSetItemsTest.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.decompose.router.pages
 
-import com.arkivanov.decompose.TestComponentContext
-import com.arkivanov.decompose.getValue
+import com.arkivanov.decompose.testutils.TestComponentContext
+import com.arkivanov.decompose.testutils.getValue
 import kotlin.test.Test
 
 @Suppress("TestFunctionName")
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsBackButtonTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsBackButtonTest.kt
index 86c4ffb3..88649591 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsBackButtonTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsBackButtonTest.kt
@@ -1,10 +1,10 @@
 package com.arkivanov.decompose.router.panels
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.DUAL
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.SINGLE
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.TRIPLE
+import com.arkivanov.decompose.testutils.getValue
 import kotlin.test.Test
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsNavigationTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsNavigationTest.kt
index 2e4a3547..510cd75e 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsNavigationTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsNavigationTest.kt
@@ -1,10 +1,10 @@
 package com.arkivanov.decompose.router.panels
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.DUAL
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.SINGLE
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.TRIPLE
+import com.arkivanov.decompose.testutils.getValue
 import com.arkivanov.essenty.lifecycle.Lifecycle.State.DESTROYED
 import kotlin.test.Test
 import kotlin.test.assertEquals
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsSavedStateTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsSavedStateTest.kt
index a0d41e87..b138f0fc 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsSavedStateTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/panels/ChildPanelsSavedStateTest.kt
@@ -1,10 +1,10 @@
 package com.arkivanov.decompose.router.panels
 
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.DUAL
 import com.arkivanov.decompose.router.panels.ChildPanelsMode.SINGLE
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.getValue
 import kotlin.test.Test
 
 @Suppress("TestFunctionName")
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/slot/ChildSlotIntegrationTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/slot/ChildSlotIntegrationTest.kt
index 6630faa0..699d4ba4 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/slot/ChildSlotIntegrationTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/slot/ChildSlotIntegrationTest.kt
@@ -3,11 +3,11 @@ package com.arkivanov.decompose.router.slot
 import com.arkivanov.decompose.Child
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.DefaultComponentContext
-import com.arkivanov.decompose.consume
-import com.arkivanov.decompose.getValue
-import com.arkivanov.decompose.register
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.getValue
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.essenty.backhandler.BackDispatcher
 import com.arkivanov.essenty.instancekeeper.InstanceKeeperDispatcher
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackIntegrationTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackIntegrationTest.kt
index ea8a9816..51e6ef4b 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackIntegrationTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackIntegrationTest.kt
@@ -4,8 +4,6 @@ import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.DecomposeExperimentFlags
 import com.arkivanov.decompose.DefaultComponentContext
 import com.arkivanov.decompose.DelicateDecomposeApi
-import com.arkivanov.decompose.consume
-import com.arkivanov.decompose.getValue
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_CREATE
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_DESTROY
@@ -13,9 +11,11 @@ import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_PAUSE
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_RESUME
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_START
 import com.arkivanov.decompose.lifecycle.TestLifecycleCallbacks.Event.ON_STOP
-import com.arkivanov.decompose.register
 import com.arkivanov.decompose.router.TestInstance
 import com.arkivanov.decompose.statekeeper.TestStateKeeperDispatcher
+import com.arkivanov.decompose.testutils.consume
+import com.arkivanov.decompose.testutils.getValue
+import com.arkivanov.decompose.testutils.register
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.essenty.backhandler.BackCallback
 import com.arkivanov.essenty.backhandler.BackDispatcher
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/statekeeper/TestStateKeeperDispatcher.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/statekeeper/TestStateKeeperDispatcher.kt
index 8ec6cf81..05f4d204 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/statekeeper/TestStateKeeperDispatcher.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/statekeeper/TestStateKeeperDispatcher.kt
@@ -1,6 +1,6 @@
 package com.arkivanov.decompose.statekeeper
 
-import com.arkivanov.decompose.serializeAndDeserialize
+import com.arkivanov.decompose.testutils.serializeAndDeserialize
 import com.arkivanov.essenty.statekeeper.SerializableContainer
 import com.arkivanov.essenty.statekeeper.StateKeeperDispatcher
 import kotlinx.serialization.SerializationStrategy