Jetpack Compose
Update the Navigation Function
inline fun <reified T : BasePage> BasePage.navigateToPageWithClick(
semanticsNodeInteraction: SemanticsNodeInteraction,
block: PageScope<T>
): T {
semanticsNodeInteraction.performClick()
return T::class.java.newInstance().apply {
this.composeTestRule = this@navigateToPageWithClick.composeTestRule
assertScreen()
block()
}
}
inline fun <reified T : BasePage> ComposeTestRule.startOnPage(block: PageScope<T> = {}): T =
T::class.java.newInstance().apply {
this.composeTestRule = this@startOnPage
assertScreen()
block()
}
Convert BasePage to Abstract Class
abstract class BasePage {
lateinit var composeTestRule: ComposeTestRule
abstract fun assertScreen()
fun Int.toViewInteraction(): ViewInteraction = onView(withId(this))
}
Update Pages
class LoginPage : BasePage() {
override fun assertScreen() {
onSignInOrRegisterButton().assertIsDisplayed()
}
fun onSignInOrRegisterButton(): SemanticsNodeInteraction {
val text =
InstrumentationRegistry.getInstrumentation().targetContext.getString(R.string.action_sign_in)
return composeTestRule.onNodeWithText(text = text)
}
fun goToLoggedInPage(block: PageScope<LoggedInPage>): LoggedInPage =
navigateToPageWithClick(onSignInOrRegisterButton(), block)
}
Since the navigateToPageWithClick
has the same name as the other version which takes a ViewInteraction
, it technically doesn't need to be updated!
Update Test
class MockkLoginTest {
@get:Rule
val composeTestRule = createAndroidComposeRule<LoginActivity>()
@Test
fun successfulLogin() {
// omitted code
//use extension function on ComposeTestRule to start the navigation
composeTestRule.startOnPage<LoginPage> {
enterInfo("andrew@example.com", "password")
}.goToLoggedInPage {
onWelcomeGreeting().verifyText("Welcome Andrew!")
}.goToSettings()
}
}
Replace View With Compose
<androidx.compose.ui.platform.ComposeView
android:id="@+id/login_button"
... />
binding.loginButton.setContent {
val state = loginViewModel.loginFormState.observeAsState()
Button(onClick = {
loading.visibility = View.VISIBLE
loginViewModel.login(username.text.toString(), password.text.toString())
}, enabled = state.value?.isDataValid ?: false) {
Text(text = stringResource(id = R.string.action_sign_in))
}
}