Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-10 15:40:37 +03:00
parent a163569c86
commit a253674fe6
13 changed files with 639 additions and 8 deletions

View file

@ -49,4 +49,16 @@ fun BaseTestCase.synchronizeAddresses(balance: String) {
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
}
fun BaseTestCase.openDeviceSettingsScreen() {
step("Open wallet details") {
onTopBar { moreButton.clickWithAssertion() }
}
step("Open 'Wallet settings' screen") {
onDetailsScreen { walletNameButton.performClick() }
}
step("Click on 'Device settings' button") {
onWalletSettingsScreen { deviceSettingsButton.clickWithAssertion() }
}
}

View file

@ -0,0 +1,21 @@
package com.tangem.scenarios
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.screens.onDeviceSettingsScreen
import io.qameta.allure.kotlin.Allure.step
fun BaseTestCase.openResetCardScreen(withBackup: Boolean = false) {
step("Click on 'Scan card or ring' button") {
onDeviceSettingsScreen { scanCardOrRingButton.clickWithAssertion() }
}
step("Assert 'Reset to Factory Settings' button title is displayed") {
onDeviceSettingsScreen { resetToFactorySettingsButtonTitle.assertIsDisplayed() }
}
step("Assert 'Reset to Factory Settings' button subtitle is displayed") {
onDeviceSettingsScreen { resetToFactorySettingsButtonSubtitle(withBackup).assertIsDisplayed() }
}
step("Click on 'Reset to Factory Settings' button") {
onDeviceSettingsScreen { resetToFactorySettingsButtonTitle.performClick() }
}
}

View file

@ -0,0 +1,80 @@
package com.tangem.scenarios
import com.tangem.common.BaseTestCase
import com.tangem.screens.onResetCardScreen
import io.qameta.allure.kotlin.Allure.step
fun BaseTestCase.checkResetCardScreen(withBackup: Boolean = false) {
step("Assert title is displayed") {
onResetCardScreen { title.assertIsDisplayed() }
}
step("Assert 'Attention' image is displayed") {
onResetCardScreen { attentionImage.assertIsDisplayed() }
}
step("Assert 'Attention' subtitle is displayed") {
onResetCardScreen { subtitle.assertIsDisplayed() }
}
step("Assert description is displayed") {
onResetCardScreen { description.assertIsDisplayed() }
}
step("Assert 'Lost wallet' checkbox is displayed") {
onResetCardScreen { lostWalletAccessCheckBox.assertIsDisplayed() }
}
if (withBackup) {
step("Assert 'Lost password restore' checkbox is displayed") {
onResetCardScreen { lostPasswordRestoreCheckBox.assertIsDisplayed() }
}
} else {
step("Assert 'Lost password restore' checkbox doesn't exist") {
onResetCardScreen { lostPasswordRestoreCheckBox.assertDoesNotExist() }
}
}
}
fun BaseTestCase.checkCheckBoxLogic(withBackup: Boolean = false) {
if (withBackup) {
step("Click on 'Lost wallet' checkbox") {
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
}
step("Assert 'Lost wallet' checkbox is enabled") {
onResetCardScreen { lostWalletAccessCheckBox.assertIsEnabled() }
}
step("Assert 'Reset the card' button is disabled") {
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
}
step("Click on 'Lost password restore' checkbox") {
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
}
step("Assert 'Lost password restore' checkbox is enabled") {
onResetCardScreen { lostPasswordRestoreCheckBox.assertIsEnabled() }
}
step("Assert 'Reset the card' button is enabled") {
onResetCardScreen { resetCardButton.assertIsEnabled() }
}
step("Click on 'Lost password restore' checkbox") {
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
}
step("Assert 'Reset the card' button is disabled") {
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
}
step("Click on 'Lost wallet' checkbox") {
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
}
step("Click on 'Lost password restore' checkbox") {
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
}
step("Assert 'Reset the card' button is disabled") {
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
}
} else {
step("Click on 'Lost wallet' checkbox") {
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
}
step("Assert 'Lost wallet' checkbox is enabled") {
onResetCardScreen { lostWalletAccessCheckBox.assertIsEnabled() }
}
step("Assert 'Reset the card' button is enabled") {
onResetCardScreen { resetCardButton.assertIsEnabled() }
}
}
}

