From fcfb1232373e76c51fcda43a128c257a52346945 Mon Sep 17 00:00:00 2001 From: Laimonas Turauskas Date: Tue, 17 Sep 2024 09:43:00 -0400 Subject: [PATCH] Cover feature observable errors. --- .../formula/android/FragmentStoreTest.kt | 49 ++++++++++++++++++- jacoco.sh | 3 ++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/formula-android/src/test/java/com/instacart/formula/android/FragmentStoreTest.kt b/formula-android/src/test/java/com/instacart/formula/android/FragmentStoreTest.kt index f8d067c0..44295eb8 100644 --- a/formula-android/src/test/java/com/instacart/formula/android/FragmentStoreTest.kt +++ b/formula-android/src/test/java/com/instacart/formula/android/FragmentStoreTest.kt @@ -9,10 +9,10 @@ import com.instacart.formula.android.fakes.MainKey import com.instacart.formula.android.events.FragmentLifecycleEvent import com.instacart.formula.android.fakes.NoOpViewFactory import io.reactivex.rxjava3.observers.TestObserver +import io.reactivex.rxjava3.subjects.PublishSubject import org.junit.Test import org.junit.runner.RunWith import org.robolectric.Shadows -import java.lang.RuntimeException import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -204,6 +204,53 @@ class FragmentStoreTest { ) } + @Test fun `feature observable error emits on screen error and finishes`() { + val stateSubject = PublishSubject.create() + + val store = FragmentStore.init { + val featureFactory = object : FeatureFactory { + override fun initialize(dependencies: Any, key: MainKey): Feature { + return Feature( + state = stateSubject, + viewFactory = NoOpViewFactory(), + ) + } + } + bind(featureFactory) + } + + val screenErrors = mutableListOf>() + val environment = FragmentEnvironment( + onScreenError = { key, error -> + screenErrors.add(key to error) + } + ) + val observer = store.state(environment).test() + val fragmentId = FragmentId("", MainKey(1)) + store.onLifecycleEffect( + FragmentLifecycleEvent.Added(fragmentId = fragmentId) + ) + stateSubject.onNext("value") + + val firstModel = observer.values().last().outputs[fragmentId]?.renderModel + assertThat(firstModel).isEqualTo("value") + + // Emit error + val error = RuntimeException("error") + stateSubject.onError(error) + + // Model didn't change + val secondModel = observer.values().last().outputs[fragmentId]?.renderModel + assertThat(secondModel).isEqualTo("value") + + // Store observable didn't crash + observer.assertNoErrors() + + assertThat(screenErrors).containsExactly( + fragmentId.key to error + ) + } + private fun FragmentStore.toStates(): TestObserver> { return state(FragmentEnvironment()) .map { it.outputs.mapKeys { entry -> entry.key.key } } diff --git a/jacoco.sh b/jacoco.sh index 62696ba2..67c41755 100755 --- a/jacoco.sh +++ b/jacoco.sh @@ -2,7 +2,10 @@ # Should match with what we run in .github/workflows/build-workflow.yml ./gradlew clean ./gradlew :formula:test +./gradlew :formula-coroutines:test ./gradlew :formula-android:testRelease ./gradlew :formula-android-tests:testRelease +./gradlew :formula-test:test +./gradlew :formula-lint:build ./gradlew jacocoTestReportMerged open build/reports/jacoco/index.html