Assert loading is displayed

This commit is contained in:
Alex Gabor 2022-03-07 10:59:15 +02:00
parent b003e23305
commit 225fbed849
4 changed files with 29 additions and 26 deletions

View file

@ -2,11 +2,11 @@ package org.fnives.test.showcase.ui
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import org.fnives.test.showcase.compose.ComposeActivity
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
import org.fnives.test.showcase.testutils.MockServerScenarioSetupResetingTestRule import org.fnives.test.showcase.testutils.MockServerScenarioSetupResetingTestRule
import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule
import org.fnives.test.showcase.testutils.idling.anyResourceIdling import org.fnives.test.showcase.testutils.idling.anyResourceIdling
import org.fnives.test.showcase.compose.ComposeActivity
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -20,8 +20,6 @@ class AuthComposeInstrumentedTest : KoinTest {
@get:Rule @get:Rule
val composeTestRule = createAndroidComposeRule<ComposeActivity>() val composeTestRule = createAndroidComposeRule<ComposeActivity>()
// private lateinit var activityScenario: ActivityScenario<ComposeActivity>
private val mockServerScenarioSetupTestRule = MockServerScenarioSetupResetingTestRule() private val mockServerScenarioSetupTestRule = MockServerScenarioSetupResetingTestRule()
private val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup private val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup
private val mainDispatcherTestRule = MainDispatcherTestRule() private val mainDispatcherTestRule = MainDispatcherTestRule()
@ -38,11 +36,6 @@ class AuthComposeInstrumentedTest : KoinTest {
robot = ComposeLoginRobot(composeTestRule) robot = ComposeLoginRobot(composeTestRule)
} }
// @After
// fun tearDown() {
// activityScenario.safeClose()
// }
/** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */ /** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */
@Test @Test
fun properLoginResultsInNavigationToHome() { fun properLoginResultsInNavigationToHome() {
@ -57,8 +50,10 @@ class AuthComposeInstrumentedTest : KoinTest {
.setUsername("banan") .setUsername("banan")
.assertUsername("banan") .assertUsername("banan")
.assertPassword("alma") .assertPassword("alma")
.clickOnLogin() composeTestRule.mainClock.autoAdvance = false
// .assertLoadingBeforeRequests() robot.clickOnLogin()
composeTestRule.mainClock.advanceTimeByFrame()
robot.assertLoading()
// mainDispatcherTestRule.advanceUntilIdleWithIdlingResources() // mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
// robot.assertNavigatedToHome() // robot.assertNavigatedToHome()

View file

@ -17,8 +17,10 @@ class ComposeLoginRobot(
} }
fun assertPassword(password: String): ComposeLoginRobot = apply { fun assertPassword(password: String): ComposeLoginRobot = apply {
composeTestRule.onNodeWithTag(AuthScreenTag.PasswordVisibilityToggle).performClick() with(composeTestRule) {
composeTestRule.onNodeWithTag(AuthScreenTag.PasswordInput).assertTextContains(password) onNodeWithTag(AuthScreenTag.PasswordVisibilityToggle).performClick()
onNodeWithTag(AuthScreenTag.PasswordInput).assertTextContains(password)
}
} }
fun assertUsername(username: String): ComposeLoginRobot = apply { fun assertUsername(username: String): ComposeLoginRobot = apply {
@ -28,4 +30,8 @@ class ComposeLoginRobot(
fun clickOnLogin(): ComposeLoginRobot = apply { fun clickOnLogin(): ComposeLoginRobot = apply {
composeTestRule.onNodeWithTag(AuthScreenTag.LoginButton).performClick() composeTestRule.onNodeWithTag(AuthScreenTag.LoginButton).performClick()
} }
fun assertLoading(): ComposeLoginRobot = apply {
composeTestRule.onNodeWithTag(AuthScreenTag.LoadingIndicator).assertIsDisplayed()
}
} }

View file

@ -8,12 +8,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -47,10 +42,13 @@ fun AuthScreen(
bottom.linkTo(login.top) bottom.linkTo(login.top)
}) })
if (authScreenState.loading) { if (authScreenState.loading) {
CircularProgressIndicator(Modifier.constrainAs(loading) { CircularProgressIndicator(
bottom.linkTo(login.top) Modifier
centerHorizontallyTo(parent) .testTag(AuthScreenTag.LoadingIndicator)
}) .constrainAs(loading) {
bottom.linkTo(login.top)
centerHorizontallyTo(parent)
})
} }
LoginButton( LoginButton(
modifier = Modifier modifier = Modifier
@ -89,7 +87,8 @@ private fun PasswordField(authScreenState: AuthScreenState) {
Icon( Icon(
painter = rememberAnimatedVectorPainter(image, passwordVisible), painter = rememberAnimatedVectorPainter(image, passwordVisible),
contentDescription = null, contentDescription = null,
modifier = Modifier.clickable { passwordVisible = !passwordVisible } modifier = Modifier
.clickable { passwordVisible = !passwordVisible }
.testTag(AuthScreenTag.PasswordVisibilityToggle) .testTag(AuthScreenTag.PasswordVisibilityToggle)
) )
}, },
@ -144,10 +143,12 @@ private fun Snackbar(authScreenState: AuthScreenState, modifier: Modifier = Modi
@Composable @Composable
private fun LoginButton(modifier: Modifier = Modifier, onClick: () -> Unit) { private fun LoginButton(modifier: Modifier = Modifier, onClick: () -> Unit) {
Box(modifier) { Box(modifier) {
Button(onClick = onClick, Button(
onClick = onClick,
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.testTag(AuthScreenTag.LoginButton)) { .testTag(AuthScreenTag.LoginButton)
) {
Text(text = "Login") Text(text = "Login")
} }
} }
@ -172,6 +173,7 @@ private fun AuthScreenState.ErrorType.stringResId() = when (this) {
object AuthScreenTag { object AuthScreenTag {
const val UsernameInput = "AuthScreenTag.UsernameInput" const val UsernameInput = "AuthScreenTag.UsernameInput"
const val PasswordInput = "AuthScreenTag.PasswordInput" const val PasswordInput = "AuthScreenTag.PasswordInput"
const val LoadingIndicator = "AuthScreenTag.LoadingIndicator"
const val LoginButton = "AuthScreenTag.LoginButton" const val LoginButton = "AuthScreenTag.LoginButton"
const val PasswordVisibilityToggle = "AuthScreenTag.PasswordVisibilityToggle" const val PasswordVisibilityToggle = "AuthScreenTag.PasswordVisibilityToggle"
} }

View file

@ -30,7 +30,7 @@ class NetworkSynchronizationTestRule : TestRule, KoinTest {
@CheckResult @CheckResult
private fun registerNetworkingSynchronization(): Disposable { private fun registerNetworkingSynchronization(): Disposable {
val idlingResources = NetworkTestConfigurationHelper.getOkHttpClients() val idlingResources = NetworkTestConfigurationHelper.getOkHttpClients()//.filterIndexed { index, okHttpClient -> index == 0 }
.associateBy(keySelector = { it.toString() }) .associateBy(keySelector = { it.toString() })
.map { (key, client) -> client.asIdlingResource(key) } .map { (key, client) -> client.asIdlingResource(key) }
.map(::IdlingResourceDisposable) .map(::IdlingResourceDisposable)