Skip to content

Commit

Permalink
MBL-1822: Compose UI tests for ChangePasswordScreen (#2157)
Browse files Browse the repository at this point in the history
  • Loading branch information
leighdouglas authored Oct 30, 2024
1 parent dadcda8 commit 165aa89
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
Expand Down Expand Up @@ -59,6 +60,18 @@ fun ChangePasswordPreview() {
}
}

enum class ChangePasswordScreenTestTag {
BACK_BUTTON,
ACCEPT_BUTTON,
CURRENT_PASSWORD,
NEW_PASSWORD_1,
NEW_PASSWORD_2,
WARNING_TEXT,
PAGE_TITLE,
PROGRESS_BAR,
SUBTITLE,
}

@Composable
fun ChangePasswordScreen(
onBackClicked: () -> Unit,
Expand Down Expand Up @@ -101,11 +114,14 @@ fun ChangePasswordScreen(
TopToolBar(
title = stringResource(id = R.string.Change_password),
titleColor = colors.kds_support_700,
titleModifier = Modifier.testTag(ChangePasswordScreenTestTag.PAGE_TITLE.name),
leftOnClickAction = onBackClicked,
leftIconColor = colors.kds_support_700,
leftIconModifier = Modifier.testTag(ChangePasswordScreenTestTag.BACK_BUTTON.name),
backgroundColor = colors.kds_white,
right = {
IconButton(
modifier = Modifier.testTag(ChangePasswordScreenTestTag.ACCEPT_BUTTON.name),
onClick = {
onAcceptButtonClicked.invoke(
currentPassword,
Expand Down Expand Up @@ -144,11 +160,13 @@ fun ChangePasswordScreen(
.padding(padding)
) {
AnimatedVisibility(visible = showProgressBar) {
KSLinearProgressIndicator(modifier = Modifier.fillMaxWidth())
KSLinearProgressIndicator(
modifier = Modifier.fillMaxWidth().testTag(ChangePasswordScreenTestTag.PROGRESS_BAR.name)
)
}

Text(
modifier = Modifier.padding(dimensions.paddingMedium),
modifier = Modifier.padding(dimensions.paddingMedium).testTag(ChangePasswordScreenTestTag.SUBTITLE.name),
text = stringResource(
id = R.string.Well_ask_you_to_sign_back_into_the_Kickstarter_app_once_youve_changed_your_password
),
Expand All @@ -164,7 +182,7 @@ fun ChangePasswordScreen(
) {

KSHiddenTextInput(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().testTag(ChangePasswordScreenTestTag.CURRENT_PASSWORD.name),
onValueChanged = { currentPassword = it },
label = stringResource(id = R.string.Current_password),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
Expand All @@ -180,7 +198,7 @@ fun ChangePasswordScreen(
Spacer(modifier = Modifier.height(dimensions.listItemSpacingMedium))

KSHiddenTextInput(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().testTag(ChangePasswordScreenTestTag.NEW_PASSWORD_1.name),
onValueChanged = { newPasswordLine1 = it },
label = stringResource(id = R.string.New_password),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
Expand All @@ -196,7 +214,7 @@ fun ChangePasswordScreen(
Spacer(modifier = Modifier.height(dimensions.listItemSpacingMedium))

KSHiddenTextInput(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().testTag(ChangePasswordScreenTestTag.NEW_PASSWORD_2.name),
onValueChanged = { newPasswordLine2 = it },
label = stringResource(id = R.string.Confirm_password),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
Expand All @@ -212,7 +230,7 @@ fun ChangePasswordScreen(

AnimatedVisibility(visible = warningText.isNotEmpty()) {
Text(
modifier = Modifier.padding(dimensions.paddingMedium),
modifier = Modifier.padding(dimensions.paddingMedium).testTag(ChangePasswordScreenTestTag.WARNING_TEXT.name),
text = warningText,
style = typography.body2,
color = colors.kds_support_700
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package com.kickstarter.ui.activities.compose

import androidx.compose.material.rememberScaffoldState
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.isDisplayed
import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextClearance
import androidx.compose.ui.test.performTextInput
import androidx.test.platform.app.InstrumentationRegistry
import com.kickstarter.KSRobolectricTestCase
import com.kickstarter.R
import com.kickstarter.ui.compose.designsystem.KSTheme
import org.junit.Test

class ChangePasswordScreenTest : KSRobolectricTestCase() {
val context = InstrumentationRegistry.getInstrumentation().targetContext

private val backButton =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.BACK_BUTTON.name)

private val acceptButton =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.ACCEPT_BUTTON.name)

private val currentPasswordEditText =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.CURRENT_PASSWORD.name)

private val newPasswordLine1EditText =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.NEW_PASSWORD_1.name)

private val newPasswordLine2EditText =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.NEW_PASSWORD_2.name)

private val warningText =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.WARNING_TEXT.name)

private val pageTitle =
composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.PAGE_TITLE.name)

private val progressBar = composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.PROGRESS_BAR.name)

private val subtitle = composeTestRule.onNodeWithTag(ChangePasswordScreenTestTag.SUBTITLE.name)

@Test
fun `test screen init`() {
composeTestRule.setContent {
KSTheme {
ChangePasswordScreen(
onBackClicked = { },
onAcceptButtonClicked = { _, _ -> },
showProgressBar = false,
scaffoldState = rememberScaffoldState()
)
}
}

val pageTitleText = context.getString(R.string.Change_password)
val changePasswordDescriptionText = context.getString(R.string.Well_ask_you_to_sign_back_into_the_Kickstarter_app_once_youve_changed_your_password)

pageTitle.assertIsDisplayed()
pageTitle.assertTextEquals(pageTitleText)
subtitle.assertIsDisplayed()
subtitle.assertTextEquals(changePasswordDescriptionText)
backButton.assertIsDisplayed()
acceptButton.assertIsDisplayed()
acceptButton.assertIsNotEnabled()
progressBar.assertDoesNotExist()
newPasswordLine1EditText.assertIsDisplayed()
newPasswordLine2EditText.assertIsDisplayed()
currentPasswordEditText.assertIsDisplayed()
warningText.isNotDisplayed()
}

@Test
fun `test back button clicks`() {
composeTestRule.setContent {
KSTheme {
ChangePasswordScreen(
onBackClicked = { },
onAcceptButtonClicked = { _, _ -> },
showProgressBar = false,
scaffoldState = rememberScaffoldState()
)
}
}
}

@Test
fun `when passwords not long enough or matching, accept button disabled and warning text displayed`() {
composeTestRule.setContent {
KSTheme {
ChangePasswordScreen(
onBackClicked = { },
onAcceptButtonClicked = { _, _ -> },
showProgressBar = false,
scaffoldState = rememberScaffoldState()
)
}
}

val passwordMismatchWarningText = context.getString(R.string.Passwords_matching_message)
val passwordLengthWarningText = context.getString(R.string.Password_min_length_message)

// current password too short, button should be disabled but no warning text
currentPasswordEditText.performTextInput("pass")
newPasswordLine1EditText.performTextInput("password1")
newPasswordLine2EditText.performTextInput("password1")

acceptButton.assertIsNotEnabled()
warningText.isNotDisplayed()

currentPasswordEditText.performTextClearance()
newPasswordLine1EditText.performTextClearance()
newPasswordLine2EditText.performTextClearance()

// only one new password field filled out, button should be disabled but no warning text
currentPasswordEditText.performTextInput("password")
newPasswordLine1EditText.performTextInput("password1")

acceptButton.assertIsNotEnabled()
warningText.isNotDisplayed()

currentPasswordEditText.performTextClearance()
newPasswordLine1EditText.performTextClearance()
newPasswordLine2EditText.performTextClearance()

// new passwords not long enough, button should be disabled and no warning text
currentPasswordEditText.performTextInput("password")
newPasswordLine1EditText.performTextInput("pass")
newPasswordLine2EditText.performTextInput("password2")

acceptButton.assertIsNotEnabled()
warningText.isDisplayed()
warningText.assertTextEquals(passwordLengthWarningText)

currentPasswordEditText.performTextClearance()
newPasswordLine1EditText.performTextClearance()
newPasswordLine2EditText.performTextClearance()

// passwords are long enough but don't match, button should be disabled and warning text shows
currentPasswordEditText.performTextInput("password")
newPasswordLine1EditText.performTextInput("password1")
newPasswordLine2EditText.performTextInput("password2")

acceptButton.assertIsNotEnabled()
warningText.isDisplayed()
warningText.assertTextEquals(passwordMismatchWarningText)
}

@Test
fun `when passwords valid and matching, accept button enabled and no warning text visible`() {
var acceptButtonClickedCount = 0
composeTestRule.setContent {
KSTheme {
ChangePasswordScreen(
onBackClicked = { },
onAcceptButtonClicked = { _, _ -> acceptButtonClickedCount++ },
showProgressBar = false,
scaffoldState = rememberScaffoldState()
)
}
}

// valid password and matching
currentPasswordEditText.performTextInput("password")
newPasswordLine1EditText.performTextInput("passwordA")
newPasswordLine2EditText.performTextInput("passwordA")

acceptButton.assertIsEnabled()
warningText.isNotDisplayed()
acceptButton.performClick()
assertEquals(1, acceptButtonClickedCount)
}
}

0 comments on commit 165aa89

Please sign in to comment.