[#1016] Force SecureScreen turned on in UI testing

- After we added the customization of SecureScreen sensitive data mechanism in building and testing the app via Gradle property in #1009, we also need to ensure that the SecureScreen is always on in our automated Android UI tests.
- Closes #1016
This commit is contained in:
Honza Rychnovský 2023-10-23 15:21:00 +02:00 committed by GitHub
parent ab7117e458
commit 2f773b8b0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 12 deletions

View File

@ -7,6 +7,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import androidx.test.filters.SmallTest
import co.electriccoin.zcash.test.UiTestPrerequisites import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -15,11 +16,30 @@ import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ScreenSecurityTest : UiTestPrerequisites() { class ScreenSecurityTest : UiTestPrerequisites() {
@get:Rule @get:Rule
val composeTestRule = createComposeRule() val composeTestRule = createComposeRule()
@Test
@SmallTest
fun sanity_is_running_test_check() {
assertTrue(
actual = isRunningTest,
message = "isRunningTest must always be TRUE while running from an automated Android UI test."
)
}
@Test
@SmallTest
fun sanity_should_secure_screen_check() {
assertTrue(
actual = shouldSecureScreen,
message = "shouldSecureScreen must always be TRUE while running from an automated Android UI test."
)
}
@Test @Test
@MediumTest @MediumTest
fun acquireAndReleaseScreenSecurity() = runTest { fun acquireAndReleaseScreenSecurity() = runTest {

View File

@ -9,13 +9,11 @@ import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.common.LocalScreenSecurity import co.electriccoin.zcash.ui.common.LocalScreenSecurity
import co.electriccoin.zcash.ui.common.ScreenSecurity import co.electriccoin.zcash.ui.common.ScreenSecurity
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@OptIn(ExperimentalCoroutinesApi::class)
class SeedViewSecuredScreenTest : UiTestPrerequisites() { class SeedViewSecuredScreenTest : UiTestPrerequisites() {
@get:Rule @get:Rule
val composeTestRule = createComposeRule() val composeTestRule = createComposeRule()

View File

@ -3,6 +3,8 @@ package co.electriccoin.zcash.ui.common
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.BuildConfig
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
@ -29,6 +31,28 @@ class ScreenSecurity {
@Suppress("CompositionLocalAllowlist") @Suppress("CompositionLocalAllowlist")
val LocalScreenSecurity = compositionLocalOf { ScreenSecurity() } val LocalScreenSecurity = compositionLocalOf { ScreenSecurity() }
/**
* Returns true only if it's used from the automated Android UI testing.
*/
val isRunningTest: Boolean by lazy {
runCatching {
Class.forName("androidx.test.espresso.Espresso")
true
}.getOrDefault(false).also {
Twig.debug { "Running in UI test: $it" }
}
}
/**
* Decides whether the SecureScreen should be activated depending on [isRunningTest] and Gradle
* [BuildConfig.IS_SECURE_SCREEN_ENABLED].
*/
val shouldSecureScreen: Boolean by lazy {
if (isRunningTest) {
true
} else BuildConfig.IS_SECURE_SCREEN_ENABLED
}
@Composable @Composable
fun SecureScreen() { fun SecureScreen() {
val screenSecurity = LocalScreenSecurity.current val screenSecurity = LocalScreenSecurity.current

View File

@ -43,9 +43,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cash.z.ecc.android.sdk.model.PersistableWallet import cash.z.ecc.android.sdk.model.PersistableWallet
import cash.z.ecc.sdk.fixture.PersistableWalletFixture import cash.z.ecc.sdk.fixture.PersistableWalletFixture
import co.electriccoin.zcash.spackle.model.Index import co.electriccoin.zcash.spackle.model.Index
import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.SecureScreen import co.electriccoin.zcash.ui.common.SecureScreen
import co.electriccoin.zcash.ui.common.shouldSecureScreen
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.Body import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.CHIP_GRID_ROW_SIZE import co.electriccoin.zcash.ui.design.component.CHIP_GRID_ROW_SIZE
@ -203,7 +203,7 @@ private fun EducationRecoveryPhrase() {
@Composable @Composable
private fun SeedPhrase(persistableWallet: PersistableWallet) { private fun SeedPhrase(persistableWallet: PersistableWallet) {
if (BuildConfig.IS_SECURE_SCREEN_ENABLED) { if (shouldSecureScreen) {
SecureScreen() SecureScreen()
} }
Column( Column(
@ -235,7 +235,7 @@ private fun TestInProgress(
onChoicesChanged: ((choicesCount: Int) -> Unit)?, onChoicesChanged: ((choicesCount: Int) -> Unit)?,
backupState: BackupState backupState: BackupState
) { ) {
if (BuildConfig.IS_SECURE_SCREEN_ENABLED) { if (shouldSecureScreen) {
SecureScreen() SecureScreen()
} }
val testChoices = splitSeedPhrase val testChoices = splitSeedPhrase

View File

@ -32,9 +32,9 @@ import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import cash.z.ecc.android.sdk.model.PersistableWallet import cash.z.ecc.android.sdk.model.PersistableWallet
import cash.z.ecc.sdk.fixture.PersistableWalletFixture import cash.z.ecc.sdk.fixture.PersistableWalletFixture
import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.SecureScreen import co.electriccoin.zcash.ui.common.SecureScreen
import co.electriccoin.zcash.ui.common.shouldSecureScreen
import co.electriccoin.zcash.ui.design.component.Body import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.ChipGrid import co.electriccoin.zcash.ui.design.component.ChipGrid
import co.electriccoin.zcash.ui.design.component.GradientSurface import co.electriccoin.zcash.ui.design.component.GradientSurface
@ -59,7 +59,6 @@ private fun ComposablePreviewShort() {
/** /**
* @param onComplete Callback when the user has confirmed viewing the seed phrase. * @param onComplete Callback when the user has confirmed viewing the seed phrase.
*/ */
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ShortNewWalletBackup( fun ShortNewWalletBackup(
wallet: PersistableWallet, wallet: PersistableWallet,
@ -112,7 +111,7 @@ private fun ShortNewWalletMainContent(
@Composable @Composable
private fun SeedPhrase(persistableWallet: PersistableWallet) { private fun SeedPhrase(persistableWallet: PersistableWallet) {
if (BuildConfig.IS_SECURE_SCREEN_ENABLED) { if (shouldSecureScreen) {
SecureScreen() SecureScreen()
} }
Column { Column {

View File

@ -63,9 +63,9 @@ import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.ZcashNetwork import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.sdk.model.SeedPhraseValidation import cash.z.ecc.sdk.model.SeedPhraseValidation
import co.electriccoin.zcash.spackle.model.Index import co.electriccoin.zcash.spackle.model.Index
import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.SecureScreen import co.electriccoin.zcash.ui.common.SecureScreen
import co.electriccoin.zcash.ui.common.shouldSecureScreen
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.Body import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.CHIP_GRID_ROW_SIZE import co.electriccoin.zcash.ui.design.component.CHIP_GRID_ROW_SIZE
@ -202,7 +202,7 @@ fun RestoreWallet(
when (currentStage) { when (currentStage) {
RestoreStage.Seed -> { RestoreStage.Seed -> {
if (BuildConfig.IS_SECURE_SCREEN_ENABLED) { if (shouldSecureScreen) {
SecureScreen() SecureScreen()
} }

View File

@ -22,9 +22,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import cash.z.ecc.android.sdk.model.PersistableWallet import cash.z.ecc.android.sdk.model.PersistableWallet
import cash.z.ecc.sdk.fixture.PersistableWalletFixture import cash.z.ecc.sdk.fixture.PersistableWalletFixture
import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.SecureScreen import co.electriccoin.zcash.ui.common.SecureScreen
import co.electriccoin.zcash.ui.common.shouldSecureScreen
import co.electriccoin.zcash.ui.design.component.Body import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.ChipGrid import co.electriccoin.zcash.ui.design.component.ChipGrid
import co.electriccoin.zcash.ui.design.component.GradientSurface import co.electriccoin.zcash.ui.design.component.GradientSurface
@ -56,7 +56,7 @@ fun Seed(
onBack: () -> Unit, onBack: () -> Unit,
onCopyToClipboard: () -> Unit onCopyToClipboard: () -> Unit
) { ) {
if (BuildConfig.IS_SECURE_SCREEN_ENABLED) { if (shouldSecureScreen) {
SecureScreen() SecureScreen()
} }
Scaffold(topBar = { Scaffold(topBar = {