Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-09 19:54:56 +05:00
parent d64a36a2a8
commit 2aa9866f07
24 changed files with 779 additions and 101 deletions

View file

@ -0,0 +1,8 @@
package com.tangem.common.extensions
import io.github.kakaocup.compose.node.element.KNode
fun KNode.clickWithAssertion() {
assertIsDisplayed()
performClick()
}

View file

@ -0,0 +1,38 @@
package com.tangem.scenarios
import androidx.compose.ui.test.junit4.ComposeTestRule
import com.kaspersky.kaspresso.testcases.api.scenario.Scenario
import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.domain.models.scan.ProductType
import com.tangem.screens.DisclaimerTestScreen
import com.tangem.screens.MainTestScreen
import com.tangem.screens.StoriesTestScreen
import com.tangem.tap.domain.sdk.mocks.MockProvider
import io.github.kakaocup.compose.node.element.ComposeScreen
class OpenMainScreenScenario(
private val testRule: ComposeTestRule,
private val productType: ProductType? = null,
) : Scenario() {
override val steps: TestContext<Unit>.() -> Unit = {
if (productType != null) {
MockProvider.setMocks(productType)
}
ComposeScreen.onComposeScreen<DisclaimerTestScreen>(testRule) {
step("Click on \"Accept\" button") {
acceptButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<StoriesTestScreen>(testRule) {
step("Click on \"Scan\" button") {
scanButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<MainTestScreen>(testRule) {
step("Make sure wallet screen is visible") {
assertIsDisplayed()
}
}
}
}

View file

@ -0,0 +1,51 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.core.ui.test.TestTags
import com.tangem.wallet.R
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.KNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
class DetailsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<DetailsTestScreen>(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.DETAILS_SCREEN) }
) {
val walletConnectButton: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
hasText(getResourceString(R.string.wallet_connect_title))
}
private val walletBlock: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
}
val walletNameButton: KNode = walletBlock.child {
hasClickAction()
hasPosition(0)
}
val scanCardButton: KNode = walletBlock.child {
hasText(getResourceString(R.string.scan_card_settings_button))
}
val buyTangemButton: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
hasText(getResourceString(R.string.details_buy_wallet))
}
val appSettingsButton: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
hasText(getResourceString(R.string.app_settings_title))
}
val contactSupportButton: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
hasText(getResourceString(R.string.details_row_title_contact_to_support))
}
val toSButton: KNode = child {
hasTestTag(TestTags.DETAILS_SCREEN_ITEM)
hasText(getResourceString(R.string.disclaimer_title))
}
}

View file

@ -1,17 +0,0 @@
package com.tangem.screens
import com.kaspersky.kaspresso.screens.KScreen
import com.tangem.tap.features.disclaimer.ui.DisclaimerFragment
import com.tangem.wallet.R
import io.github.kakaocup.kakao.text.KButton
object DisclaimerScreen : KScreen<DisclaimerScreen>(){
override val layoutId = R.layout.fragment_disclaimer
override val viewClass = DisclaimerFragment::class.java
val acceptButton: KButton = KButton {
withId(R.id.btn_accept)
}
}

View file

@ -0,0 +1,17 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.core.ui.test.TestTags
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.KNode
class DisclaimerTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<DisclaimerTestScreen>(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.DISCLAIMER_SCREEN_CONTAINER) }
) {
val acceptButton: KNode = child {
hasTestTag(TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON)
}
}

View file

@ -4,8 +4,8 @@ import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.core.ui.test.TestTags import com.tangem.core.ui.test.TestTags
import io.github.kakaocup.compose.node.element.ComposeScreen import io.github.kakaocup.compose.node.element.ComposeScreen
class WalletScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : class MainTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<WalletScreen>( ComposeScreen<MainTestScreen>(
semanticsProvider = semanticsProvider, semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.WALLET_SCREEN) } viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN) }
) )

View file

