Gestures are actions too: performTouchInput { swipeLeft(startX = centerX, endX = centerX - 1_000f) } on The Quiet Harbor drags the card through the cart's hand-written swipe-to-remove (Drag Gestures), and the test asserts that onRemove received that book. The app's own log line came out in the test report: D/BookNestAnim: released at -909 of 288 px: remove.
For navigation, BookNestNav gained one parameter, nav: NavHostController = rememberNavController(), so a test can pass a TestNavHostController (androidx.navigation:navigation-testing) and inspect the back stack. The graph calls hiltViewModel(), so the test is a @HiltAndroidTest hosted in HiltTestActivity, an empty @AndroidEntryPoint activity in the debug source set, and Hilt injects Testing with Fake Dependencies's fake repository, which now serves testBooks:
@HiltAndroidTest
@Config(application = HiltTestApplication::class)
@RunWith(AndroidJUnit4::class)
class BookNestNavTest {
@get:Rule(order = 0) val hilt = HiltAndroidRule(this)
@get:Rule(order = 1) val compose = createAndroidComposeRule<HiltTestActivity>()
private lateinit var nav: TestNavHostController
@Before fun setUp() {
compose.setContent {
nav = TestNavHostController(LocalContext.current).apply {
navigatorProvider.addNavigator(ComposeNavigator())
}
BookNestNav(testBooks, nav)
}
}
@Test fun tappingABookOpensItsDetail() {
compose.onNodeWithText("Salt and Saffron").performClick()
val entry = nav.currentBackStackEntry!!
assertTrue(entry.destination.hasRoute<BookDetail>())
assertEquals(3, entry.toRoute<BookDetail>().id) // typed arguments
compose.onNodeWithText("Add to cart").assertIsDisplayed()
}A second test adds the book, taps the Cart tab and asserts "Cart: 1 books, $24.00". Hilt's rule runs first (order = 0) so its component exists before the activity starts.