View file

@ -0,0 +1,61 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.common.utils.LazyListItemNode
import com.tangem.core.ui.test.BaseButtonTestTags
import com.tangem.core.ui.test.DeviceSettingsScreenTestTags
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
import com.tangem.wallet.R
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
import io.github.kakaocup.compose.node.element.lazylist.KLazyListNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
class DeviceSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<DeviceSettingsPageObject>(semanticsProvider = semanticsProvider) {
private val lazyList = KLazyListNode(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(DeviceSettingsScreenTestTags.LAZY_LIST) },
itemTypeBuilder = { itemType(::LazyListItemNode) },
positionMatcher = { position ->
SemanticsMatcher.expectValue(
LazyListItemPositionSemantics,
position
)
}
)
val imageBlock: KNode = child {
hasTestTag(DeviceSettingsScreenTestTags.IMAGE_BLOCK)
useUnmergedTree = true
}
val resetToFactorySettingsButtonTitle: KNode = child {
hasTestTag(DeviceSettingsScreenTestTags.ITEM_TITLE)
hasText(getResourceString(R.string.card_settings_reset_card_to_factory))
useUnmergedTree = true
}
val scanCardOrRingButton: KNode = child {
hasTestTag(BaseButtonTestTags.TEXT)
hasText(getResourceString(R.string.scan_card_settings_button))
useUnmergedTree = true
}
fun resetToFactorySettingsButtonSubtitle(withBackup: Boolean = false): KNode = child {
hasTestTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE)
useUnmergedTree = true
if (withBackup) {
hasText(getResourceString(R.string.reset_card_with_backup_to_factory_message))
} else {
hasText(getResourceString(R.string.reset_card_without_backup_to_factory_message))
}
}
}
internal fun BaseTestCase.onDeviceSettingsScreen(function: DeviceSettingsPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,65 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.test.BaseButtonTestTags
import com.tangem.core.ui.test.ResetCardScreenTestTags
import com.tangem.wallet.R
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
import io.github.kakaocup.kakao.common.utilities.getResourceString
import androidx.compose.ui.test.hasTestTag as withTestTag
import androidx.compose.ui.test.hasText as withText
class ResetCardPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<ResetCardPageObject>(semanticsProvider = semanticsProvider) {
val title: KNode = child {
hasTestTag(ResetCardScreenTestTags.TITLE)
hasText(getResourceString(R.string.card_settings_reset_card_to_factory))
useUnmergedTree = true
}
val attentionImage: KNode = child {
hasTestTag(ResetCardScreenTestTags.ATTENTION_IMAGE)
useUnmergedTree = true
}
val subtitle: KNode = child {
hasTestTag(ResetCardScreenTestTags.SUBTITLE)
hasText(getResourceString(R.string.common_attention))
useUnmergedTree = true
}
val description: KNode = child {
hasTestTag(ResetCardScreenTestTags.DESCRIPTION)
useUnmergedTree = true
}
val lostWalletAccessCheckBox: KNode = child {
hasTestTag(ResetCardScreenTestTags.CHECKBOX)
hasAnySibling(
withTestTag(ResetCardScreenTestTags.CHECKBOX_TEXT) and
withText(getResourceString(R.string.reset_card_to_factory_condition_1))
)
useUnmergedTree = true
}
val lostPasswordRestoreCheckBox: KNode = child {
hasTestTag(ResetCardScreenTestTags.CHECKBOX)
hasAnySibling(
withTestTag(ResetCardScreenTestTags.CHECKBOX_TEXT) and
withText(getResourceString(R.string.reset_card_to_factory_condition_2))
)
useUnmergedTree = true
}
val resetCardButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.reset_card_to_factory_button_title))
}
}
internal fun BaseTestCase.onResetCardScreen(function: ResetCardPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -21,7 +21,7 @@ class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
val linkMoreCardsButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.details_row_title_create_backup))
}
val cardSettingsButton: KNode = walletSettingsItem.child {
val deviceSettingsButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.card_settings_title))
}
val referralProgramButton: KNode = walletSettingsItem.child {

View file

@ -55,7 +55,7 @@ class DetailsTest : BaseTestCase() {
linkMoreCardsButton.assertIsDisplayed()
}
step("Assert 'Card Settings' button is visible") {
cardSettingsButton.assertIsDisplayed()
deviceSettingsButton.assertIsDisplayed()
}
step("Assert 'Referral program' button is visible") {
referralProgramButton.assertIsDisplayed()
@ -105,7 +105,7 @@ class DetailsTest : BaseTestCase() {
linkMoreCardsButton.assertIsNotDisplayed()
}
step("Assert 'Card Settings' button is visible") {
cardSettingsButton.assertIsDisplayed()
deviceSettingsButton.assertIsDisplayed()
}
step("Assert 'Referral program' button is visible") {
referralProgramButton.assertIsDisplayed()
@ -152,7 +152,7 @@ class DetailsTest : BaseTestCase() {
}
onWalletSettingsScreen {
step("Assert 'Card Settings' button is visible") {
cardSettingsButton.assertIsDisplayed()
deviceSettingsButton.assertIsDisplayed()
}
step("Assert 'Referral program' button does not exist") {
referralProgramButton.assertIsNotDisplayed()

View file

@ -0,0 +1,85 @@
package com.tangem.tests
import com.tangem.common.BaseTestCase
import com.tangem.domain.models.scan.ProductType
import com.tangem.scenarios.*
import com.tangem.tap.domain.sdk.mocks.content.BackupWalletMockContent
import dagger.hilt.android.testing.HiltAndroidTest
import io.qameta.allure.kotlin.AllureId
import io.qameta.allure.kotlin.junit4.DisplayName
import org.junit.Ignore
import org.junit.Test
@HiltAndroidTest
class ResetCardTest : BaseTestCase() {
@AllureId("3988")
@DisplayName("Reset card: reset Wallet 1.0 card without backup")
@Test
fun resetWallet1CardWithoutBackupTest() {
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Open 'Device settings' screen") {
openDeviceSettingsScreen()
}
step("Open 'Reset card' screen") {
openResetCardScreen()
}
step("Check 'Reset card' screen") {
checkResetCardScreen()
}
step("Check checkbox logic") {
checkCheckBoxLogic()
}
}
}
@AllureId("3987")
@DisplayName("Reset card: reset Wallet 1.0 card with backup")
@Test
fun resetWallet1CardWithBackupTest() {
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen(mockContent = BackupWalletMockContent)
}
step("Open 'Device settings' screen") {
openDeviceSettingsScreen()
}
step("Open 'Reset card' screen") {
openResetCardScreen(withBackup = true)
}
step("Check 'Reset card' screen") {
checkResetCardScreen(withBackup = true)
}
step("Check checkbox logic") {
checkCheckBoxLogic(withBackup = true)
}
}
}
@AllureId("3974")
@DisplayName("Reset card: reset Wallet 2.0 card with backup")
@Ignore("toDo [REDACTED_TASK_KEY]: On CI Already used wallet dialog doesn't displayed")
@Test
fun resetWallet2CardWithBackupTest() {
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen(productType = ProductType.Wallet2, alreadyActivatedDialogIsShown = true)
}
step("Open 'Device settings' screen") {
openDeviceSettingsScreen()
}
step("Open 'Reset card' screen") {
openResetCardScreen(withBackup = true)
}
step("Check 'Reset card' screen") {
checkResetCardScreen(withBackup = true)
}
step("Check checkbox logic") {
checkCheckBoxLogic(withBackup = true)
}
}
}
}