@ -8,8 +8,8 @@ import io.github.kakaocup.compose.node.element.KNode
import io.github.kakaocup.kakao.common.views.KView import io.github.kakaocup.kakao.common.views.KView
import io.github.kakaocup.kakao.text.KButton import io.github.kakaocup.kakao.text.KButton
class StoriesScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : class StoriesTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<StoriesScreen>( ComposeScreen<StoriesTestScreen>(
semanticsProvider = semanticsProvider, semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.STORIES_SCREEN) } viewBuilderAction = { hasTestTag(TestTags.STORIES_SCREEN) }
) { ) {

View file

@ -0,0 +1,16 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.core.ui.test.TestTags
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.KNode
class TestTopBar(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<TestTopBar>(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN_TOP_BAR) }
) {
val moreButton: KNode = child {
hasTestTag(TestTags.MAIN_SCREEN_MORE_BUTTON)
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.core.ui.test.TestTags
import com.tangem.wallet.R
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.KNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
class WalletSettingsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<WalletSettingsTestScreen>(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(TestTags.WALLET_SETTINGS_SCREEN) }
) {
private val walletSettingsItem: KNode = child {
hasTestTag(TestTags.WALLET_SETTINGS_SCREEN_ITEM)
}
val linkMoreCardsButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.details_row_title_create_backup))
}
val cardSettingsButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.card_settings_title))
}
val referralProgramButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.details_referral_title))
}
val forgetWalletButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.settings_forget_wallet))
}
}

View file

