diff --git a/formula-android/src/main/java/com/instacart/formula/android/internal/FragmentStoreFormula.kt b/formula-android/src/main/java/com/instacart/formula/android/internal/FragmentStoreFormula.kt index 1f3e7da8..3b4be24c 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/internal/FragmentStoreFormula.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/internal/FragmentStoreFormula.kt @@ -94,12 +94,8 @@ internal class FragmentStoreFormula( feature = feature, ) action.onEvent { - if (state.activeIds.contains(fragmentId)) { - val keyState = FragmentOutput(fragmentId.key, it) - transition(state.copy(outputs = state.outputs.plus(fragmentId to keyState))) - } else { - none() - } + val keyState = FragmentOutput(fragmentId.key, it) + transition(state.copy(outputs = state.outputs.plus(fragmentId to keyState))) } } } 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 44295eb8..fecd2ab6 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 @@ -8,6 +8,7 @@ import com.instacart.formula.android.fakes.FakeComponent 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.core.Observable import io.reactivex.rxjava3.observers.TestObserver import io.reactivex.rxjava3.subjects.PublishSubject import org.junit.Test @@ -204,6 +205,45 @@ class FragmentStoreTest { ) } + @Test fun `fragment store ignores events after key is removed`() { + 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 observer = store.state(FragmentEnvironment()).test() + val fragmentId = FragmentId("", MainKey(1)) + store.onLifecycleEffect( + FragmentLifecycleEvent.Added(fragmentId = fragmentId) + ) + stateSubject.onNext("value") + + // Check that first event was shown + val firstModel = observer.values().last().outputs[fragmentId]?.renderModel + assertThat(firstModel).isEqualTo("value") + + // Remove fragment + store.onLifecycleEffect( + FragmentLifecycleEvent.Removed(fragmentId = fragmentId) + ) + + // Check that new events are ignored + stateSubject.onNext("new-value") + + // Output should not exist + val secondModel = observer.values().last().outputs[fragmentId] + assertThat(secondModel).isNull() + } + @Test fun `feature observable error emits on screen error and finishes`() { val stateSubject = PublishSubject.create() @@ -251,6 +291,44 @@ class FragmentStoreTest { ) } + @Test fun `fragment store visible output`() { + val store = FragmentStore.init { + val featureFactory = object : FeatureFactory { + override fun initialize(dependencies: Any, key: MainKey): Feature { + return Feature( + state = Observable.just("value"), + viewFactory = NoOpViewFactory(), + ) + } + } + bind(featureFactory) + } + + val observer = store.state(FragmentEnvironment()).test() + val fragmentId = FragmentId("", MainKey(1)) + store.onLifecycleEffect( + FragmentLifecycleEvent.Added(fragmentId = fragmentId) + ) + + // No visible output yet + val firstModel = observer.values().last().visibleOutput() + assertThat(firstModel).isNull() + + // Toggle visibility + store.onVisibilityChanged(fragmentId, true) + + // Check that visible output is now present + val secondModel = observer.values().last().visibleOutput() + assertThat(secondModel).isNotNull() + + // Toggle visibility again + store.onVisibilityChanged(fragmentId, false) + + // Check that visible output is null again + val third = observer.values().last().visibleOutput() + assertThat(third).isNull() + } + private fun FragmentStore.toStates(): TestObserver> { return state(FragmentEnvironment()) .map { it.outputs.mapKeys { entry -> entry.key.key } }