From d9725e31e6a12fc53867e4dec0dccc240ab20187 Mon Sep 17 00:00:00 2001 From: Alex Gabor Date: Fri, 1 Apr 2022 16:06:35 +0300 Subject: [PATCH] Cover all auth tests --- .../ui/AuthComposeInstrumentedTest.kt | 98 +++++++++++++++++-- .../test/showcase/ui/ComposeLoginRobot.kt | 11 +++ ...reenRobot.kt => ComposeNavigationRobot.kt} | 11 +-- .../compose/screen/auth/AuthScreen.kt | 3 +- 4 files changed, 110 insertions(+), 13 deletions(-) rename app/src/androidTest/java/org/fnives/test/showcase/ui/{ComposeScreenRobot.kt => ComposeNavigationRobot.kt} (62%) diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/AuthComposeInstrumentedTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/AuthComposeInstrumentedTest.kt index 62966fc..b4e21fb 100644 --- a/app/src/androidTest/java/org/fnives/test/showcase/ui/AuthComposeInstrumentedTest.kt +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/AuthComposeInstrumentedTest.kt @@ -2,6 +2,7 @@ package org.fnives.test.showcase.ui import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.fnives.test.showcase.R import org.fnives.test.showcase.compose.ComposeActivity import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario import org.fnives.test.showcase.testutils.MockServerScenarioSetupResetingTestRule @@ -25,7 +26,7 @@ class AuthComposeInstrumentedTest : KoinTest { private val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup private val mainDispatcherTestRule = ComposeMainDispatcherTestRule() private lateinit var robot: ComposeLoginRobot - private lateinit var screenRobot: ComposeScreenRobot + private lateinit var navigationRobot: ComposeNavigationRobot @Rule @JvmField @@ -36,7 +37,7 @@ class AuthComposeInstrumentedTest : KoinTest { @Before fun setup() { robot = ComposeLoginRobot(composeTestRule) - screenRobot = ComposeScreenRobot(composeTestRule) + navigationRobot = ComposeNavigationRobot(composeTestRule) } /** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */ @@ -47,9 +48,8 @@ class AuthComposeInstrumentedTest : KoinTest { ) composeTestRule.mainClock.advanceTimeBy(500L) composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } - screenRobot.assertAuthScreen() - robot - .setPassword("alma") + navigationRobot.assertAuthScreen() + robot.setPassword("alma") .setUsername("banan") .assertUsername("banan") .assertPassword("alma") @@ -61,7 +61,93 @@ class AuthComposeInstrumentedTest : KoinTest { composeTestRule.mainClock.autoAdvance = true composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } - screenRobot.assertHomeScreen() + navigationRobot.assertHomeScreen() } + /** GIVEN empty password and username WHEN signIn THEN error password is shown */ + @Test + fun emptyPasswordShowsProperErrorMessage() { + composeTestRule.mainClock.advanceTimeBy(500L) + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + navigationRobot.assertAuthScreen() + + robot.setUsername("banan") + .assertUsername("banan") + .clickOnLogin() + + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + robot.assertErrorIsShown(R.string.password_is_invalid) + .assertNotLoading() + navigationRobot.assertAuthScreen() + } + + /** GIVEN password and empty username WHEN signIn THEN error username is shown */ + @Test + fun emptyUserNameShowsProperErrorMessage() { + composeTestRule.mainClock.advanceTimeBy(500L) + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + navigationRobot.assertAuthScreen() + + robot + .setPassword("banan") + .assertPassword("banan") + .clickOnLogin() + + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + robot.assertErrorIsShown(R.string.username_is_invalid) + .assertNotLoading() + navigationRobot.assertAuthScreen() + } + + /** GIVEN password and username and invalid credentials response WHEN signIn THEN error invalid credentials is shown */ + @Test + fun invalidCredentialsGivenShowsProperErrorMessage() { + mockServerScenarioSetup.setScenario( + AuthScenario.InvalidCredentials(password = "alma", username = "banan") + ) + composeTestRule.mainClock.advanceTimeBy(500L) + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + navigationRobot.assertAuthScreen() + robot.setUsername("alma") + .setPassword("banan") + .assertUsername("alma") + .assertPassword("banan") + + composeTestRule.mainClock.autoAdvance = false + robot.clickOnLogin() + composeTestRule.mainClock.advanceTimeByFrame() + robot.assertLoading() + composeTestRule.mainClock.autoAdvance = true + + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + robot.assertErrorIsShown(R.string.credentials_invalid) + .assertNotLoading() + navigationRobot.assertAuthScreen() + } + + /** GIVEN password and username and error response WHEN signIn THEN error invalid credentials is shown */ + @Test + fun networkErrorShowsProperErrorMessage() { + mockServerScenarioSetup.setScenario( + AuthScenario.GenericError(username = "alma", password = "banan") + ) + composeTestRule.mainClock.advanceTimeBy(500L) + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + navigationRobot.assertAuthScreen() + robot.setUsername("alma") + .setPassword("banan") + .assertUsername("alma") + .assertPassword("banan") + + composeTestRule.mainClock.autoAdvance = false + robot.clickOnLogin() + composeTestRule.mainClock.advanceTimeByFrame() + robot.assertLoading() + composeTestRule.mainClock.autoAdvance = true + + composeTestRule.mainClock.advanceTimeUntil { anyResourceIdling() } + robot.assertErrorIsShown(R.string.something_went_wrong) + .assertNotLoading() + navigationRobot.assertAuthScreen() + } } \ No newline at end of file diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeLoginRobot.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeLoginRobot.kt index c792769..53c237d 100644 --- a/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeLoginRobot.kt +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeLoginRobot.kt @@ -1,7 +1,9 @@ package org.fnives.test.showcase.ui +import android.content.Context import androidx.compose.ui.test.* import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.test.core.app.ApplicationProvider import org.fnives.test.showcase.compose.screen.auth.AuthScreenTag class ComposeLoginRobot( @@ -34,4 +36,13 @@ class ComposeLoginRobot( fun assertLoading(): ComposeLoginRobot = apply { composeTestRule.onNodeWithTag(AuthScreenTag.LoadingIndicator).assertIsDisplayed() } + fun assertNotLoading(): ComposeLoginRobot = apply { + composeTestRule.onAllNodesWithTag(AuthScreenTag.LoadingIndicator).assertCountEquals(0) + } + + fun assertErrorIsShown(stringId: Int): ComposeLoginRobot = apply { + composeTestRule.onNodeWithTag(AuthScreenTag.LoginError) + .assertTextContains(ApplicationProvider.getApplicationContext().resources.getString(stringId)) + } + } \ No newline at end of file diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeScreenRobot.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeNavigationRobot.kt similarity index 62% rename from app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeScreenRobot.kt rename to app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeNavigationRobot.kt index a9c9542..881875f 100644 --- a/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeScreenRobot.kt +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/ComposeNavigationRobot.kt @@ -1,19 +1,18 @@ package org.fnives.test.showcase.ui -import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.onNodeWithTag import org.fnives.test.showcase.compose.screen.AppNavigationTag -class ComposeScreenRobot( +class ComposeNavigationRobot( private val composeTestRule: ComposeTestRule, ) { - fun assertHomeScreen(): ComposeScreenRobot = apply { - composeTestRule.onNodeWithTag(AppNavigationTag.HomeScreen).assertIsDisplayed() + fun assertHomeScreen(): ComposeNavigationRobot = apply { + composeTestRule.onNodeWithTag(AppNavigationTag.HomeScreen).assertExists() } - fun assertAuthScreen(): ComposeScreenRobot = apply { - composeTestRule.onNodeWithTag(AppNavigationTag.AuthScreen).assertIsDisplayed() + fun assertAuthScreen(): ComposeNavigationRobot = apply { + composeTestRule.onNodeWithTag(AppNavigationTag.AuthScreen).assertExists() } } \ No newline at end of file diff --git a/app/src/main/java/org/fnives/test/showcase/compose/screen/auth/AuthScreen.kt b/app/src/main/java/org/fnives/test/showcase/compose/screen/auth/AuthScreen.kt index 21ed15a..708d115 100644 --- a/app/src/main/java/org/fnives/test/showcase/compose/screen/auth/AuthScreen.kt +++ b/app/src/main/java/org/fnives/test/showcase/compose/screen/auth/AuthScreen.kt @@ -135,7 +135,7 @@ private fun Snackbar(authScreenState: AuthScreenState, modifier: Modifier = Modi val stringId = error?.stringResId() if (stringId != null) { Snackbar(modifier = Modifier.padding(horizontal = 16.dp)) { - Text(text = stringResource(stringId)) + Text(text = stringResource(stringId), Modifier.testTag(AuthScreenTag.LoginError)) } } } @@ -176,5 +176,6 @@ object AuthScreenTag { const val PasswordInput = "AuthScreenTag.PasswordInput" const val LoadingIndicator = "AuthScreenTag.LoadingIndicator" const val LoginButton = "AuthScreenTag.LoginButton" + const val LoginError = "AuthScreenTag.LoginError" const val PasswordVisibilityToggle = "AuthScreenTag.PasswordVisibilityToggle" }