@ -0,0 +1,160 @@
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.OpenMainScreenScenario
import com.tangem.screens.DetailsTestScreen
import com.tangem.screens.TestTopBar
import com.tangem.screens.WalletSettingsTestScreen
import dagger.hilt.android.testing.HiltAndroidTest
import io.github.kakaocup.compose.node.element.ComposeScreen
import org.junit.Test
@HiltAndroidTest
class DetailsScreenTest : BaseTestCase() {
@Test
fun walletWithoutBackupDetails() =
setupHooks().run {
scenario(OpenMainScreenScenario(composeTestRule))
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
step("Open wallet details") {
moreButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
step("Assert wallet connect button is visible") {
walletConnectButton.assertIsDisplayed()
}
step("Assert scan card button is visible") {
scanCardButton.assertIsDisplayed()
}
step("Assert buy Tangem card button is visible") {
buyTangemButton.assertIsDisplayed()
}
step("Assert app settings button is visible") {
appSettingsButton.assertIsDisplayed()
}
step("Assert contact support button is visible") {
contactSupportButton.assertIsDisplayed()
}
step("Assert terms or service button is visible") {
toSButton.assertIsDisplayed()
}
step("Open wallet settings screen") {
walletNameButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
step("Assert Link more cards button is visible") {
linkMoreCardsButton.assertIsDisplayed()
}
step("Assert Card Settings button is visible") {
cardSettingsButton.assertIsDisplayed()
}
step("Assert Referral program button is visible") {
referralProgramButton.assertIsDisplayed()
}
step("Assert Forget wallet button is visible") {
forgetWalletButton.assertIsDisplayed()
}
}
}
@Test
fun wallet2Details() =
setupHooks().run {
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Wallet2))
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
step("Open wallet details") {
moreButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
step("Assert wallet connect button is visible") {
walletConnectButton.assertIsDisplayed()
}
step("Assert scan card button is visible") {
scanCardButton.assertIsDisplayed()
}
step("Assert buy Tangem card button is visible") {
buyTangemButton.assertIsDisplayed()
}
step("Assert app settings button is visible") {
appSettingsButton.assertIsDisplayed()
}
step("Assert contact support button is visible") {
contactSupportButton.assertIsDisplayed()
}
step("Assert terms or service button is visible") {
toSButton.assertIsDisplayed()
}
step("Open wallet settings screen") {
walletNameButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
step("Assert Link more cards button does not exist") {
linkMoreCardsButton.assertIsNotDisplayed()
}
step("Assert Card Settings button is visible") {
cardSettingsButton.assertIsDisplayed()
}
step("Assert Referral program button is visible") {
referralProgramButton.assertIsDisplayed()
}
step("Assert Forget wallet button is visible") {
forgetWalletButton.assertIsDisplayed()
}
}
}
@Test
fun noteDetails() =
setupHooks().run {
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Note))
ComposeScreen.onComposeScreen<TestTopBar>(composeTestRule) {
step("Open wallet details") {
moreButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<DetailsTestScreen>(composeTestRule) {
step("Assert wallet connect button does not exist") {
walletConnectButton.assertIsNotDisplayed()
}
step("Assert scan card button is visible") {
scanCardButton.assertIsDisplayed()
}
step("Assert buy Tangem card button is visible") {
buyTangemButton.assertIsDisplayed()
}
step("Assert app settings button is visible") {
appSettingsButton.assertIsDisplayed()
}
step("Assert contact support button is visible") {
contactSupportButton.assertIsDisplayed()
}
step("Assert terms or service button is visible") {
toSButton.assertIsDisplayed()
}
step("Open wallet settings screen") {
walletNameButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<WalletSettingsTestScreen>(composeTestRule) {
step("Assert Link more cards button does not exist") {
linkMoreCardsButton.assertIsNotDisplayed()
}
step("Assert Card Settings button is visible") {
cardSettingsButton.assertIsDisplayed()
}
step("Assert Referral program button does not exist") {
referralProgramButton.assertIsNotDisplayed()
}
step("Assert Forget wallet button is visible") {
forgetWalletButton.assertIsDisplayed()
}
}
}
}

View file

@ -1,11 +1,8 @@
package com.tangem.tests package com.tangem.tests
import com.tangem.common.BaseTestCase import com.tangem.common.BaseTestCase
import com.tangem.screens.DisclaimerScreen import com.tangem.scenarios.OpenMainScreenScenario
import com.tangem.screens.StoriesScreen
import com.tangem.screens.WalletScreen
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import io.github.kakaocup.compose.node.element.ComposeScreen
import org.junit.Test import org.junit.Test
@HiltAndroidTest @HiltAndroidTest
@ -14,26 +11,6 @@ class MainScreenTest : BaseTestCase() {
@Test @Test
fun goToMain() = fun goToMain() =
setupHooks().run { setupHooks().run {
ComposeScreen.onComposeScreen<StoriesScreen>(composeTestRule) { scenario(OpenMainScreenScenario(composeTestRule))
step("Click on \"Scan\" button") {
scanButton {
assertIsDisplayed()
performClick()
}
}
}
DisclaimerScreen {
step("Click on \"Accept\" button") {
acceptButton {
isVisible()
click()
}
}
}
ComposeScreen.onComposeScreen<WalletScreen>(composeTestRule) {
step("Make sure wallet screen is visible") {
assertIsDisplayed()
}
}
} }
} }

View file

@ -1,9 +1,10 @@
package com.tangem.tests package com.tangem.tests
import com.tangem.common.BaseTestCase import com.tangem.common.BaseTestCase
import com.tangem.screens.DisclaimerScreen import com.tangem.common.extensions.clickWithAssertion
import com.tangem.screens.StoriesScreen import com.tangem.screens.DisclaimerTestScreen
import com.tangem.screens.WalletScreen import com.tangem.screens.MainTestScreen
import com.tangem.screens.StoriesTestScreen
import com.tangem.tap.domain.sdk.mocks.MockProvider import com.tangem.tap.domain.sdk.mocks.MockProvider
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import io.github.kakaocup.compose.node.element.ComposeScreen import io.github.kakaocup.compose.node.element.ComposeScreen
@ -15,31 +16,22 @@ class ScanErrorTest : BaseTestCase() {
@Test @Test
fun goToMain() = fun goToMain() =
setupHooks().run { setupHooks().run {
ComposeScreen.onComposeScreen<StoriesScreen>(composeTestRule) { ComposeScreen.onComposeScreen<DisclaimerTestScreen>(composeTestRule) {
step("Click on \"Accept\" button") {
acceptButton.clickWithAssertion()
}
}
ComposeScreen.onComposeScreen<StoriesTestScreen>(composeTestRule) {
step("Click on \"Scan\" button emulating scan error") { step("Click on \"Scan\" button emulating scan error") {
MockProvider.setEmulateError() MockProvider.setEmulateError()
scanButton { scanButton.clickWithAssertion()
assertIsDisplayed()
performClick()
}
} }
step("Click on \"Scan\" button again without emulating error") { step("Click on \"Scan\" button again without emulating error") {
MockProvider.resetEmulateError() MockProvider.resetEmulateError()
scanButton { scanButton.clickWithAssertion()
assertIsDisplayed()
performClick()
}
} }
} }
DisclaimerScreen { ComposeScreen.onComposeScreen<MainTestScreen>(composeTestRule) {
step("Click on \"Accept\" button") {
acceptButton {
isVisible()
click()
}
}
}
ComposeScreen.onComposeScreen<WalletScreen>(composeTestRule) {
step("Make sure wallet screen is visible") { step("Make sure wallet screen is visible") {
assertIsDisplayed() assertIsDisplayed()
} }

View file

@ -2,7 +2,9 @@ package com.tangem.tests
import android.content.Intent.ACTION_VIEW import android.content.Intent.ACTION_VIEW
import com.tangem.common.BaseTestCase import com.tangem.common.BaseTestCase
import com.tangem.screens.StoriesScreen import com.tangem.common.extensions.clickWithAssertion
import com.tangem.screens.DisclaimerTestScreen
import com.tangem.screens.StoriesTestScreen
import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import io.github.kakaocup.compose.node.element.ComposeScreen import io.github.kakaocup.compose.node.element.ComposeScreen
@ -13,22 +15,16 @@ import org.junit.Test
class StoriesTest : BaseTestCase() { class StoriesTest : BaseTestCase() {
@Test @Test
fun clickOnButtons() = fun clickOnOrderButton() =
setupHooks().run { setupHooks().run {
ComposeScreen.onComposeScreen<StoriesScreen>(composeTestRule) { ComposeScreen.onComposeScreen<DisclaimerTestScreen>(composeTestRule) {
step("Click on \"Scan\" button") { step("Click on \"Accept\" button") {
scanButton { acceptButton.clickWithAssertion()
assertIsDisplayed()
performClick()
}
}
step("Assert: \"Scan card\" popup opened") {
enableNFCAlert.isDisplayed()
cancelButton.click()
device.uiDevice.pressBack()
} }
}
ComposeScreen.onComposeScreen<StoriesTestScreen>(composeTestRule) {
step("Click on \"Order\" button") { step("Click on \"Order\" button") {
orderButton.performClick() orderButton.clickWithAssertion()
} }
step("Assert: browser opened") { step("Assert: browser opened") {
val expectedIntent = KIntent { val expectedIntent = KIntent {

View file

@ -4,6 +4,7 @@ import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError import com.tangem.common.core.TangemSdkError
import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ProductType
import com.tangem.tap.domain.sdk.mocks.content.NoteMockContent
import com.tangem.tap.domain.sdk.mocks.content.WalletMockContent import com.tangem.tap.domain.sdk.mocks.content.WalletMockContent
import com.tangem.tap.domain.sdk.mocks.content.Wallet2MockContent import com.tangem.tap.domain.sdk.mocks.content.Wallet2MockContent
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
@ -67,6 +68,7 @@ object MockProvider {
return when (productType) { return when (productType) {
ProductType.Wallet -> WalletMockContent ProductType.Wallet -> WalletMockContent
ProductType.Wallet2 -> Wallet2MockContent ProductType.Wallet2 -> Wallet2MockContent
ProductType.Note -> NoteMockContent
else -> TODO() else -> TODO()
} }
} }

View file

@ -0,0 +1,117 @@
package com.tangem.tap.domain.sdk.mocks.content
import com.tangem.common.SuccessResponse
import com.tangem.common.card.*
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.derivation.DerivationTaskResponse
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.domain.sdk.mocks.MockContent
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import java.util.Date
object NoteMockContent : MockContent {
override val cardDto = CardDTO(
cardId = "AB04000000010905",
batchId = "AB04",
cardPublicKey = byteArrayOf(2, 102, 3, -106, -14, -87, -118, 120, 10, 93, 17, 55, 26, -44, 5, 115, 88, 35, 49, -88, -69, 116, 0, -72, -27, 57, 50, -55, 80, -16, 39, -70, 119),
firmwareVersion = CardDTO.FirmwareVersion(
major = 4,
minor = 39,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
),
manufacturer = CardDTO.Manufacturer(
name = "TANGEM",
manufactureDate = Date(1649635200000),
signature = byteArrayOf(-2, -45, 100, -79, 7, -120, 49, 74, 126, -3, -75, 54, -36, -1, 19, -83, 47, -82, 52, -43, -119, 75, 58, 97, 50, 37, 103, -6, -2, 28, 120, 103, -38, -95, 7, -126, -3, -23, -22, -30, -24, -126, 3, 70, 7, -20, -6, -49, 55, -93, 26, 57, -71, 12, -20, 41, -105, -75, 82, 116, 12, -75, -22, 55),
),
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 = 1,
isSettingAccessCodeAllowed = false,
isSettingPasscodeAllowed = false,
isResettingUserCodesAllowed = true,
isLinkedTerminalEnabled = true,
isBackupAllowed = false,
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
isFilesAllowed = false,
isHDWalletAllowed = false,
isKeysImportAllowed = false,
),
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = false),
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
isAccessCodeSet = false,
isPasscodeSet = false,
supportedCurves = listOf(
EllipticCurve.Secp256k1,
EllipticCurve.Ed25519,
EllipticCurve.Secp256r1,
),
wallets = listOf(
CardDTO.Wallet(
publicKey = byteArrayOf(2, -27, -117, 23, 68, -3, 21, -109, 18, -67, -107, -42, -44, -16, -127, -53, 46, -109, -46, -51, 89, 119, 79, 111, 78, 62, -125, 72, 109, 8, 45, 59, 117),
chainCode = byteArrayOf(),
curve = EllipticCurve.Secp256k1,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 3,
remainingSignatures = null,
index = 0,
hasBackup = false,
derivedKeys = emptyMap(),
extendedPublicKey = null,
isImported = false,
),
),
attestation = Attestation(
cardKeyAttestation = Attestation.Status.Verified,
walletKeysAttestation = Attestation.Status.Skipped,
firmwareAttestation = Attestation.Status.Skipped,
cardUniquenessAttestation = Attestation.Status.Skipped,
),
backupStatus = CardDTO.BackupStatus.NoBackup,
)
override val scanResponse = ScanResponse(
card = cardDto,
productType = ProductType.Note,
walletData = WalletData(blockchain = "DOGE", token = null),
secondTwinPublicKey = null,
derivedKeys = emptyMap(),
primaryCard = null,
)
override val derivationTaskResponse = DerivationTaskResponse(
entries = emptyMap(),
)
override val extendedPublicKey
get() = error("Available only for wallet+?")
override val successResponse = SuccessResponse(cardId = "AB04000000010905")
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
card = cardDto,
derivedKeys = emptyMap(),
primaryCard = null,
)
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

@ -1,33 +1,292 @@
package com.tangem.tap.domain.sdk.mocks.content package com.tangem.tap.domain.sdk.mocks.content
import com.tangem.common.SuccessResponse 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.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse 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.DerivationTaskResponse
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.wallet.CreateWalletResponse import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.domain.sdk.mocks.MockContent import com.tangem.tap.domain.sdk.mocks.MockContent
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import java.util.Date
object Wallet2MockContent : MockContent { object Wallet2MockContent : MockContent {
override val scanResponse: ScanResponse private val primaryCard = PrimaryCard(
get() = TODO("Not yet implemented") cardId = "AF10000000981426",
batchId = "AF10",
cardPublicKey = byteArrayOf(3, 7, 80, -118, 6, 77, -15, -22, 107, 105, -64, 103, 77, -79, -102, 106, 46, 84, 21, -34, 47, -74, -56, 124, 17, -49, -29, 76, 84, 59, 50, -15, -52),
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 = 5, isHDWalletAllowed = true,
issuer = Card.Issuer(
name = "TANGEM 2.0",
publicKey = byteArrayOf(2, -120, 89, -52, -60, 36, -73, -17, 103, 107, -110, -36, 3, 110, -122, 72, 43, -38, 8, 30, -50, 25, -23, -17, 38, 94, 5, -112, -20, 9, 54, -24, -32),
),
walletCurves = listOf(
EllipticCurve.Secp256k1,
EllipticCurve.Ed25519,
EllipticCurve.Bls12381G2Aug,
EllipticCurve.Secp256r1,
EllipticCurve.Ed25519Slip0010,
EllipticCurve.Bls12381G2,
EllipticCurve.Bls12381G2Pop,
EllipticCurve.Bip0340,
),
firmwareVersion = FirmwareVersion(
major = 6,
minor = 33,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
),
isKeysImportAllowed = false,
certificate = null,
)
override val cardDto: CardDTO override val cardDto = CardDTO(
get() = TODO("Not yet implemented") cardId = "AF10000000981426",
batchId = "AF10",
cardPublicKey = byteArrayOf(3, 7, 80, -118, 6, 77, -15, -22, 107, 105, -64, 103, 77, -79, -102, 106, 46, 84, 21, -34, 47, -74, -56, 124, 17, -49, -29, 76, 84, 59, 50, -15, -52),
firmwareVersion = CardDTO.FirmwareVersion(
major = 6,
minor = 33,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
),
manufacturer = CardDTO.Manufacturer(
name = "TANGEM",
manufactureDate = Date(1698094800000),
signature = byteArrayOf(71, -20, 9, 31, 25, 111, 61, 119, 109, -123, -63, 51, 58, -71, -44, 53, 57, 20, -16, 97, -87, -82, 1, -35, -48, 63, 77, -78, -89, -112, -27, 25, -10, 90, 7, -53, -84, -125, 112, 68, -14, -85, -100, -64, -115, 31, 42, 119, 87, -79, 127, 42, -87, -102, 13, -9, -10, -51, -29, -63, -1, -52, -117, 57),
),
issuer = CardDTO.Issuer(
name = "TANGEM 2.0",
publicKey = byteArrayOf(2, -120, 89, -52, -60, 36, -73, -17, 103, 107, -110, -36, 3, 110, -122, 72, 43, -38, 8, 30, -50, 25, -23, -17, 38, 94, 5, -112, -20, 9, 54, -24, -32),
),
settings = CardDTO.Settings(
securityDelay = 15000,
maxWalletsCount = 20,
isSettingAccessCodeAllowed = true,
isSettingPasscodeAllowed = true,
isResettingUserCodesAllowed = false,
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 = true,
isPasscodeSet = false,
supportedCurves = listOf(
EllipticCurve.Secp256k1,
EllipticCurve.Ed25519,
EllipticCurve.Bls12381G2Aug,
EllipticCurve.Secp256r1,
EllipticCurve.Ed25519Slip0010,
EllipticCurve.Bls12381G2,
EllipticCurve.Bls12381G2Pop,
EllipticCurve.Bip0340,
),
wallets = listOf(
CardDTO.Wallet(
publicKey = byteArrayOf(2, -114, -64, 120, -121, 11, -28, 89, -91, 114, 10, 84, -87, -36, 36, 19, -69, 95, 66, 14, 32, -35, -99, -67, 118, 51, 26, 71, -78, -36, 59, -126, -58),
chainCode = byteArrayOf(-47, -8, 74, 69, -1, 52, 10, -56, -85, 118, 56, 77, 125, -12, 85, -23, 42, -58, 99, 47, -87, -34, -83, 72, -122, -29, 88, -85, 46, -118, -26, 116),
curve = EllipticCurve.Secp256k1,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 73,
remainingSignatures = null,
index = 0,
hasBackup = true,
derivedKeys = mapOf(
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
),
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
),
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
),
),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(2, -114, -64, 120, -121, 11, -28, 89, -91, 114, 10, 84, -87, -36, 36, 19, -69, 95, 66, 14, 32, -35, -99, -67, 118, 51, 26, 71, -78, -36, 59, -126, -58),
chainCode = byteArrayOf(-47, -8, 74, 69, -1, 52, 10, -56, -85, 118, 56, 77, 125, -12, 85, -23, 42, -58, 99, 47, -87, -34, -83, 72, -122, -29, 88, -85, 46, -118, -26, 116),
),
isImported = false,
),
CardDTO.Wallet(
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
curve = EllipticCurve.Ed25519,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 0,
remainingSignatures = null,
index = 1,
hasBackup = true,
derivedKeys = emptyMap(),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
),
isImported = false,
),
CardDTO.Wallet(
publicKey = byteArrayOf(-94, 111, -89, -77, -62, -113, 16, -118, -46, -16, -20, 28, 53, -82, -109, 28, 99, -98, -54, 59, -3, 99, 16, -70, -73, 43, -6, 33, -53, -66, 76, -72, 6, -49, 83, -121, -122, 111, -111, -116, -119, 98, -94, -98, -121, -37, 20, -95),
chainCode = null,
curve = EllipticCurve.Bls12381G2Aug,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 1,
remainingSignatures = null,
index = 2,
hasBackup = true,
derivedKeys = emptyMap(),
extendedPublicKey = null,
isImported = false,
),
CardDTO.Wallet(
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
curve = EllipticCurve.Bip0340,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 0,
remainingSignatures = null,
index = 3,
hasBackup = true,
derivedKeys = emptyMap(),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
),
isImported = false,
),
CardDTO.Wallet(
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
curve = EllipticCurve.Ed25519Slip0010,
settings = CardWallet.Settings(isPermanent = false),
totalSignedHashes = 15,
remainingSignatures = null,
index = 4,
hasBackup = true,
derivedKeys = emptyMap(),
extendedPublicKey = ExtendedPublicKey(
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
),
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 derivationTaskResponse: DerivationTaskResponse override val scanResponse = ScanResponse(
get() = TODO("Not yet implemented") card = cardDto,
productType = ProductType.Wallet2,
walletData = null,
secondTwinPublicKey = null,
derivedKeys = emptyMap(),
primaryCard = null,
)
override val extendedPublicKey: ExtendedPublicKey override val derivationTaskResponse = DerivationTaskResponse(
get() = TODO("Not yet implemented") 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/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,
),
),
),
),
)
override val successResponse: SuccessResponse override val extendedPublicKey = ExtendedPublicKey(
get() = TODO("Not yet implemented") 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 createProductWalletTaskResponse: CreateProductWalletTaskResponse override val successResponse = SuccessResponse(cardId = "AF10000000981426")
get() = TODO("Not yet implemented")
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 override val importWalletResponse: CreateProductWalletTaskResponse
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")

View file

@ -5,5 +5,16 @@ object TestTags {
const val STORIES_SCREEN_SCAN_BUTTON = "STORIES_SCREEN_SCAN_BUTTON" const val STORIES_SCREEN_SCAN_BUTTON = "STORIES_SCREEN_SCAN_BUTTON"
const val STORIES_SCREEN_ORDER_BUTTON = "STORIES_SCREEN_ORDER_BUTTON" const val STORIES_SCREEN_ORDER_BUTTON = "STORIES_SCREEN_ORDER_BUTTON"
const val WALLET_SCREEN = "WALLET_SCREEN_CONTAINER" const val MAIN_SCREEN = "MAIN_SCREEN_CONTAINER"
const val MAIN_SCREEN_MORE_BUTTON = "MAIN_SCREEN_MORE_BUTTON"
const val MAIN_SCREEN_TOP_BAR = "MAIN_SCREEN_TOP_BAR"
const val DETAILS_SCREEN = "DETAILS_SCREEN_CONTAINER"
const val DETAILS_SCREEN_ITEM = "DETAILS_SCREEN_ITEM"
const val WALLET_SETTINGS_SCREEN = "WALLET_SETTINGS_SCREEN"
const val WALLET_SETTINGS_SCREEN_ITEM = "WALLET_SETTINGS_SCREEN_ITEM"
const val DISCLAIMER_SCREEN_CONTAINER = "DISCLAIMER_SCREEN_CONTAINER"
const val DISCLAIMER_SCREEN_ACCEPT_BUTTON = "DISCLAIMER_SCREEN_ACCEPT_BUTTON"
} }

View file

@ -16,6 +16,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -27,6 +28,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.res.LocalSnackbarHostState import com.tangem.core.ui.res.LocalSnackbarHostState
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TestTags
import com.tangem.features.details.component.preview.PreviewDetailsComponent import com.tangem.features.details.component.preview.PreviewDetailsComponent
import com.tangem.features.details.entity.DetailsFooterUM import com.tangem.features.details.entity.DetailsFooterUM
import com.tangem.features.details.entity.DetailsItemUM import com.tangem.features.details.entity.DetailsItemUM
@ -74,7 +76,7 @@ private fun Content(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
LazyColumn( LazyColumn(
modifier = modifier, modifier = modifier.testTag(TestTags.DETAILS_SCREEN),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
contentPadding = PaddingValues( contentPadding = PaddingValues(
top = TangemTheme.dimens.spacing12, top = TangemTheme.dimens.spacing12,
@ -125,7 +127,7 @@ private fun Block(
horizontalAlignment = Alignment.Start, horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Top, verticalArrangement = Arrangement.Top,
) { ) {
val itemModifier = Modifier.fillMaxWidth() val itemModifier = Modifier.fillMaxWidth().testTag(TestTags.DETAILS_SCREEN_ITEM)
when (model) { when (model) {
is DetailsItemUM.Basic -> { is DetailsItemUM.Basic -> {

View file

@ -16,6 +16,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
@ -34,6 +35,8 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON
import com.tangem.core.ui.test.TestTags.DISCLAIMER_SCREEN_CONTAINER
import com.tangem.features.disclaimer.impl.R import com.tangem.features.disclaimer.impl.R
import com.tangem.features.disclaimer.impl.entity.DisclaimerUM import com.tangem.features.disclaimer.impl.entity.DisclaimerUM
import com.tangem.features.disclaimer.impl.entity.DummyDisclaimer import com.tangem.features.disclaimer.impl.entity.DummyDisclaimer
@ -57,7 +60,8 @@ internal fun DisclaimerScreen(state: DisclaimerUM) {
Box( Box(
modifier = Modifier modifier = Modifier
.background(backgroundColor) .background(backgroundColor)
.statusBarsPadding(), .statusBarsPadding()
.testTag(DISCLAIMER_SCREEN_CONTAINER),
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@ -158,6 +162,7 @@ private fun BoxScope.DisclaimerButton(onAccept: (Boolean) -> Unit) {
disabledContentColor = TangemColorPalette.Dark6, disabledContentColor = TangemColorPalette.Dark6,
), ),
modifier = Modifier modifier = Modifier
.testTag(DISCLAIMER_SCREEN_ACCEPT_BUTTON)
.align(Alignment.BottomCenter) .align(Alignment.BottomCenter)
.navigationBarsPadding() .navigationBarsPadding()
.padding( .padding(

View file

@ -11,6 +11,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -23,6 +24,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.LocalSnackbarHostState import com.tangem.core.ui.res.LocalSnackbarHostState
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TestTags
import com.tangem.feature.walletsettings.component.preview.PreviewWalletSettingsComponent import com.tangem.feature.walletsettings.component.preview.PreviewWalletSettingsComponent
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM import com.tangem.feature.walletsettings.entity.WalletSettingsUM
@ -55,7 +57,7 @@ internal fun WalletSettingsScreen(
}, },
content = { paddingValues -> content = { paddingValues ->
Content( Content(
modifier = Modifier.padding(paddingValues), modifier = Modifier.padding(paddingValues).testTag(TestTags.WALLET_SETTINGS_SCREEN),
state = state, state = state,
) )
@ -89,6 +91,7 @@ private fun Content(state: WalletSettingsUM, modifier: Modifier = Modifier) {
val itemModifier = Modifier val itemModifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16) .padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth() .fillMaxWidth()
.testTag(TestTags.WALLET_SETTINGS_SCREEN_ITEM)
when (item) { when (item) {
is WalletSettingsItemUM.WithItems -> ItemsBlock( is WalletSettingsItemUM.WithItems -> ItemsBlock(

View file

@ -164,7 +164,7 @@ private fun WalletContent(
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.testTag(TestTags.WALLET_SCREEN), .testTag(TestTags.MAIN_SCREEN),
contentPadding = PaddingValues( contentPadding = PaddingValues(
bottom = TangemTheme.dimens.spacing92 + bottomBarHeight, bottom = TangemTheme.dimens.spacing92 + bottomBarHeight,
), ),

View file

@ -3,10 +3,14 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable 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.res.painterResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TestTags.MAIN_SCREEN_MORE_BUTTON
import com.tangem.core.ui.test.TestTags.MAIN_SCREEN_TOP_BAR
import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.common.WalletPreviewData import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTopBarConfig import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTopBarConfig
@ -24,7 +28,7 @@ internal fun WalletTopBar(config: WalletTopBarConfig) {
Icon(painter = painterResource(id = R.drawable.img_tangem_logo_90_24), contentDescription = null) Icon(painter = painterResource(id = R.drawable.img_tangem_logo_90_24), contentDescription = null)
}, },
actions = { actions = {
IconButton(onClick = config.onDetailsClick) { IconButton(onClick = config.onDetailsClick, modifier = Modifier.testTag(MAIN_SCREEN_MORE_BUTTON)) {
Icon(painter = painterResource(id = R.drawable.ic_more_vertical_24), contentDescription = null) Icon(painter = painterResource(id = R.drawable.ic_more_vertical_24), contentDescription = null)
} }
}, },
@ -34,6 +38,7 @@ internal fun WalletTopBar(config: WalletTopBarConfig) {
actionIconContentColor = TangemTheme.colors.icon.primary1, actionIconContentColor = TangemTheme.colors.icon.primary1,
), ),
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
modifier = Modifier.testTag(MAIN_SCREEN_TOP_BAR),
) )
} }

View file

@ -45,6 +45,10 @@ internal class DefaultBlockchainSDKFactory(
private val mainScope = CoroutineScope(dispatchers.main) private val mainScope = CoroutineScope(dispatchers.main)
private val walletManagerFactory: Flow<WalletManagerFactory?> = createWalletManagerFactory() private val walletManagerFactory: Flow<WalletManagerFactory?> = createWalletManagerFactory()
// TODO: [REDACTED_JIRA]
// private val walletManagerFactory: Flow<WalletManagerFactory?> by lazy(LazyThreadSafetyMode.NONE) {
// createWalletManagerFactory()
// }
override suspend fun init() { override suspend fun init() {
coroutineScope { coroutineScope {

View file

@ -4,6 +4,7 @@ internal object AppConfig {
const val packageName = "com.tangem.wallet" const val packageName = "com.tangem.wallet"
const val versionCode = 1 const val versionCode = 1
const val versionName = "1.0.0-SNAPSHOT" const val versionName = "1.0.0-SNAPSHOT"
// const val versionName = "100.0.0-SNAPSHOT" //TODO: [REDACTED_JIRA]
const val minSdkVersion = 24 const val minSdkVersion = 24
const val targetSdkVersion = 34 const val targetSdkVersion = 34
const val compileSdkVersion = 34 const val compileSdkVersion = 34