View file

@ -0,0 +1,270 @@
package com.tangem.tap.domain.sdk.mocks.content
import com.tangem.common.SuccessResponse
import com.tangem.common.card.*
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.attestation.Attestation
import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.sdk.api.CreateProductWalletTaskResponse
import com.tangem.tap.domain.sdk.mocks.MockContent
import java.util.Date
object BackupWalletMockContent : MockContent {
private val primaryCard = PrimaryCard(
cardId = "AC05000000086747",
batchId = "AC05",
cardPublicKey = byteArrayOf(2, -120, -3, -32, -122, -127, -120, -104, 59, 72, 76, 114, 94, 75, -37, -55, 55, 99, 66, 123, 85, -87, 80, 106, 105, -116, 87, -83, -12, 70, 108, -68, -39),
linkingKey = byteArrayOf(
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
),
existingWalletsCount = 3, isHDWalletAllowed = true,
issuer = Card.Issuer(
name = "TANGEM AG",
publicKey = byteArrayOf(3, 86, -25, -61, 55, 99, 41, -33, -82, 115, -120, -33, 22, -107, 103, 3, -122, 16, 60, -110, 72, 106, -121, 100, 79, -87, -27, 18, -55, -49, 78, -110, -2),
),
manufacturer = Card.Manufacturer(
name = "TANGEM",
manufactureDate = Date(1743759687),
signature = byteArrayOf(),
),
walletCurves = listOf(EllipticCurve.Secp256k1, EllipticCurve.Ed25519, EllipticCurve.Bls12381G2Aug),
firmwareVersion = FirmwareVersion(
major = 4,
minor = 52,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
),
isKeysImportAllowed = false,
certificate = null,
)
override val cardDto = CardDTO(
cardId = "AC05000000086747",
batchId = "AC05",
cardPublicKey = byteArrayOf(2, -120, -3, -32, -122, -127, -120, -104, 59, 72, 76, 114, 94, 75, -37, -55, 55, 99, 66, 123, 85, -87, 80, 106, 105, -116, 87, -83, -12, 70, 108, -68, -39),
firmwareVersion = CardDTO.FirmwareVersion(
major = 4,
minor = 52,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
),
manufacturer = CardDTO.Manufacturer(
name = "TANGEM",
manufactureDate = Date(1649635200000),
signature = byteArrayOf(-20, 98, -101, 94, -23, 73, 122, -21, 74, 76, 79, -55, -102, -62, -30, 44, -38, 118, 75, 121, -36, 118, -62, 60, -38, -63, 33, -14, -98, -69, 112, 22, 48, -43, 47, 65, -61, -56, 38, -94, -45, 44, 95, -22, 6, -31, -40, -25, 42, 38, 94, -99, 71, 98, -33, 27, -102, 30, 52, -7, 51, -27, 84, 66),
),
issuer = CardDTO.Issuer(
name = "TANGEM AG",
publicKey = byteArrayOf(3, 86, -25, -61, 55, 99, 41, -33, -82, 115, -120, -33, 22, -107, 103, 3, -122, 16, 60, -110, 72, 106, -121, 100, 79, -87, -27, 18, -55, -49, 78, -110, -2),
),
settings = CardDTO.Settings(
securityDelay = 15000,
maxWalletsCount = 20,
isSettingAccessCodeAllowed = false,
isSettingPasscodeAllowed = false,
isResettingUserCodesAllowed = true,
isLinkedTerminalEnabled = true,
isBackupAllowed = true,
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
isFilesAllowed = true,
isHDWalletAllowed = true,
isKeysImportAllowed = false,
),
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
isAccessCodeSet = false,
isPasscodeSet = false,
supportedCurves = listOf(
EllipticCurve.Secp256k1,
EllipticCurve.Ed25519,
EllipticCurve.Secp256r1,
EllipticCurve.Bls12381G2,
EllipticCurve.Bls12381G2Aug,
EllipticCurve.Bls12381G2Pop,
EllipticCurve.Bip0340,
),
wallets = listOf(
CardDTO.Wallet(
publicKey = byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
chainCode = byteArrayOf(80, 13, -8, -108, -35, 116, -92, 125, -65, -28, 85, 72, -113, 59, 83, 13, 5, -83, -102, 123, 124, -22, 94, 108, -71, 95, 65, -2, 38, 38, -108, 14),
curve = EllipticCurve.Secp256k1,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 0,
remainingSignatures = null,
index = 0,
hasBackup = true,
derivedKeys = mapOf(
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
),
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
),
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
),
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
),
),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
chainCode = byteArrayOf(80, 13, -8, -108, -35, 116, -92, 125, -65, -28, 85, 72, -113, 59, 83, 13, 5, -83, -102, 123, 124, -22, 94, 108, -71, 95, 65, -2, 38, 38, -108, 14),
),
isImported = false,
),
CardDTO.Wallet(
publicKey = byteArrayOf(-65, -53, -62, -12, -57, -32, -38, -9, -128, -52, -83, -61, 73, 39, 41, 15, -74, -97, 38, 52, -101, 63, 74, -56, -20, 15, 57, -127, 114, -93, -17, -109),
chainCode = byteArrayOf(-81, 15, 125, 28, -115, -22, 87, 81, 87, -123, -25, -74, 86, 2, 1, 110, -115, 65, -110, 63, -64, 83, -93, -97, -104, 123, 12, -26, 94, 27, 84, -6),
curve = EllipticCurve.Ed25519,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 0,
remainingSignatures = null,
index = 1,
hasBackup = true,
derivedKeys = emptyMap(),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(-65, -53, -62, -12, -57, -32, -38, -9, -128, -52, -83, -61, 73, 39, 41, 15, -74, -97, 38, 52, -101, 63, 74, -56, -20, 15, 57, -127, 114, -93, -17, -109),
chainCode = byteArrayOf(-81, 15, 125, 28, -115, -22, 87, 81, 87, -123, -25, -74, 86, 2, 1, 110, -115, 65, -110, 63, -64, 83, -93, -97, -104, 123, 12, -26, 94, 27, 84, -6),
),
isImported = false,
),
),
attestation = Attestation(
cardKeyAttestation = Attestation.Status.Verified,
walletKeysAttestation = Attestation.Status.Skipped,
firmwareAttestation = Attestation.Status.Skipped,
cardUniquenessAttestation = Attestation.Status.Skipped,
),
backupStatus = CardDTO.BackupStatus.Active(1),
)
override val scanResponse = ScanResponse(
card = cardDto,
productType = ProductType.Wallet,
walletData = null,
secondTwinPublicKey = null,
derivedKeys = emptyMap(),
primaryCard = null,
)
override val derivationTaskResponse = DerivationTaskResponse(
entries = mapOf(
ByteArrayKey(
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
)
to
ExtendedPublicKeysMap(
mapOf(
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey( // btc
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
),
),
),
)
override val extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(3, 2, 95, 53, 40, -87, -60, 11, -8, -47, 41, 37, 100, 15, -69, 1, -122, 127, -20, -81, -32, -20, -24, 5, -28, 113, 106, -90, -59, -30, -27, -110, -110),
chainCode = byteArrayOf(-95, -87, -95, -25, 27, 96, -57, -92, -69, -106, -45, 10, 85, 4, -92, -68, 49, -24, -28, -50, -49, -77, -20, 118, -50, -27, 104, -93, 115, -50, -46, -34),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
)
override val successResponse = SuccessResponse(cardId = "AC05000000086747")
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
card = cardDto,
derivedKeys = mapOf(
ByteArrayKey(
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
)
to
ExtendedPublicKeysMap(
mapOf(
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
depth = 0,
parentFingerprint = byteArrayOf(0, 0, 0, 0),
childNumber = 0,
),
),
),
),
primaryCard = primaryCard,
)
override val importWalletResponse: CreateProductWalletTaskResponse
get() = error("Available only for Wallet 2")
override val createFirstTwinResponse: CreateWalletResponse
get() = error("Available only for Twin")
override val createSecondTwinResponse: CreateWalletResponse
get() = error("Available only for Twin")
override val finalizeTwinResponse: ScanResponse
get() = error("Available only for Twin")
}

