diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt index d0fa784cad..0cf28bc27e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext @@ -40,6 +41,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.state.ToggleableState import androidx.compose.ui.text.buildAnnotatedString @@ -80,7 +83,7 @@ import com.x8bit.bitwarden.ui.platform.theme.clickableSpanStyle /** * Top level composable for the create account screen. */ -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @Suppress("LongMethod") @Composable fun CreateAccountScreen( @@ -188,6 +191,7 @@ fun CreateAccountScreen( ) { innerPadding -> Column( modifier = Modifier + .semantics { testTagsAsResourceId = true } .padding(innerPadding) .fillMaxSize() .background(color = MaterialTheme.colorScheme.surface) @@ -201,6 +205,7 @@ fun CreateAccountScreen( { viewModel.trySendAction(EmailInputChange(it)) } }, modifier = Modifier + .semantics { testTag = "EmailAddressEntry" } .fillMaxWidth() .padding(horizontal = 16.dp), keyboardType = KeyboardType.Email, @@ -217,8 +222,10 @@ fun CreateAccountScreen( { viewModel.trySendAction(PasswordInputChange(it)) } }, modifier = Modifier + .semantics { testTag = "MasterPasswordEntry" } .fillMaxWidth() .padding(horizontal = 16.dp), + showPasswordTestTag = "PasswordVisibilityToggle", ) Spacer(modifier = Modifier.height(8.dp)) PasswordStrengthIndicator( @@ -235,8 +242,10 @@ fun CreateAccountScreen( { viewModel.trySendAction(ConfirmPasswordInputChange(it)) } }, modifier = Modifier + .semantics { testTag = "ConfirmMasterPasswordEntry" } .fillMaxWidth() .padding(horizontal = 16.dp), + showPasswordTestTag = "ConfirmPasswordVisibilityToggle", ) Spacer(modifier = Modifier.height(16.dp)) BitwardenTextField( @@ -247,6 +256,7 @@ fun CreateAccountScreen( }, hint = stringResource(id = R.string.master_password_hint_description), modifier = Modifier + .semantics { testTag = "MasterPasswordHintLabel" } .fillMaxWidth() .padding(horizontal = 16.dp), ) @@ -260,6 +270,7 @@ fun CreateAccountScreen( } }, modifier = Modifier + .semantics { testTag = "CheckExposedMasterPasswordToggle" } .padding(horizontal = 16.dp), ) Spacer(modifier = Modifier.height(8.dp)) @@ -308,6 +319,7 @@ private fun TermsAndPrivacySwitch( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .semantics(mergeDescendants = true) { + testTag = "AcceptPoliciesToggle" toggleableState = ToggleableState(isChecked) customActions = listOf( CustomAccessibilityAction( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt index d3cf75f501..229ad9dbef 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt @@ -1,5 +1,7 @@ package com.x8bit.bitwarden.ui.platform.components +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -19,6 +21,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation @@ -48,6 +52,7 @@ fun BitwardenPasswordField( onValueChange: (String) -> Unit, modifier: Modifier = Modifier, hint: String? = null, + showPasswordTestTag: String? = null, ) { Column( modifier = modifier, @@ -69,19 +74,21 @@ fun BitwardenPasswordField( IconButton( onClick = { showPasswordChange.invoke(!showPassword) }, ) { - if (showPassword) { - Icon( - painter = painterResource(id = R.drawable.ic_visibility_off), - contentDescription = stringResource(id = R.string.hide), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) + @DrawableRes + val painterRes = if (showPassword) { + R.drawable.ic_visibility_off } else { - Icon( - painter = painterResource(id = R.drawable.ic_visibility), - contentDescription = stringResource(id = R.string.show), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) + R.drawable.ic_visibility } + + @StringRes + val contentDescriptionRes = if (showPassword) R.string.hide else R.string.show + Icon( + modifier = Modifier.semantics { showPasswordTestTag?.let { testTag = it } }, + painter = painterResource(id = painterRes), + contentDescription = stringResource(id = contentDescriptionRes), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) } }, )