diff --git a/formula-android-tests/src/main/AndroidManifest.xml b/formula-android-tests/src/main/AndroidManifest.xml
index 2a6798b7..98ced030 100644
--- a/formula-android-tests/src/main/AndroidManifest.xml
+++ b/formula-android-tests/src/main/AndroidManifest.xml
@@ -6,12 +6,5 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
-
-
-
-
-
-
diff --git a/formula-android-tests/src/main/java/com/instacart/formula/test/TestFragmentActivity.kt b/formula-android-tests/src/main/java/com/instacart/formula/test/TestFragmentActivity.kt
deleted file mode 100644
index eb17abf9..00000000
--- a/formula-android-tests/src/main/java/com/instacart/formula/test/TestFragmentActivity.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.instacart.formula.test
-
-import android.os.Bundle
-import androidx.annotation.VisibleForTesting
-import com.instacart.formula.android.FragmentKey
-import com.instacart.formula.android.FormulaAppCompatActivity
-import com.instacart.testutils.android.R
-
-class TestFragmentActivity : FormulaAppCompatActivity() {
- @VisibleForTesting val renderCalls = mutableListOf>()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.test_activity)
- }
-}
diff --git a/formula-android-tests/src/main/java/com/instacart/formula/test/TestLifecycleKey.kt b/formula-android-tests/src/main/java/com/instacart/formula/test/TestLifecycleKey.kt
deleted file mode 100644
index 9efacaf3..00000000
--- a/formula-android-tests/src/main/java/com/instacart/formula/test/TestLifecycleKey.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.instacart.formula.test
-
-import com.instacart.formula.android.FragmentKey
-import kotlinx.parcelize.Parcelize
-
-@Parcelize
-data class TestLifecycleKey(
- override val tag: String = "test-lifecycle",
-) : FragmentKey
diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FormulaFragmentTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FormulaFragmentTest.kt
index f1c0dced..2d1697a1 100644
--- a/formula-android-tests/src/test/java/com/instacart/formula/FormulaFragmentTest.kt
+++ b/formula-android-tests/src/test/java/com/instacart/formula/FormulaFragmentTest.kt
@@ -17,11 +17,9 @@ import com.instacart.formula.android.events.FragmentLifecycleEvent
import com.instacart.formula.test.TestBackCallbackRenderModel
import com.instacart.testutils.android.TestKey
import com.instacart.formula.test.TestKeyWithId
-import com.instacart.formula.test.TestFragmentActivity
-import com.instacart.formula.test.TestLifecycleKey
import com.instacart.testutils.android.HeadlessFragment
+import com.instacart.testutils.android.TestFormulaActivity
import com.instacart.testutils.android.activity
-import com.instacart.testutils.android.get
import com.instacart.testutils.android.showFragment
import com.jakewharton.rxrelay3.PublishRelay
import io.reactivex.rxjava3.core.Observable
@@ -31,7 +29,6 @@ import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import org.robolectric.Shadows
-import org.robolectric.annotation.LooperMode
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
@@ -44,6 +41,8 @@ class FormulaFragmentTest {
private var updateThreads = linkedSetOf()
private val errors = mutableListOf()
private val fragmentLifecycleEvents = mutableListOf()
+ private val renderCalls = mutableListOf>()
+
private val formulaRule = TestFormulaRule(
initFormula = { app ->
val environment = FragmentEnvironment(
@@ -52,7 +51,7 @@ class FormulaFragmentTest {
}
)
FormulaAndroid.init(app, environment) {
- activity {
+ activity {
ActivityStore(
onRenderFragmentState = { a, state ->
lastState = state
@@ -60,9 +59,17 @@ class FormulaFragmentTest {
updateThreads.add(Thread.currentThread())
},
fragmentStore = FragmentStore.init {
- bind(TestFeatureFactory { stateChanges(it) })
+ bind(
+ featureFactory = TestFeatureFactory(
+ render = { key, value ->
+ renderCalls.add(key to value)
+ },
+ state = { stateChanges(it) }
+ )
+ )
bind(TestFeatureFactory(
- applyOutput = { output ->
+ render = { key, output ->
+ renderCalls.add(key to output)
if (output == "crash") {
throw IllegalStateException("crashing")
}
@@ -87,10 +94,10 @@ class FormulaFragmentTest {
}
)
- private val activityRule = ActivityScenarioRule(TestFragmentActivity::class.java)
+ private val activityRule = ActivityScenarioRule(TestFormulaActivity::class.java)
@get:Rule val rule = RuleChain.outerRule(formulaRule).around(activityRule)
- lateinit var scenario: ActivityScenario
+ lateinit var scenario: ActivityScenario
@Before fun setup() {
scenario = activityRule.scenario
@@ -136,17 +143,15 @@ class FormulaFragmentTest {
}
@Test fun `render model is passed to visible fragment`() {
- val activity = activity()
sendStateUpdate(TestKey(), "update")
- assertThat(activity.renderCalls).containsExactly(TestKey() to "update").inOrder()
+ assertThat(renderCalls).containsExactly(TestKey() to "update").inOrder()
}
@Test fun `render model is not passed to not visible fragment`() {
navigateToTaskDetail()
- val activity = activity()
sendStateUpdate(TestKey(), "update")
- assertThat(activity.renderCalls).isEqualTo(emptyList())
+ assertThat(renderCalls).isEqualTo(emptyList())
}
@Test fun `visible fragments are updated when navigating`() {
@@ -154,17 +159,15 @@ class FormulaFragmentTest {
val contract = TestKeyWithId(1)
- val activity = activity()
sendStateUpdate(contract, "update")
- assertThat(activity.renderCalls).containsExactly(contract to "update").inOrder()
+ assertThat(renderCalls).containsExactly(contract to "update").inOrder()
navigateBack()
sendStateUpdate(contract, "update-two")
- assertThat(activity.renderCalls).containsExactly(contract to "update").inOrder()
+ assertThat(renderCalls).containsExactly(contract to "update").inOrder()
}
- @LooperMode(LooperMode.Mode.LEGACY)
@Test fun `delegates back press to current render model`() {
navigateToTaskDetail()
@@ -318,19 +321,18 @@ class FormulaFragmentTest {
val key = TestKeyWithId(1)
navigateToTaskDetail(id = key.id)
- val activity = activity()
sendStateUpdate(key, "crash")
- assertThat(activity.renderCalls).isNotEmpty()
+ assertThat(renderCalls).isNotEmpty()
assertThat(errors).hasSize(1)
}
@Test
fun toStringContainsTagAndKey() {
- val fragment = FormulaFragment.newInstance(TestLifecycleKey())
+ val fragment = FormulaFragment.newInstance(TestKey())
val toStringValue = fragment.toString()
assertThat(toStringValue).isEqualTo(
- "test-lifecycle -> TestLifecycleKey(tag=test-lifecycle)"
+ "test key -> TestKey(tag=test key)"
)
}
@@ -350,20 +352,18 @@ class FormulaFragmentTest {
}
}
- private fun activity(): TestFragmentActivity {
+ private fun activity(): TestFormulaActivity {
return scenario.activity()
}
private fun activeContracts(): List {
- return scenario.get {
- lastState!!.activeIds.map { it.key }
- }
+ return lastState!!.activeIds.map { it.key }
}
private fun assertVisibleContract(contract: FragmentKey) {
assertNoDuplicates(contract)
// TODO: would be best to test visibleState() however `FragmentFlowState.states` is empty
- assertThat(scenario.get { lastState?.visibleIds?.lastOrNull()?.key }).isEqualTo(contract)
+ assertThat(lastState?.visibleIds?.lastOrNull()?.key).isEqualTo(contract)
}
private fun assertNoDuplicates(contract: FragmentKey) {
diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt
deleted file mode 100644
index bc7dfa9f..00000000
--- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.instacart.formula
-
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import com.instacart.formula.android.ActivityStore
-import com.instacart.formula.android.FormulaFragment
-import com.instacart.formula.android.FragmentStore
-import com.instacart.testutils.android.TestFragmentLifecycleCallback
-import com.instacart.formula.test.TestLifecycleKey
-import com.instacart.testutils.android.NoOpFeatureFactory
-import com.instacart.testutils.android.TestFormulaActivity
-import com.instacart.testutils.android.TestViewFactory
-import com.instacart.testutils.android.showFragment
-import com.instacart.testutils.android.withFormulaAndroid
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class FragmentLifecycleTest {
-
- private fun runTest(
- continuation: (ActivityScenario, TestFragmentLifecycleCallback) -> Unit
- ) {
- val lifecycleCallback = TestFragmentLifecycleCallback()
- withFormulaAndroid(
- configure = {
- activity {
- ActivityStore(
- fragmentStore = FragmentStore.init {
- val featureFactory = NoOpFeatureFactory(
- viewFactory = TestViewFactory(lifecycleCallback)
- )
- bind(featureFactory)
- },
- )
- }
- }
- ) {
- val scenario = ActivityScenario.launch(TestFormulaActivity::class.java)
- scenario.showFragment(TestLifecycleKey())
- continuation(scenario, lifecycleCallback)
- }
- }
-
- @Test fun `creation callbacks`() {
- runTest { _, lifecycleCallback ->
- assertThat(lifecycleCallback.hasOnViewCreated).isTrue()
- assertThat(lifecycleCallback.hasOnActivityCreated).isTrue()
- assertThat(lifecycleCallback.hasOnStart).isTrue()
- assertThat(lifecycleCallback.hasOnResume).isTrue()
- }
- }
-
- @Test fun `destroy callbacks`() {
- runTest { scenario, lifecycleCallback ->
- scenario.close()
-
- assertThat(lifecycleCallback.hasOnPauseEvent).isTrue()
- assertThat(lifecycleCallback.hasOnStop).isTrue()
- assertThat(lifecycleCallback.hasOnDestroyView).isTrue()
- }
- }
-
- @Test fun `save instance state callback`() {
- runTest { scenario, lifecycleCallback ->
- assertThat(lifecycleCallback.hasOnSaveInstanceState).isFalse()
- scenario.recreate()
- assertThat(lifecycleCallback.hasOnSaveInstanceState).isTrue()
- }
- }
-
- @Test fun `low memory`() {
- runTest { scenario, lifecycleCallback ->
- scenario.onActivity {
- val fragment = it.supportFragmentManager.fragments
- .filterIsInstance()
- .first()
-
- fragment.onLowMemory()
- }
- assertThat(lifecycleCallback.hasCalledLowMemory).isTrue()
- }
- }
-}
diff --git a/formula-android-tests/src/test/java/com/instacart/formula/TestFeatureFactory.kt b/formula-android-tests/src/test/java/com/instacart/formula/TestFeatureFactory.kt
index b771c670..c92f5ff4 100644
--- a/formula-android-tests/src/test/java/com/instacart/formula/TestFeatureFactory.kt
+++ b/formula-android-tests/src/test/java/com/instacart/formula/TestFeatureFactory.kt
@@ -3,20 +3,19 @@ package com.instacart.formula
import com.instacart.formula.android.Feature
import com.instacart.formula.android.FeatureFactory
import com.instacart.formula.android.FragmentKey
-import com.instacart.formula.test.TestFragmentActivity
import com.instacart.testutils.android.TestViewFactory
import io.reactivex.rxjava3.core.Observable
class TestFeatureFactory(
- private val applyOutput: (Any) -> Unit = {},
+ private val render: (FragmentKey, Any) -> Unit = { _, _ -> },
private val state: (Key) -> Observable,
+
) : FeatureFactory {
override fun initialize(dependencies: Unit, key: Key): Feature {
return Feature(
state = state(key),
- viewFactory = TestViewFactory { view, value ->
- (view.context as TestFragmentActivity).renderCalls.add(Pair(key, value))
- applyOutput(value)
+ viewFactory = TestViewFactory { _, value ->
+ render(key, value)
}
)
}
diff --git a/formula-android/src/test/java/com/instacart/formula/android/FormulaAndroidTest.kt b/formula-android/src/test/java/com/instacart/formula/android/FormulaAndroidTest.kt
index 57d82ffa..a30fe832 100644
--- a/formula-android/src/test/java/com/instacart/formula/android/FormulaAndroidTest.kt
+++ b/formula-android/src/test/java/com/instacart/formula/android/FormulaAndroidTest.kt
@@ -13,6 +13,7 @@ import com.google.common.truth.Truth.assertThat
import com.instacart.formula.FormulaAndroid
import com.instacart.formula.android.events.ActivityResult
import com.instacart.formula.android.test.runActivityUpdateTest
+import com.instacart.formula.android.test.runFeatureFactoryLifecycleTest
import com.instacart.testutils.android.TestActivity
import com.instacart.testutils.android.TestFormulaActivity
import com.instacart.testutils.android.TestFragmentActivity
@@ -27,7 +28,6 @@ class FormulaAndroidTest {
@Test
fun `crashes if initialized twice`() {
-
try {
val result = runCatching {
val context = ApplicationProvider.getApplicationContext()
@@ -180,4 +180,43 @@ class FormulaAndroidTest {
)
}
}
+
+ @Test
+ fun `feature factory lifecycle events`() {
+ runFeatureFactoryLifecycleTest {
+ assertThat(lifecycleCallback.hasOnViewCreated).isTrue()
+ assertThat(lifecycleCallback.hasOnActivityCreated).isTrue()
+ assertThat(lifecycleCallback.hasOnStart).isTrue()
+ assertThat(lifecycleCallback.hasOnResume).isTrue()
+
+ scenario.close()
+
+ assertThat(lifecycleCallback.hasOnPauseEvent).isTrue()
+ assertThat(lifecycleCallback.hasOnStop).isTrue()
+ assertThat(lifecycleCallback.hasOnDestroyView).isTrue()
+ }
+ }
+
+ @Test
+ fun `feature factory save instance event`() {
+ runFeatureFactoryLifecycleTest {
+ assertThat(lifecycleCallback.hasOnSaveInstanceState).isFalse()
+ scenario.recreate()
+ assertThat(lifecycleCallback.hasOnSaveInstanceState).isTrue()
+ }
+ }
+
+ @Test
+ fun `feature factory low memory event`() {
+ runFeatureFactoryLifecycleTest {
+ scenario.onActivity {
+ val fragment = it.supportFragmentManager.fragments
+ .filterIsInstance()
+ .first()
+
+ fragment.onLowMemory()
+ }
+ assertThat(lifecycleCallback.hasCalledLowMemory).isTrue()
+ }
+ }
}
diff --git a/formula-android/src/test/java/com/instacart/formula/android/test/FeatureFactoryLifecycleInteractor.kt b/formula-android/src/test/java/com/instacart/formula/android/test/FeatureFactoryLifecycleInteractor.kt
new file mode 100644
index 00000000..17387956
--- /dev/null
+++ b/formula-android/src/test/java/com/instacart/formula/android/test/FeatureFactoryLifecycleInteractor.kt
@@ -0,0 +1,42 @@
+package com.instacart.formula.android.test
+
+import androidx.test.core.app.ActivityScenario
+import com.instacart.formula.android.ActivityStore
+import com.instacart.formula.android.FragmentStore
+import com.instacart.testutils.android.NoOpFeatureFactory
+import com.instacart.testutils.android.TestFormulaActivity
+import com.instacart.testutils.android.TestFragmentLifecycleCallback
+import com.instacart.testutils.android.TestKey
+import com.instacart.testutils.android.TestViewFactory
+import com.instacart.testutils.android.showFragment
+import com.instacart.testutils.android.withFormulaAndroid
+
+class FeatureFactoryLifecycleInteractor(
+ val scenario: ActivityScenario,
+ val lifecycleCallback: TestFragmentLifecycleCallback,
+)
+
+fun runFeatureFactoryLifecycleTest(
+ continuation: FeatureFactoryLifecycleInteractor.() -> Unit
+) {
+ val lifecycleCallback = TestFragmentLifecycleCallback()
+ withFormulaAndroid(
+ configure = {
+ activity {
+ ActivityStore(
+ fragmentStore = FragmentStore.init {
+ val featureFactory = NoOpFeatureFactory(
+ viewFactory = TestViewFactory(lifecycleCallback)
+ )
+ bind(featureFactory)
+ },
+ )
+ }
+ }
+ ) {
+ val scenario = ActivityScenario.launch(TestFormulaActivity::class.java)
+ scenario.showFragment(TestKey())
+ val interactor = FeatureFactoryLifecycleInteractor(scenario, lifecycleCallback)
+ continuation(interactor)
+ }
+}
\ No newline at end of file