View file

@ -13,11 +13,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.DeviceSettingsScreenTestTags
import com.tangem.tap.features.details.ui.common.DetailsMainButton
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
import com.tangem.wallet.R
@ -49,7 +51,8 @@ private fun CardSettingsReadCard(onScanCardClick: () -> Unit) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = TangemTheme.dimens.spacing40),
.padding(bottom = TangemTheme.dimens.spacing40)
.testTag(DeviceSettingsScreenTestTags.IMAGE_BLOCK),
) {
Image(
modifier = Modifier
@ -116,7 +119,9 @@ private fun CardSettings(state: CardSettingsScreenState) {
if (state.cardDetails == null) return
LazyColumn(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.testTag(DeviceSettingsScreenTestTags.LAZY_LIST),
) {
items(state.cardDetails) {
val paddingBottom = when (it) {
@ -164,12 +169,14 @@ private fun CardSettings(state: CardSettingsScreenState) {
text = it.titleRes.resolveReference(),
color = titleColor,
style = TangemTheme.typography.subtitle1,
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_TITLE),
)
Spacer(modifier = Modifier.size(TangemTheme.dimens.size4))
Text(
text = it.subtitle.resolveReference(),
color = subtitleColor,
style = TangemTheme.typography.body2,
modifier = Modifier.testTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE),
)
}
}

View file

@ -9,12 +9,14 @@ import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.*
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.ResetCardScreenTestTags
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
import com.tangem.tap.features.details.ui.common.DetailsMainButton
@ -74,6 +76,7 @@ private fun Title() {
text = stringResourceSafe(id = R.string.card_settings_reset_card_to_factory),
style = TangemTheme.typography.h1,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.testTag(ResetCardScreenTestTags.TITLE),
)
}
@ -82,7 +85,9 @@ private fun AlertImage() {
Image(
painter = painterResource(id = R.drawable.img_alert_80),
contentDescription = null,
modifier = Modifier.size(TangemTheme.dimens.size80),
modifier = Modifier
.size(TangemTheme.dimens.size80)
.testTag(ResetCardScreenTestTags.ATTENTION_IMAGE),
)
}
@ -92,6 +97,7 @@ private fun Subtitle() {
text = stringResourceSafe(id = R.string.common_attention),
style = TangemTheme.typography.h3,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.testTag(ResetCardScreenTestTags.SUBTITLE),
)
}
@ -101,6 +107,7 @@ private fun Description(text: TextReference) {
text = text.resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.secondary,
modifier = Modifier.testTag(ResetCardScreenTestTags.DESCRIPTION),
)
}
@ -135,7 +142,11 @@ private fun ConditionCheckBox(checkedState: Boolean, onCheckedChange: (Boolean)
.padding(vertical = TangemTheme.dimens.size16),
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
) {
IconToggleButton(checked = checkedState, onCheckedChange = onCheckedChange) {
IconToggleButton(
checked = checkedState,
onCheckedChange = onCheckedChange,
modifier = Modifier.testTag(ResetCardScreenTestTags.CHECKBOX),
) {
AnimatedContent(targetState = checkedState, label = "Update checked state") { checked ->
Icon(
painter = painterResource(
@ -159,6 +170,7 @@ private fun ConditionCheckBox(checkedState: Boolean, onCheckedChange: (Boolean)
text = description.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier.testTag(ResetCardScreenTestTags.CHECKBOX_TEXT),
)
}
}

View file

@ -0,0 +1,8 @@
package com.tangem.core.ui.test
object DeviceSettingsScreenTestTags {
const val LAZY_LIST = "DEVICE_SETTINGS_SCREEN_LAZY_LIST"
const val IMAGE_BLOCK = "DEVICE_SETTINGS_SCREEN_IMAGE_BLOCK"
const val ITEM_TITLE = "DEVICE_SETTINGS_SCREEN_ITEM_TITLE"
const val ITEM_SUBTITLE = "DEVICE_SETTINGS_SCREEN_ITEM_SUBTITLE"
}

View file

@ -0,0 +1,10 @@
package com.tangem.core.ui.test
object ResetCardScreenTestTags {
const val TITLE = "RESET_CARD_SCREEN_TITLE"
const val ATTENTION_IMAGE = "RESET_CARD_SCREEN_ATTENTION_IMAGE"
const val SUBTITLE = "RESET_CARD_SCREEN_SUBTITLE"
const val DESCRIPTION = "RESET_CARD_SCREEN_DESCRIPTION"
const val CHECKBOX = "RESET_CARD_SCREEN_CHECKBOX"
const val CHECKBOX_TEXT = "RESET_CARD_SCREEN_CHECKBOX_TEXT"
}