Skip to content

Commit

Permalink
Added tests to verify EnroTest rule clean up issues, and updated Enro…
Browse files Browse the repository at this point in the history
…Test/ConfigureNavigationHandleForPlugins to solve the reported bug
  • Loading branch information
isaac-udy committed Oct 16, 2023
1 parent a090f0b commit 82a9a5e
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.coroutineScope
import dev.enro.core.*
import dev.enro.core.NavigationContext
import dev.enro.core.NavigationHandle
import dev.enro.core.controller.repository.PluginRepository
import dev.enro.core.getNavigationHandle
import dev.enro.core.internal.handle.NavigationHandleViewModel
import dev.enro.core.leafContext
import dev.enro.core.rootContext
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -34,7 +38,7 @@ internal class ConfigureNavigationHandleForPlugins(
// in which case, we just ignore the exception
runCatching {
val active = context.rootContext().leafContext().getNavigationHandle()
if (!active.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return@runCatching
if (!active.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return@runCatching
activeNavigationHandle = WeakReference(active)
}
}
Expand Down
18 changes: 5 additions & 13 deletions enro-test/src/main/java/dev/enro/test/EnroTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ object EnroTest {
if (navigationController != null) {
uninstallNavigationController()
}
navigationController = createUnattachedNavigationController()
.apply {
isInTest = true
}

if (isInstrumented()) {
val application = ApplicationProvider.getApplicationContext<Application>()
Expand All @@ -35,7 +31,11 @@ object EnroTest {
}
navigationController?.apply { install(application) }
} else {
navigationController?.installForJvmTests()
navigationController = createUnattachedNavigationController()
.apply {
isInTest = true
installForJvmTests()
}
}
}

Expand All @@ -44,15 +44,7 @@ object EnroTest {
navigationController?.apply {
isInTest = false
}

val uninstallNavigationController = navigationController
navigationController = null

if (isInstrumented()) {
val application = ApplicationProvider.getApplicationContext<Application>()
if (application is NavigationApplication) return
uninstallNavigationController?.uninstall(application)
}
}

fun getCurrentNavigationController(): NavigationController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onSiblings
import androidx.compose.ui.test.performClick
import dev.enro.test.application.activity.SimpleActivityRobot
import dev.enro.test.application.compose.BottomSheetChangeSizeRobot
import dev.enro.test.application.compose.BottomSheetCloseAndPresentRobot
import dev.enro.test.application.compose.LegacyBottomSheetsRobot
Expand Down Expand Up @@ -46,4 +47,13 @@ class SelectDestinationRobot(

return LegacyBottomSheetsRobot(composeRule)
}

fun openSimpleActivity() : SimpleActivityRobot {
composeRule.onNode(hasText("Simple Activity"))
.onSiblings()
.filterToOne(hasText("Present"))
.performClick()

return SimpleActivityRobot(composeRule)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.enro.test.application.activity

import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.performClick
import dev.enro.test.application.waitForNavigationHandle
import dev.enro.tests.application.activity.SimpleActivity

class SimpleActivityRobot(
private val composeRule: ComposeTestRule
) {

init {
composeRule.waitForNavigationHandle {
it.key is SimpleActivity
}
}

fun close() {
composeRule.onNode(hasText("Close Activity"))
.performClick()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.enro.test.application.ruleinterop

import android.content.Intent
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import dev.enro.core.NavigationInstruction
import dev.enro.core.addOpenInstruction
import dev.enro.core.close
import dev.enro.test.assertClosed
import dev.enro.test.extensions.getTestNavigationHandle
import dev.enro.test.runEnroTest
import dev.enro.tests.application.activity.SimpleActivity
import dev.enro.tests.application.activity.SimpleActivityImpl
import org.junit.Test

class FirstTestWithEnroRule {
@Test
fun test() = runEnroTest {
val scenario = ActivityScenario.launch<SimpleActivityImpl>(
Intent(ApplicationProvider.getApplicationContext(), SimpleActivityImpl::class.java)
.addOpenInstruction(NavigationInstruction.Present(SimpleActivity))
)
val navigationHandle = scenario.getTestNavigationHandle<SimpleActivity>()
navigationHandle.close()
navigationHandle.assertClosed()
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.enro.test.application.ruleinterop

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import dev.enro.test.application.SelectDestinationRobot
import dev.enro.tests.application.TestActivity
import org.junit.Rule
import org.junit.Test

class FirstTestWithoutEnroRule() {
@get:Rule
val composeRule = createAndroidComposeRule<TestActivity>()

@Test
fun test() {
SelectDestinationRobot(composeRule)
.openSimpleActivity()
.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Rule Interop Tests
`EnroTest` (`EnroTestRule` or `runEnroTest`) are designed for testing screens in isolation. When using `EnroTest` functionality in instrumented tests (i.e. those in `src/androidTest`), the NavigationController configures NavigationHandles so that they don't launch any NavigationInstructions, but instead record the NavigationInstructions that were executed against a NavigationHandle, which can be verified against expected state without performing the navigation action. When the test is finished, the `EnroTest` functionality will revert this behaviour.

When running instrumented tests without using `EnroTest` functionality, navigation is expected to occur as normal.

The tests in this package are designed to be ran as a package (not as individual tests). A bug was reported where packages that mix isolated single screen tests using `EnroTest` and tests that do not use `EnroTest` (i.e. tests that perform "real" navigation). This bug would cause the tests not using `EnroTest` to fail, due to the clean up process of `EnroTest` being overeager and clearing NavigationBindings that should not have been cleared and needed to be accessed by the tests. Running the tests in this package together as a whole verifies that this bug is no longer present.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.enro.test.application.ruleinterop

import android.content.Intent
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import dev.enro.core.NavigationInstruction
import dev.enro.core.addOpenInstruction
import dev.enro.core.close
import dev.enro.test.assertClosed
import dev.enro.test.extensions.getTestNavigationHandle
import dev.enro.test.runEnroTest
import dev.enro.tests.application.activity.SimpleActivity
import dev.enro.tests.application.activity.SimpleActivityImpl
import org.junit.Test

class SecondTestWithEnroRule {
@Test
fun test() = runEnroTest {
val scenario = ActivityScenario.launch<SimpleActivityImpl>(
Intent(ApplicationProvider.getApplicationContext(), SimpleActivityImpl::class.java)
.addOpenInstruction(NavigationInstruction.Present(SimpleActivity))
)
val navigationHandle = scenario.getTestNavigationHandle<SimpleActivity>()
navigationHandle.close()
navigationHandle.assertClosed()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.enro.test.application.ruleinterop

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import dev.enro.test.application.SelectDestinationRobot
import dev.enro.tests.application.TestActivity
import org.junit.Rule
import org.junit.Test

class SecondTestWithoutEnroRule() {
@get:Rule
val composeRule = createAndroidComposeRule<TestActivity>()

@Test
fun test() {
SelectDestinationRobot(composeRule)
.openSimpleActivity()
.close()
}
}
1 change: 1 addition & 0 deletions tests/application/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

</activity>
<activity android:name="dev.enro.tests.application.compose.CloseRootAndPresentActivity" />
<activity android:name="dev.enro.tests.application.activity.SimpleActivityImpl" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dev.enro.tests.application.activity

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.Button
import androidx.compose.material.Text
import dev.enro.annotations.NavigationDestination
import dev.enro.core.NavigationKey
import dev.enro.core.navigationHandle
import dev.enro.core.requestClose
import dev.enro.tests.application.compose.common.TitledColumn
import kotlinx.parcelize.Parcelize

@Parcelize
object SimpleActivity : NavigationKey.SupportsPresent

@NavigationDestination(SimpleActivity::class)
class SimpleActivityImpl : ComponentActivity() {

private val navigation by navigationHandle<NavigationKey>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TitledColumn(title = "Simple Activity") {
Button(onClick = { navigation.requestClose() }) {
Text(text = "Close Activity")
}
}
}
}
}

0 comments on commit 82a9a5e

Please sign in to comment.