From 19510f362b22f942717443e3ebfabe588ebcae12 Mon Sep 17 00:00:00 2001 From: Waldemar Kornewald Date: Sat, 3 Feb 2024 13:39:56 +0100 Subject: [PATCH] Added StateFlow.onStateSubscription and use dispatchers.main for better iOS interop --- .github/workflows/build.yaml | 2 +- CHANGELOG.md | 6 +++ build.gradle | 24 ++++++------ dependencies.gradle | 6 +-- gradle.properties | 3 +- gradle/common/android-common.gradle | 14 +------ gradle/common/android-library.gradle | 4 -- gradle/common/kotlin-common.gradle | 1 + gradle/wrapper/gradle-wrapper.properties | 2 +- .../com/ensody/reactivestate/AutoRun.kt | 12 +++--- .../com/ensody/reactivestate/Derived.kt | 12 +++--- .../reactivestate/RefreshableStateFlow.kt | 38 +++++++++++++++++++ .../ensody/reactivestate/StateFlowUtils.kt | 19 ++++++++++ .../ensody/reactivestate/android/AutoRun.kt | 4 +- .../ensody/reactivestate/android/Derived.kt | 8 ++-- .../reactivestate/android/FragmentTest.kt | 2 - 16 files changed, 104 insertions(+), 53 deletions(-) create mode 100644 reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/RefreshableStateFlow.kt diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1f7a575c..0824c648 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,7 +20,7 @@ jobs: - name: Install JDK uses: actions/setup-java@v2 with: - java-version: "11" + java-version: "17" distribution: "temurin" cache: "gradle" check-latest: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 99db1765..2f23d8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 5.7.0 + +* Upgraded to Kotlin 1.9.22. +* Switched `derived` and `AutoRunner` default dispatcher to `dispatcher.main`, to prevent threading errors on iOS by default. +* Added `MutableStateFlow.onStateSubscription {}` and `StateFlow.onStateSubscription {}` which behave like `onSubscription` but return a `MutableStateFlow`/`StateFlow`. + ## 5.6.0 * Upgraded to kotlinx.coroutines 1.7.3. diff --git a/build.gradle b/build.gradle index 8f8dc86f..99bd52a4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform buildscript { - ext.kotlin_version = '1.8.21' + ext.kotlin_version = '1.9.22' } plugins { - id 'com.android.application' version '7.4.2' apply false + id 'com.android.application' version '8.2.0' apply false id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false - id "org.jetbrains.dokka" version "1.8.20" + id "org.jetbrains.dokka" version "1.9.10" id 'pl.allegro.tech.build.axion-release' version '1.15.3' id 'com.github.ben-manes.versions' version '0.47.0' id "io.github.gradle-nexus.publish-plugin" version "1.3.0" @@ -80,7 +80,7 @@ subprojects { } if (isAndroidProject) { - android { + androidTarget { publishLibraryVariants("release") } @@ -107,17 +107,22 @@ subprojects { // wasm32() + applyDefaultHierarchyTemplate() + if (isIosProject) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() testAll.dependsOn "iosSimulatorArm64Test" testAll.dependsOn "iosX64Test" - tvos() + tvosArm64() + tvosX64() tvosSimulatorArm64() - watchos() - watchosX86() + watchosArm32() + watchosArm64() + watchosX64() watchosSimulatorArm64() sourceSets { @@ -146,8 +151,6 @@ subprojects { watchosArm32Test { dependsOn(watchosTest) } watchosX64Main { dependsOn(watchosMain) } watchosX64Test { dependsOn(watchosTest) } - watchosX86Main { dependsOn(watchosMain) } - watchosX86Test { dependsOn(watchosTest) } watchosSimulatorArm64Main { dependsOn(watchosMain) } watchosSimulatorArm64Test { dependsOn(watchosTest) } } @@ -197,7 +200,6 @@ subprojects { if (isAndroidProject) { androidLibrary( minVersion: isComposeProject ? 21 : 19, - kotlinCompilerArgs: kotlinCompilerArgs, ) android { diff --git a/dependencies.gradle b/dependencies.gradle index 8f4c6adc..ac3b8fa3 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -70,11 +70,11 @@ dependencies { androidTestDependency "androidx.fragment:fragment-testing:$fragmentVersion" androidTestDependency "androidx.test:core-ktx:1.5.0" androidTestDependency "androidx.test.ext:junit-ktx:1.1.5" - androidTestDependency "org.robolectric:robolectric:4.10.3" + androidTestDependency "org.robolectric:robolectric:4.11.1" } - composeVersion = "1.4.3" - composeCompilerVersion = "1.4.7" + composeVersion = "1.6.0" + composeCompilerVersion = "1.5.8" jetpackCompose = { android { buildFeatures { diff --git a/gradle.properties b/gradle.properties index 21ba0a02..e227191d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,8 +30,9 @@ kotlin.mpp.androidSourceSetLayoutVersion=2 # https://youtrack.jetbrains.com/issue/KT-58818 #kotlin.mpp.enableCInteropCommonization=true -kotlin.native.binary.freezing=disabled kotlin.native.binary.objcExportSuspendFunctionLaunchThreadRestriction=none org.gradle.caching=true kotlin.compiler.preciseCompilationResultsBackup=true + +android.nonTransitiveRClass=true diff --git a/gradle/common/android-common.gradle b/gradle/common/android-common.gradle index 61dcfb37..59913069 100644 --- a/gradle/common/android-common.gradle +++ b/gradle/common/android-common.gradle @@ -2,8 +2,6 @@ class Config { Integer minVersion = null Integer targetVersion = null Integer compileSdkVersion = null - Boolean kotlinExplicitApiMode = false - List kotlinCompilerArgs = [] } def isMultiplatform = ["androidMain", "jvmMain", "jvmCommonMain", "commonMain"].any { project.file("src/$it").exists() } @@ -17,9 +15,9 @@ ext.androidCommon = { args = [:] -> Config config = new Config(args) int minVersion = config.minVersion ?: 19 - int targetVersion = config.targetVersion ?: 33 + int targetVersion = config.targetVersion ?: 34 int compileVersion = config.compileSdkVersion ?: targetVersion - def javaVersion = JavaVersion.VERSION_11 + def javaVersion = JavaVersion.VERSION_17 kotlinCommon() @@ -32,14 +30,6 @@ ext.androidCommon = { args = [:] -> targetCompatibility javaVersion } - kotlinOptions { - jvmTarget = javaVersion.toString() - freeCompilerArgs = getCompilerArgs( - kotlinExplicitApiMode: config.kotlinExplicitApiMode, - kotlinCompilerArgs: config.kotlinCompilerArgs, - ) - } - namespace = "$group.${name.replace('-', '.')}" defaultConfig { diff --git a/gradle/common/android-library.gradle b/gradle/common/android-library.gradle index c616b66f..13782295 100644 --- a/gradle/common/android-library.gradle +++ b/gradle/common/android-library.gradle @@ -2,8 +2,6 @@ class Config { Integer minVersion = null Integer targetVersion = null Integer compileSdkVersion = null - Boolean kotlinExplicitApiMode = true - List kotlinCompilerArgs = [] } apply plugin: 'com.android.library' @@ -16,8 +14,6 @@ ext.androidLibrary = { args = [:] -> minVersion: config.minVersion, targetVersion: config.targetVersion, compileSdkVersion: config.compileSdkVersion, - kotlinExplicitApiMode: config.kotlinExplicitApiMode, - kotlinCompilerArgs: config.kotlinCompilerArgs, ) android { diff --git a/gradle/common/kotlin-common.gradle b/gradle/common/kotlin-common.gradle index ec9a11c1..f9b29dce 100644 --- a/gradle/common/kotlin-common.gradle +++ b/gradle/common/kotlin-common.gradle @@ -15,6 +15,7 @@ ext.getCompilerArgs = { args = [:] -> CompilerArgsConfig config = new CompilerArgsConfig(args) def compilerArgs = [ "-opt-in=kotlin.RequiresOptIn", + "-Xexpect-actual-classes", ] + config.kotlinCompilerArgs if (config.kotlinExplicitApiMode) { compilerArgs.add("-Xexplicit-api=strict") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e8be595e..7fc84bec 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/AutoRun.kt b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/AutoRun.kt index 5263828a..1db5f283 100644 --- a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/AutoRun.kt +++ b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/AutoRun.kt @@ -44,14 +44,14 @@ public fun CoroutineLauncher.autoRun( * @param onChange Gets called when the observables change. If you provide a handler you have to * manually call [run]. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading]. * @param observer The callback which is used to track the observables. */ public fun CoroutineLauncher.coAutoRun( onChange: CoAutoRunOnChangeCallback? = null, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = loading, observer: CoAutoRunCallback, ): CoAutoRunner = @@ -103,7 +103,7 @@ public fun CoroutineScope.autoRun( * @param onChange Gets called when the observables change. If you provide a handler you have to * manually call [run]. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to `launcher.loading`. * @param observer The callback which is used to track the observables. */ @@ -111,7 +111,7 @@ public fun CoroutineScope.coAutoRun( launcher: CoroutineLauncher = SimpleCoroutineLauncher(this), onChange: CoAutoRunOnChangeCallback? = null, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = launcher.loading, observer: CoAutoRunCallback, ): CoAutoRunner = @@ -268,7 +268,7 @@ public class AutoRunner( * @param onChange Gets called when the observables change. Your onChange handler has to * manually call [run] at any point (e.g. asynchronously) to change the tracked observables. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading]. * @param immediate Whether to start tracking in a background coroutine immediately. * @param observer The callback which is used to track the observables. @@ -277,7 +277,7 @@ public class CoAutoRunner( launcher: CoroutineLauncher, onChange: CoAutoRunOnChangeCallback? = null, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - private val dispatcher: CoroutineDispatcher = dispatchers.default, + private val dispatcher: CoroutineDispatcher = dispatchers.main, override val withLoading: MutableValueFlow? = launcher.loading, immediate: Boolean = false, private val observer: CoAutoRunCallback, diff --git a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/Derived.kt b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/Derived.kt index 47f757c3..9d30c34f 100644 --- a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/Derived.kt +++ b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/Derived.kt @@ -128,14 +128,14 @@ public fun CoroutineScope.derived( * * @param initial The initial value (until the first computation finishes). * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to `null`. * @param observer The callback which is used to track the observables. */ public fun derivedWhileSubscribed( initial: T, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = null, observer: CoAutoRunCallback, ): StateFlow { @@ -161,7 +161,7 @@ public fun derivedWhileSubscribed( * @param started When the value should be updated. Pass [SharingStarted.WhileSubscribed] to compute only on demand. * Defaults to [SharingStarted.Eagerly]. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading]. * @param observer The callback which is used to track the observables. */ @@ -169,7 +169,7 @@ public fun CoroutineLauncher.derived( initial: T, started: SharingStarted = SharingStarted.Eagerly, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = loading, observer: CoAutoRunCallback, ): StateFlow { @@ -197,7 +197,7 @@ public fun CoroutineLauncher.derived( * Defaults to [SharingStarted.Eagerly]. * @param launcher The [CoroutineLauncher] to use. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to `null`. * @param observer The callback which is used to track the observables. */ @@ -206,7 +206,7 @@ public fun CoroutineScope.derived( started: SharingStarted = SharingStarted.Eagerly, launcher: CoroutineLauncher = SimpleCoroutineLauncher(this), flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = null, observer: CoAutoRunCallback, ): StateFlow = diff --git a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/RefreshableStateFlow.kt b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/RefreshableStateFlow.kt new file mode 100644 index 00000000..b889183a --- /dev/null +++ b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/RefreshableStateFlow.kt @@ -0,0 +1,38 @@ +package com.ensody.reactivestate + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** + * A [StateFlow] which can retrieve a new value e.g. from a backend via [refresh]. + */ +@ExperimentalReactiveStateApi +public interface RefreshableStateFlow : StateFlow { + /** + * Refreshes the [value]. + * + * @param force Can enforce refreshing the value and bypassing any caching mechanism. + */ + public suspend fun refresh(force: Boolean = false) +} + +@ExperimentalReactiveStateApi +public fun MutableStateFlow.withRefresh( + block: suspend MutableStateFlow.(force: Boolean) -> Unit, +): RefreshableStateFlow = + DefaultRefreshableStateFlow(this) { block(it) } + +@ExperimentalReactiveStateApi +public fun StateFlow.withRefresh( + block: suspend StateFlow.(force: Boolean) -> Unit, +): RefreshableStateFlow = + DefaultRefreshableStateFlow(this) { block(it) } + +private class DefaultRefreshableStateFlow( + private val delegate: StateFlow, + private val refresher: suspend (force: Boolean) -> Unit, +) : RefreshableStateFlow, StateFlow by delegate { + override suspend fun refresh(force: Boolean) { + refresher(force) + } +} diff --git a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/StateFlowUtils.kt b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/StateFlowUtils.kt index 58af83eb..54c75cd7 100644 --- a/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/StateFlowUtils.kt +++ b/reactivestate-core/src/commonMain/kotlin/com/ensody/reactivestate/StateFlowUtils.kt @@ -1,6 +1,9 @@ package com.ensody.reactivestate +import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.onSubscription /** * Replaces the [MutableStateFlow.value] with [block]'s return value. @@ -24,3 +27,19 @@ public fun MutableStateFlow.replace(block: T.() -> T): T { value = value.block() return previous } + +/** + * Similar to [MutableStateFlow.onSubscription] but returns a [MutableStateFlow]. + */ +public fun MutableStateFlow.onStateSubscription( + block: suspend FlowCollector.() -> Unit, +): MutableStateFlow = + onSubscription(block).stateOnDemand { value }.toMutable { this@onStateSubscription.value = it } + +/** + * Similar to [StateFlow.onSubscription] but returns a [StateFlow]. + */ +public fun StateFlow.onStateSubscription( + block: suspend FlowCollector.() -> Unit, +): StateFlow = + onSubscription(block).stateOnDemand { value } diff --git a/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/AutoRun.kt b/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/AutoRun.kt index 3cb84203..d8688cd3 100644 --- a/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/AutoRun.kt +++ b/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/AutoRun.kt @@ -122,7 +122,7 @@ public fun LifecycleOwner.autoRun( * @param [onChange] Gets called when the observables change. If you provide a handler you have to * manually call [run]. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading] if * this is a [CoroutineLauncher] or `null` otherwise. * @param [observer] The callback which is used to track the observables. @@ -131,7 +131,7 @@ public fun LifecycleOwner.coAutoRun( launcher: CoroutineLauncher = if (this is CoroutineLauncher) this else LifecycleCoroutineLauncher(this), onChange: CoAutoRunOnChangeCallback? = null, flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = if (this is CoroutineLauncher) launcher.loading else null, observer: AutoRunCallback, ): CoAutoRunner { diff --git a/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/Derived.kt b/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/Derived.kt index 8611b77b..ce931c36 100644 --- a/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/Derived.kt +++ b/reactivestate/src/androidMain/kotlin/com/ensody/reactivestate/android/Derived.kt @@ -41,7 +41,7 @@ public fun ViewModel.derived( * Defaults to [SharingStarted.Eagerly]. * @param launcher The [CoroutineLauncher] to use. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading] if * this is a [CoroutineLauncher] or `null` otherwise. * @param observer The callback which is used to track the observables. @@ -51,7 +51,7 @@ public fun ViewModel.derived( started: SharingStarted = SharingStarted.Eagerly, launcher: CoroutineLauncher = if (this is CoroutineLauncher) this else SimpleCoroutineLauncher(viewModelScope), flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = if (this is CoroutineLauncher) launcher.loading else null, observer: CoAutoRunCallback, ): StateFlow = @@ -87,7 +87,7 @@ public fun LifecycleOwner.derived( * Defaults to [SharingStarted.Eagerly]. * @param launcher The [CoroutineLauncher] to use. * @param flowTransformer How changes should be executed/collected. Defaults to [conflatedWorker]. - * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.default`. + * @param dispatcher The [CoroutineDispatcher] to use. Defaults to `dispatchers.main`. * @param withLoading Tracks loading state for the (re-)computation. Defaults to [CoroutineLauncher.loading] if * this is a [CoroutineLauncher] or `null` otherwise. * @param observer The callback which is used to track the observables. @@ -97,7 +97,7 @@ public fun LifecycleOwner.derived( started: SharingStarted = SharingStarted.Eagerly, launcher: CoroutineLauncher = if (this is CoroutineLauncher) this else LifecycleCoroutineLauncher(this), flowTransformer: AutoRunFlowTransformer = { conflatedWorker(transform = it) }, - dispatcher: CoroutineDispatcher = dispatchers.default, + dispatcher: CoroutineDispatcher = dispatchers.main, withLoading: MutableValueFlow? = if (this is CoroutineLauncher) launcher.loading else null, observer: CoAutoRunCallback, ): StateFlow = diff --git a/reactivestate/src/androidUnitTest/kotlin/com/ensody/reactivestate/android/FragmentTest.kt b/reactivestate/src/androidUnitTest/kotlin/com/ensody/reactivestate/android/FragmentTest.kt index cf5f6318..c47d244b 100644 --- a/reactivestate/src/androidUnitTest/kotlin/com/ensody/reactivestate/android/FragmentTest.kt +++ b/reactivestate/src/androidUnitTest/kotlin/com/ensody/reactivestate/android/FragmentTest.kt @@ -6,7 +6,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.ensody.reactivestate.test.AndroidCoroutineTest import kotlinx.coroutines.test.runCurrent import org.junit.runner.RunWith -import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs @@ -15,7 +14,6 @@ import kotlin.test.assertSame @RunWith(AndroidJUnit4::class) internal class FragmentTest : AndroidCoroutineTest() { - @Ignore // The CI sometimes hangs here although locally the test runs successfully @Test fun creationOfReactiveState() = runTest { val scenario = launchFragmentInContainer()