Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-01 09:47:32 +02:00
parent 2110b5f541
commit 53c0546b5c
8 changed files with 9 additions and 96 deletions

View file

@ -93,6 +93,13 @@ Scenario files orchestrate flows; they must not define page objects or duplicate
`com.tangem.core.res.R` or `com.tangem.core.ui.R`. The Detekt rule `UnsafeStringResourceUsage` `com.tangem.core.res.R` or `com.tangem.core.ui.R`. The Detekt rule `UnsafeStringResourceUsage`
enforces this for production code; reviewers extend it to test code informally. enforces this for production code; reviewers extend it to test code informally.
### Allure IDs
- **Every test method gets its own unique `@AllureId`.** Never reuse the same id across two test methods —
not even for two variants of one manual case. If a manual case is split into multiple automated tests
(e.g. a positive and a negative variant), each test must be linked to its own distinct Allure case/id.
(Note: iOS sometimes shares one id across methods — do NOT mirror that here.)
### Assertions ### Assertions
- **Never** use Kotlin's built-in `assert(...)` — Android instrumentation runs don't enable JVM - **Never** use Kotlin's built-in `assert(...)` — Android instrumentation runs don't enable JVM

View file

@ -46,10 +46,6 @@ class DeviceSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
useUnmergedTree = true useUnmergedTree = true
} }
val securityModeRow: KNode = child {
hasTestTag(DeviceSettingsScreenTestTags.SECURITY_MODE_ROW)
}
fun resetToFactorySettingsButtonSubtitle(withBackup: Boolean = false): KNode = child { fun resetToFactorySettingsButtonSubtitle(withBackup: Boolean = false): KNode = child {
hasTestTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE) hasTestTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE)
useUnmergedTree = true useUnmergedTree = true

View file

@ -1,19 +0,0 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.test.SecurityModeScreenTestTags
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
import io.github.kakaocup.compose.node.element.KNode
class SecurityModePageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SecurityModePageObject>(semanticsProvider = semanticsProvider) {
val screenContainer: KNode = child {
hasTestTag(SecurityModeScreenTestTags.SCREEN_CONTAINER)
}
}
internal fun BaseTestCase.onSecurityModeScreen(function: SecurityModePageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -1,55 +0,0 @@
package com.tangem.tests
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.domain.models.scan.ProductType
import com.tangem.scenarios.openDeviceSettingsScreen
import com.tangem.scenarios.openMainScreen
import com.tangem.screens.*
import dagger.hilt.android.testing.HiltAndroidTest
import io.qameta.allure.kotlin.AllureId
import io.qameta.allure.kotlin.junit4.DisplayName
import org.junit.Test
@HiltAndroidTest
class SecurityModeTest : BaseTestCase() {
@AllureId("2267")
@DisplayName("Security Mode: Twin card opens the section")
@Test
fun twinSecurityModeOpensTest() =
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen(productType = ProductType.Twins, isTwinsCard = true)
}
openDeviceSettingsScreen()
step("Click on 'Scan card or ring' button") {
onDeviceSettingsScreen { scanCardOrRingButton.clickWithAssertion() }
}
step("Assert 'Security Mode' row is enabled") {
onDeviceSettingsScreen { securityModeRow.assertIsEnabled() }
}
step("Click on 'Security Mode' row") {
onDeviceSettingsScreen { securityModeRow.clickWithAssertion() }
}
step("Assert 'Security Mode' screen is displayed") {
onSecurityModeScreen { screenContainer.assertIsDisplayed() }
}
}
@DisplayName("Security Mode: other cards cannot open the section")
@Test
fun walletSecurityModeDisabledTest() =
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
openDeviceSettingsScreen()
step("Click on 'Scan card or ring' button") {
onDeviceSettingsScreen { scanCardOrRingButton.clickWithAssertion() }
}
step("Assert 'Security Mode' row is not clickable") {
onDeviceSettingsScreen { securityModeRow.assertIsNotEnabled() }
}
}
}

View file

@ -125,7 +125,7 @@ private fun ScanCardContent(onScanCardClick: () -> Unit) {
} }
} }
@Suppress("ComplexMethod", "LongMethod") @Suppress("ComplexMethod")
@Composable @Composable
private fun CardSettings(state: CardSettingsScreenState) { private fun CardSettings(state: CardSettingsScreenState) {
if (state.cardDetails == null) return if (state.cardDetails == null) return
@ -156,13 +156,6 @@ private fun CardSettings(state: CardSettingsScreenState) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.then(
if (cardInfo is CardInfo.SecurityMode) {
Modifier.testTag(DeviceSettingsScreenTestTags.SECURITY_MODE_ROW)
} else {
Modifier
},
)
.clickable( .clickable(
enabled = cardInfo.isClickable, enabled = cardInfo.isClickable,
onClick = { state.onElementClick(cardInfo) }, onClick = { state.onElementClick(cardInfo) },

View file

@ -5,11 +5,9 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.test.SecurityModeScreenTestTags
import com.tangem.tap.features.details.redux.SecurityOption import com.tangem.tap.features.details.redux.SecurityOption
import com.tangem.tap.features.details.ui.common.DetailsMainButton import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.DetailsRadioButtonElement import com.tangem.tap.features.details.ui.common.DetailsRadioButtonElement
@ -37,8 +35,7 @@ private fun SecurityModeOptions(state: SecurityModeScreenState) {
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(bottom = 28.dp) .padding(bottom = 28.dp),
.testTag(SecurityModeScreenTestTags.SCREEN_CONTAINER),
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
) { ) {
ScreenTitle(titleRes = R.string.card_settings_security_mode, Modifier.padding(bottom = 36.dp)) ScreenTitle(titleRes = R.string.card_settings_security_mode, Modifier.padding(bottom = 36.dp))

View file

@ -5,5 +5,4 @@ object DeviceSettingsScreenTestTags {
const val IMAGE_BLOCK = "DEVICE_SETTINGS_SCREEN_IMAGE_BLOCK" const val IMAGE_BLOCK = "DEVICE_SETTINGS_SCREEN_IMAGE_BLOCK"
const val ITEM_TITLE = "DEVICE_SETTINGS_SCREEN_ITEM_TITLE" const val ITEM_TITLE = "DEVICE_SETTINGS_SCREEN_ITEM_TITLE"
const val ITEM_SUBTITLE = "DEVICE_SETTINGS_SCREEN_ITEM_SUBTITLE" const val ITEM_SUBTITLE = "DEVICE_SETTINGS_SCREEN_ITEM_SUBTITLE"
const val SECURITY_MODE_ROW = "DEVICE_SETTINGS_SCREEN_SECURITY_MODE_ROW"
} }

View file

@ -1,5 +0,0 @@
package com.tangem.core.ui.test
object SecurityModeScreenTestTags {
const val SCREEN_CONTAINER = "SECURITY_MODE_SCREEN_CONTAINER"
}