From d30f231520cc5ef1ef160f49039705c08b660840 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Apr 2026 13:10:18 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/common/constants/TestConstants.kt | 1 + .../com/tangem/scenarios/AccountsScenarios.kt | 102 +++++++ .../com/tangem/screens/DialogPageObject.kt | 5 + .../screens/WalletSettingsPageObject.kt | 12 + .../AccountDetailsPageObject.kt | 19 +- .../accounts/ArchivedAccountsPageObject.kt | 70 +++++ .../tests/accounts/AccountArchivationsTest.kt | 253 ++++++++++++++++++ .../com/tangem/tests/main/HideTokenTest.kt | 10 +- .../sdk/mocks/content/WalletMockContent.kt | 101 ++++++- .../tangem/common/ui/account/AccountRow.kt | 5 + .../ui/test/AccountDetailsScreenTestTags.kt | 5 - .../ui/test/WalletSettingsScreenTestTags.kt | 1 + .../accounts/AccountDetailsScreenTestTags.kt | 9 + .../accounts/AccountInfoEditScreenTestTags.kt | 10 + .../ui/test/accounts/AccountRowTestTags.kt | 7 + .../ArchivedAccountsScreenTestTags.kt | 8 + .../archived/ui/ArchivedAccountListContent.kt | 8 +- .../createedit/ui/AccountCreateEditContent.kt | 8 +- .../details/ui/AccountDetailsContent.kt | 11 +- 19 files changed, 613 insertions(+), 32 deletions(-) create mode 100644 app/src/androidTest/kotlin/com/tangem/scenarios/AccountsScenarios.kt rename app/src/androidTest/kotlin/com/tangem/screens/{ => accounts}/AccountDetailsPageObject.kt (58%) create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/accounts/ArchivedAccountsPageObject.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/tests/accounts/AccountArchivationsTest.kt delete mode 100644 core/ui/src/main/java/com/tangem/core/ui/test/AccountDetailsScreenTestTags.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountDetailsScreenTestTags.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountInfoEditScreenTestTags.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountRowTestTags.kt create mode 100644 core/ui/src/main/java/com/tangem/core/ui/test/accounts/ArchivedAccountsScreenTestTags.kt diff --git a/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt b/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt index 8ad9db91da..4b2d416965 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt @@ -43,6 +43,7 @@ object TestConstants { const val ALLURE_LABEL_VALUE = "Kaspresso" const val USER_TOKENS_API_SCENARIO = "user_tokens_api" + const val REFERRAL_API_SCENARIO = "referral_api" const val QUOTES_API_SCENARIO = "quotes_api" const val SEED_PHRASE_12 = "they cram join fantasy unfair observe true theory buffalo bus exchange walk" diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/AccountsScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/AccountsScenarios.kt new file mode 100644 index 0000000000..7320642036 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/AccountsScenarios.kt @@ -0,0 +1,102 @@ +package com.tangem.scenarios + +import com.tangem.common.BaseTestCase +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.screens.accounts.onAccountDetailsScreen +import com.tangem.screens.accounts.onArchivedAccountsScreen +import com.tangem.screens.onDetailsScreen +import com.tangem.screens.onDialog +import com.tangem.screens.onMainScreenTopBar +import com.tangem.screens.onWalletSettingsScreen +import io.qameta.allure.kotlin.Allure.step + +fun BaseTestCase.openWalletSettingsScreen() { + step("Open 'Wallet details' screen") { + onMainScreenTopBar { moreButton.clickWithAssertion() } + } + step("Open 'Wallet settings' screen") { + onDetailsScreen { walletNameButton.clickWithAssertion() } + } +} + +fun BaseTestCase.openAccountDetails(accountName: String) { + step("Click on account: '$accountName'") { + onWalletSettingsScreen { accountItem(accountName).clickWithAssertion() } + } + step("Assert 'Account details' screen is displayed") { + onAccountDetailsScreen { screenContainer.assertIsDisplayed() } + } +} + +fun BaseTestCase.archiveAccount() { + step("Assert 'Archive' button is displayed") { + onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() } + } + step("Click on 'Archive' button") { + onAccountDetailsScreen { archiveAccountButton.clickWithAssertion() } + } + step("Confirm archivation in dialog") { + onDialog { archiveButton.clickWithAssertion() } + } +} + +fun BaseTestCase.assertArchiveConfirmationDialog() { + step("Assert confirmation dialog is displayed") { + onDialog { dialogContainer.assertIsDisplayed() } + } + step("Assert confirmation dialog has 'Cancel' button") { + onDialog { cancelButton.assertIsDisplayed() } + } + step("Assert confirmation dialog has 'Archive' button") { + onDialog { archiveButton.assertIsDisplayed() } + } +} + +fun BaseTestCase.assertErrorDialog(expectedTitle: String, expectedMessage: String) { + step("Assert error dialog is displayed") { + onDialog { dialogContainer.assertIsDisplayed() } + } + step("Assert error dialog has proper title") { + onDialog { + title.assertTextContains(expectedTitle) + } + } + step("Assert error dialog has explanatory text") { + onDialog { + text.assertTextContains(expectedMessage) + } + } + step("Assert error dialog has 'OK' button") { + onDialog { okButton.assertIsDisplayed() } + } +} + +fun BaseTestCase.dismissErrorDialog() { + step("Dismiss error dialog by clicking 'Ok' button") { + onDialog { okButton.clickWithAssertion() } + } +} + +fun BaseTestCase.openArchivedAccountsScreen() { + step("Click on 'Archived accounts' button") { + onWalletSettingsScreen { openArchivedAccountsButton.clickWithAssertion() } + } +} + +fun BaseTestCase.assertArchivedAccountIsDisplayed(accountName: String) { + step("Assert archived account with name '$accountName' is displayed") { + onArchivedAccountsScreen { + findArchivedAccountItemByName(accountName) + .container.assertIsDisplayed() + } + } +} + +fun BaseTestCase.restoreArchivedAccount(accountName: String) { + step("Restore account with name '$accountName'") { + onArchivedAccountsScreen { + findArchivedAccountItemByName(accountName) + .restoreButton.clickWithAssertion() + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DialogPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/DialogPageObject.kt index ff268b8969..87e72b5b05 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/DialogPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/DialogPageObject.kt @@ -40,6 +40,11 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : hasText(getResourceString(R.string.common_confirm)) } + val archiveButton: KNode = child { + hasTestTag(BaseButtonTestTags.BUTTON) + hasText(getResourceString(R.string.account_details_archive_action)) + } + val continueButton: KNode = child { hasTestTag(BaseButtonTestTags.BUTTON) hasText(getResourceString(R.string.common_continue)) diff --git a/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPageObject.kt index db6413a7f2..5b84dda406 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPageObject.kt @@ -38,6 +38,18 @@ class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi hasText(getResourceString(R.string.settings_forget_wallet)) } + val accountsListContainer: KNode = walletSettingsItem.child { + hasTestTag(WalletSettingsScreenTestTags.ACCOUNTS_CONTAINER) + } + + val addAccountButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.account_form_create_button)) + } + + val openArchivedAccountsButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.account_archived_accounts)) + } + fun accountItem(accountName: String): KNode = walletSettingsItem.child { hasTestTag(WalletSettingsScreenTestTags.USER_ACCOUNT_ITEM) hasAnyDescendant(withText(accountName)) diff --git a/app/src/androidTest/kotlin/com/tangem/screens/AccountDetailsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/accounts/AccountDetailsPageObject.kt similarity index 58% rename from app/src/androidTest/kotlin/com/tangem/screens/AccountDetailsPageObject.kt rename to app/src/androidTest/kotlin/com/tangem/screens/accounts/AccountDetailsPageObject.kt index b347ee4785..99d9841489 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/AccountDetailsPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/accounts/AccountDetailsPageObject.kt @@ -1,8 +1,8 @@ -package com.tangem.screens +package com.tangem.screens.accounts import androidx.compose.ui.test.SemanticsNodeInteractionsProvider import com.tangem.common.BaseTestCase -import com.tangem.core.ui.test.AccountDetailsScreenTestTags +import com.tangem.core.ui.test.accounts.AccountDetailsScreenTestTags import com.tangem.core.ui.test.TopAppBarTestTags import io.github.kakaocup.compose.node.element.ComposeScreen import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen @@ -11,6 +11,10 @@ import io.github.kakaocup.compose.node.element.KNode class AccountDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen(semanticsProvider = semanticsProvider) { + val screenContainer: KNode = child { + hasTestTag(AccountDetailsScreenTestTags.ACCOUNT_DETAILS_CONTAINER) + } + val topAppBarBackButton: KNode = child { hasTestTag(TopAppBarTestTags.CLOSE_BUTTON) } @@ -18,7 +22,16 @@ class AccountDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi val manageTokensButton: KNode = child { hasTestTag(AccountDetailsScreenTestTags.MANAGE_TOKENS_BUTTON) } + + val archiveAccountButton: KNode = child { + hasTestTag(AccountDetailsScreenTestTags.ARCHIVE_ACCOUNT_BUTTON) + } + + val editAccountButton: KNode = child { + hasTestTag(AccountDetailsScreenTestTags.EDIT_ACCOUNT_BUTTON) + } + } -internal fun BaseTestCase.onAccountDetails(function: AccountDetailsPageObject.() -> Unit) = +internal fun BaseTestCase.onAccountDetailsScreen(function: AccountDetailsPageObject.() -> Unit) = onComposeScreen(composeTestRule, function) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/accounts/ArchivedAccountsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/accounts/ArchivedAccountsPageObject.kt new file mode 100644 index 0000000000..5fd1d2cae7 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/accounts/ArchivedAccountsPageObject.kt @@ -0,0 +1,70 @@ +package com.tangem.screens.accounts + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.common.BaseTestCase +import com.tangem.core.ui.R +import com.tangem.core.ui.test.TopAppBarTestTags +import com.tangem.core.ui.test.accounts.AccountRowTestTags +import com.tangem.core.ui.test.accounts.ArchivedAccountsScreenTestTags +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.hasText as withText + +class ArchivedAccountsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen(semanticsProvider = semanticsProvider) { + + val screenContainer: KNode = child { + hasTestTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNTS_SCREEN_CONTAINER) + } + + val topAppBarBackButton: KNode = child { + hasTestTag(TopAppBarTestTags.CLOSE_BUTTON) + } + + val topAppBarTitle: KNode = child { + hasTestTag(TopAppBarTestTags.TITLE) + hasText(getResourceString(R.string.account_archived_accounts)) + useUnmergedTree = true + } + + /** + * Returns a composite handle for a single archived account row, scoped by account name. + * All sub-elements (icon, title, tokens, networks, restore button) are children of this row. + */ + fun findArchivedAccountItemByName(accountName: String): ArchivedAccountRow { + val container: KNode = child { + hasTestTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNT_ITEM) + hasAnyDescendant(withText(accountName)) + useUnmergedTree = true + } + return ArchivedAccountRow(container) + } + + class ArchivedAccountRow(val container: KNode) { + + val icon: KNode = container.child { + hasTestTag(AccountRowTestTags.ICON) + useUnmergedTree = true + } + + val title: KNode = container.child { + hasTestTag(AccountRowTestTags.TITLE) + useUnmergedTree = true + } + + val subtitle: KNode = container.child { + hasTestTag(AccountRowTestTags.SUBTITLE) + useUnmergedTree = true + } + + val restoreButton: KNode = container.child { + hasTestTag(ArchivedAccountsScreenTestTags.RESTORE_BUTTON) + useUnmergedTree = true + } + } +} + +internal fun BaseTestCase.onArchivedAccountsScreen(function: ArchivedAccountsPageObject.() -> Unit) = + onComposeScreen(composeTestRule, function) diff --git a/app/src/androidTest/kotlin/com/tangem/tests/accounts/AccountArchivationsTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/accounts/AccountArchivationsTest.kt new file mode 100644 index 0000000000..70e4d5d02a --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/tests/accounts/AccountArchivationsTest.kt @@ -0,0 +1,253 @@ +package com.tangem.tests.accounts + +import com.tangem.common.BaseTestCase +import com.tangem.common.constants.TestConstants.REFERRAL_API_SCENARIO +import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.common.utils.resetWireMockScenarioState +import com.tangem.common.utils.setWireMockScenarioState +import com.tangem.core.ui.R +import com.tangem.scenarios.* +import com.tangem.screens.accounts.onAccountDetailsScreen +import com.tangem.screens.accounts.onArchivedAccountsScreen +import com.tangem.screens.onDialog +import com.tangem.screens.onWalletSettingsScreen +import dagger.hilt.android.testing.HiltAndroidTest +import io.github.kakaocup.kakao.common.utilities.getResourceString +import io.qameta.allure.kotlin.AllureId +import io.qameta.allure.kotlin.junit4.DisplayName +import org.junit.Test + +@HiltAndroidTest +class AccountArchivationsTest : BaseTestCase() { + + private val userTokensScenario = USER_TOKENS_API_SCENARIO + private val referralScenario = REFERRAL_API_SCENARIO + + @Test + @AllureId("5979") + @DisplayName("Accounts: Verify main account archivation button not available") + fun mainAccountArchivationAttemptTest() { + val mainAccountName = "Main account" + + setupHooks().run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open wallet account with name $mainAccountName") { openAccountDetails(mainAccountName) } + step("Assert archive button is NOT displayed") { + onAccountDetailsScreen { archiveAccountButton.assertDoesNotExist() } + } + } + } + + @Test + @AllureId("5974") + @DisplayName("Accounts: archive a non-main account") + fun archiveSuccessfullyAccountTest() { + val accountToArchiveName = "Account 2" + val userAccountsState = "TwoAccountsArchivable" + + setupHooks( + additionalBeforeSection = { + setWireMockScenarioState(userTokensScenario, userAccountsState) + }, + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenario) + }, + ).run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open wallet account with name $accountToArchiveName") { + openAccountDetails(accountToArchiveName) + } + + step("Assert 'Archive' button is displayed") { + onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() } + } + step("Click on 'Archive' button") { + onAccountDetailsScreen { archiveAccountButton.clickWithAssertion() } + } + step("Verify 'Archive confirmation' dialog appeared with all elements") { + assertArchiveConfirmationDialog() + } + step("Click 'Archive' in confirmation menu") { + onDialog { archiveButton.clickWithAssertion() } + } + + step("Verify app returned to 'Wallet settings' screen") { + onWalletSettingsScreen { addAccountButton.assertIsDisplayed() } + } + step("Verify archived account '$accountToArchiveName' is no longer listed") { + onWalletSettingsScreen { + accountItem(accountToArchiveName).assertDoesNotExist() + } + } + } + } + + @Test + @AllureId("6844") + @DisplayName("Accounts: account archivation error on UI") + fun archiveAccountErrorTest() { + val accountToArchiveName = "Account 2" + val userAccountsState = "TwoAccountsArchivable" + val userAccountsErrorState = "AccountsPutError" + + setupHooks( + additionalBeforeSection = { + setWireMockScenarioState(userTokensScenario, userAccountsState) + }, + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenario) + }, + ).run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open wallet account with name $accountToArchiveName") { + openAccountDetails(accountToArchiveName) + } + + step("Forcing network error scenario") { + setWireMockScenarioState(userTokensScenario, userAccountsErrorState) + } + step("Attempt to archive the account") { archiveAccount() } + step("Assert error dialog details") { + assertErrorDialog( + expectedTitle = getResourceString(R.string.common_something_went_wrong), + expectedMessage = getResourceString(R.string.account_generic_error_dialog_message), + ) + } + } + } + + @Test + @AllureId("5981") + @DisplayName("Accounts: archive account with referral program error") + fun archiveAccountReferralErrorTest() { + val accountToArchiveName = "Account 2" + val userAccountsState = "TwoAccountsArchivableAndReferral" + val referralActiveState = "Participating" + + setupHooks( + additionalBeforeSection = { + setWireMockScenarioState(userTokensScenario, userAccountsState) + setWireMockScenarioState(referralScenario, referralActiveState) + }, + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenario) + resetWireMockScenarioState(referralScenario) + }, + ).run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open wallet account with name $accountToArchiveName") { + openAccountDetails(accountToArchiveName) + } + step("Attempt to archive the account") { archiveAccount() } + + step("Assert error dialog details") { + assertErrorDialog( + expectedTitle = getResourceString(R.string.account_could_not_archive_referral_program_title), + expectedMessage = getResourceString(R.string.account_could_not_archive_referral_program_message), + ) + } + step("Dismiss error dialog") { dismissErrorDialog() } + step("Assert 'Archive' button is still visible after error") { + onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() } + } + } + } + + @Test + @AllureId("5976") + @DisplayName("Accounts: restore an archived account") + fun restoreArchivedAccountTest() { + val archivedAccountName = "Account 3" + val userAccountsInitialState = "TwoAccountsWithArchivedAccounts" + val userAccountsAfterArchivationState = "ReadyToRestore" + + setupHooks( + additionalBeforeSection = { + setWireMockScenarioState(userTokensScenario, userAccountsInitialState) + }, + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenario) + }, + ).run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open 'Archived accounts' screen") { openArchivedAccountsScreen() } + step("Verify archived wallet account with name '$archivedAccountName' is present") { + assertArchivedAccountIsDisplayed(archivedAccountName) + } + + step("Switch WireMock to '$userAccountsAfterArchivationState' users scenario state") { + setWireMockScenarioState(userTokensScenario, userAccountsAfterArchivationState) + } + step("Restore account with name '$archivedAccountName'") { + restoreArchivedAccount(archivedAccountName) + } + + step("Assert 'Wallet settings' screen is displayed") { + onWalletSettingsScreen { addAccountButton.assertIsDisplayed() } + } + step("Assert restored account '$archivedAccountName' appears in 'Active accounts' list") { + onWalletSettingsScreen { accountItem(archivedAccountName).assertIsDisplayed() } + } + } + } + + @Test + @AllureId("7962") + @DisplayName("Accounts: restore archived account error") + fun restoreArchivedAccountErrorTest() { + val archivedAccountName = "Account 3" + val userAccountsInitialState = "TwoAccountsWithArchivedAccounts" + val userAccountsRestorationErrorState = "AccountsPutError" + + setupHooks( + additionalBeforeSection = { + setWireMockScenarioState(userTokensScenario, userAccountsInitialState) + }, + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenario) + }, + ).run { + step("Open 'Main Screen'") { openMainScreen() } + step("Synchronize addresses") { synchronizeAddresses() } + step("Open wallet settings") { openWalletSettingsScreen() } + step("Open 'Archived accounts' screen") { openArchivedAccountsScreen() } + step("Verify archived wallet account with name '$archivedAccountName' is present") { + assertArchivedAccountIsDisplayed(archivedAccountName) + } + + step("Switch WireMock to '$userAccountsRestorationErrorState' user" + + "accounts scenario state to simulate restoration failure") { + setWireMockScenarioState(userTokensScenario, userAccountsRestorationErrorState) + } + step("Attempt restore account with name '$archivedAccountName'") { + restoreArchivedAccount(archivedAccountName) + } + + step("Assert error dialog details") { + assertErrorDialog( + expectedTitle = getResourceString(R.string.common_something_went_wrong), + expectedMessage = getResourceString(R.string.account_generic_error_dialog_message), + ) + } + step("Dismiss error dialog") { dismissErrorDialog() } + + step("Assert archived account '$archivedAccountName' is still in archived list") { + onArchivedAccountsScreen { + findArchivedAccountItemByName(archivedAccountName) + .container.assertIsDisplayed() + } + } + } + } +} diff --git a/app/src/androidTest/kotlin/com/tangem/tests/main/HideTokenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/main/HideTokenTest.kt index a69ee3c9f4..a576c9e327 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/main/HideTokenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/main/HideTokenTest.kt @@ -9,6 +9,7 @@ import com.tangem.common.utils.setWireMockScenarioState import com.tangem.scenarios.openMainScreen import com.tangem.scenarios.synchronizeAddresses import com.tangem.screens.* +import com.tangem.screens.accounts.onAccountDetailsScreen import dagger.hilt.android.testing.HiltAndroidTest import io.qameta.allure.kotlin.AllureId import io.qameta.allure.kotlin.junit4.DisplayName @@ -93,7 +94,7 @@ class HideTokenTest : BaseTestCase() { onWalletSettingsScreen { accountItem(accountName).performClick() } } step("Click on 'Manage tokens' button") { - onAccountDetails { manageTokensButton.performClick() } + onAccountDetailsScreen { manageTokensButton.performClick() } } step("Click on token: '$tokenTitle'") { onManageTokensScreen { tokenItem(tokenTitle).performClick() } @@ -118,7 +119,7 @@ class HideTokenTest : BaseTestCase() { } step("Click on 'Account details' screen 'Back' button") { waitForIdle() - onAccountDetails { topAppBarBackButton.performClick() } + onAccountDetailsScreen { topAppBarBackButton.performClick() } } step("Click on 'Wallet settings' screen 'Back' button") { waitForIdle() @@ -162,7 +163,7 @@ class HideTokenTest : BaseTestCase() { onWalletSettingsScreen { accountItem(accountName).performClick() } } step("Click on 'Manage tokens' button") { - onAccountDetails { manageTokensButton.performClick() } + onAccountDetailsScreen { manageTokensButton.performClick() } } step("Click on token: '$tokenTitle'") { onManageTokensScreen { tokenItem(tokenTitle).performClick() } @@ -187,7 +188,7 @@ class HideTokenTest : BaseTestCase() { } step("Click on 'Account details' screen 'Back' button") { waitForIdle() - onAccountDetails { topAppBarBackButton.performClick() } + onAccountDetailsScreen { topAppBarBackButton.performClick() } } step("Click on 'Wallet settings' screen 'Back' button") { waitForIdle() @@ -308,5 +309,4 @@ class HideTokenTest : BaseTestCase() { } } } - } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/mocks/content/WalletMockContent.kt b/app/src/main/java/com/tangem/tap/domain/sdk/mocks/content/WalletMockContent.kt index 382b50ad26..e6d872be54 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/mocks/content/WalletMockContent.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/mocks/content/WalletMockContent.kt @@ -24,6 +24,9 @@ import java.util.Date @Suppress("LargeClass") object WalletMockContent : MockContent { + private val secp256k1WalletPublicKey = + 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) + private val primaryCard = PrimaryCard( cardId = "AC05000000086747", batchId = "AC05", @@ -100,7 +103,7 @@ object WalletMockContent : MockContent { ), 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), + publicKey = secp256k1WalletPublicKey, 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), @@ -117,11 +120,15 @@ object WalletMockContent : MockContent { 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'/60'/0'/0/1") 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( + DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron Network 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), ), @@ -137,7 +144,7 @@ object WalletMockContent : MockContent { 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'/501'/0'") to ExtendedPublicKey( + DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana 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), ), @@ -151,7 +158,7 @@ object WalletMockContent : MockContent { ), ), 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), + publicKey = secp256k1WalletPublicKey, 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, @@ -193,9 +200,7 @@ object WalletMockContent : MockContent { 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), - ) + ByteArrayKey(secp256k1WalletPublicKey) to ExtendedPublicKeysMap( mapOf( @@ -220,6 +225,20 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), + DerivationPath("m/44'/60'/0'/0/1") to ExtendedPublicKey( // eth (account 2) + 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'/60'/0'/0/3") to ExtendedPublicKey( // eth (account 3) + 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), @@ -241,7 +260,14 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), - DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( + DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron (account 0) + 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, + ), + DerivationPath("m/44'/195'/1'/0/0") to ExtendedPublicKey( // Tron (account 2) 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, @@ -269,6 +295,13 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), + DerivationPath("m/44'/111111'/1'/0/0") to ExtendedPublicKey( // Kaspa (account 2) + 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, + ), DerivationPath("m/44'/330'/0'/0/0") to ExtendedPublicKey( // Terra 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), @@ -305,7 +338,14 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), - DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana + DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana (account 1) + 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), + 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'/501'/1'") to ExtendedPublicKey( // Solana (account 2) 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), 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, @@ -386,6 +426,13 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), + DerivationPath("m/44'/60'/0'/0/3") 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'/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), @@ -407,7 +454,30 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), + DerivationPath("m/44'/111111'/1'/0/0") to ExtendedPublicKey( // Kaspa (account 2) + 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(-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, + ), DerivationPath("m/44'/818'/0'/0/0") to ExtendedPublicKey( // Vechain + 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(-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, + ), + DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron (account 1) + 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, + ), + DerivationPath("m/44'/195'/1'/0/0") to ExtendedPublicKey( // Tron (account 2) 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, @@ -436,9 +506,16 @@ object WalletMockContent : MockContent { parentFingerprint = byteArrayOf(0, 0, 0, 0), childNumber = 0, ), - DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana - 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'/501'/0'") to ExtendedPublicKey( // Solana (account 1) + 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), + 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'/501'/1'") to ExtendedPublicKey( // Solana (account 2) + 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), + 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, diff --git a/common/ui/src/main/java/com/tangem/common/ui/account/AccountRow.kt b/common/ui/src/main/java/com/tangem/common/ui/account/AccountRow.kt index 8e755eb8bc..76873d6c56 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/account/AccountRow.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/account/AccountRow.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import com.tangem.common.ui.R @@ -19,6 +20,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.test.accounts.AccountRowTestTags /** * Displays a row representing an account with an icon, title, and subtitle. @@ -54,6 +56,7 @@ fun AccountRow( name = title, icon = icon, size = AccountIconSize.Default, + modifier = Modifier.testTag(AccountRowTestTags.ICON), ) Column( verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2), @@ -72,6 +75,7 @@ fun AccountRow( @Composable private fun Title(title: TextReference) { Text( + modifier = Modifier.testTag(AccountRowTestTags.TITLE), text = title.resolveReference(), style = TangemTheme.typography.subtitle2, color = TangemTheme.colors.text.primary1, @@ -83,6 +87,7 @@ private fun Title(title: TextReference) { @Composable private fun Subtitle(subtitle: TextReference) { Text( + modifier = Modifier.testTag(AccountRowTestTags.SUBTITLE), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.caption2, text = subtitle.resolveReference(), diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/AccountDetailsScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/AccountDetailsScreenTestTags.kt deleted file mode 100644 index ccc4793a3c..0000000000 --- a/core/ui/src/main/java/com/tangem/core/ui/test/AccountDetailsScreenTestTags.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.core.ui.test - -object AccountDetailsScreenTestTags { - const val MANAGE_TOKENS_BUTTON = "ACCOUNT_DETAILS_SCREEN_MANAGE_TOKENS_BUTTON" -} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/WalletSettingsScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/WalletSettingsScreenTestTags.kt index 6d178c0cd9..15b8847280 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/test/WalletSettingsScreenTestTags.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/test/WalletSettingsScreenTestTags.kt @@ -2,6 +2,7 @@ package com.tangem.core.ui.test object WalletSettingsScreenTestTags { const val SCREEN_CONTAINER = "WALLET_SETTINGS_SCREEN_CONTAINER" + const val ACCOUNTS_CONTAINER = "WALLET_SETTINGS_SCREEN_ACCOUNTS_CONTAINER" const val SCREEN_ITEM = "WALLET_SETTINGS_SCREEN_ITEM" const val USER_ACCOUNT_ITEM = "WALLET_SETTINGS_USER_ACCOUNT_ITEM" } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountDetailsScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountDetailsScreenTestTags.kt new file mode 100644 index 0000000000..cd4c95dbda --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountDetailsScreenTestTags.kt @@ -0,0 +1,9 @@ +package com.tangem.core.ui.test.accounts + +object AccountDetailsScreenTestTags { + + const val ACCOUNT_DETAILS_CONTAINER = "ACCOUNT_DETAILS_SCREEN_CONTAINER" + const val MANAGE_TOKENS_BUTTON = "ACCOUNT_DETAILS_SCREEN_MANAGE_TOKENS_BUTTON" + const val EDIT_ACCOUNT_BUTTON = "ACCOUNT_DETAILS_SCREEN_EDIT_ACCOUNT_BUTTON" + const val ARCHIVE_ACCOUNT_BUTTON = "ACCOUNT_DETAILS_SCREEN_ARCHIVE_ACCOUNT_BUTTON" +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountInfoEditScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountInfoEditScreenTestTags.kt new file mode 100644 index 0000000000..940f3eebe1 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountInfoEditScreenTestTags.kt @@ -0,0 +1,10 @@ +package com.tangem.core.ui.test.accounts + +object AccountInfoEditScreenTestTags { + const val ACCOUNT_DETAILS_CONTAINER = "ACCOUNT_INFO_EDIT_SCREEN_ACCOUNT_DETAILS_CONTAINER" + const val ADD_ACCOUNT_BUTTON = "ACCOUNT_INFO_EDIT_SCREEN_ADD_ACCOUNT_BUTTON" + const val COLOR_OPTION = "ACCOUNT_INFO_EDIT_SCREEN_ACCOUNT_INFO_COLOR_OPTION" + const val TYPE_OPTION = "ACCOUNT_INFO_EDIT_SCREEN_ACCOUNT_INFO_TYPE_OPTION" + const val SELECTED_ICON = "ACCOUNT_INFO_EDIT_SCREEN_SELECTED_ICON" + const val NAME_FIELD = "ACCOUNT_INFO_EDIT_SCREEN_ACCOUNT_INFO_NAME_FIELD" +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountRowTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountRowTestTags.kt new file mode 100644 index 0000000000..680509ff25 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/AccountRowTestTags.kt @@ -0,0 +1,7 @@ +package com.tangem.core.ui.test.accounts + +object AccountRowTestTags { + const val ICON = "ACCOUNT_ROW_ICON" + const val TITLE = "ACCOUNT_ROW_TITLE" + const val SUBTITLE = "ACCOUNT_ROW_SUBTITLE" +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/accounts/ArchivedAccountsScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/ArchivedAccountsScreenTestTags.kt new file mode 100644 index 0000000000..9bb6ef093f --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/test/accounts/ArchivedAccountsScreenTestTags.kt @@ -0,0 +1,8 @@ +package com.tangem.core.ui.test.accounts + +object ArchivedAccountsScreenTestTags { + + const val ARCHIVED_ACCOUNTS_SCREEN_CONTAINER = "ARCHIVED_ACCOUNTS_LIST_CONTAINER" + const val ARCHIVED_ACCOUNT_ITEM = "ARCHIVED_ACCOUNTS_LIST_ARCHIVED_ACCOUNT_ITEM" + const val RESTORE_BUTTON = "ARCHIVED_ACCOUNTS_LIST_RESTORE_BUTTON" +} \ No newline at end of file diff --git a/features/account/impl/src/main/java/com/tangem/features/account/archived/ui/ArchivedAccountListContent.kt b/features/account/impl/src/main/java/com/tangem/features/account/archived/ui/ArchivedAccountListContent.kt index 782341c8e1..7f4ec9b4c5 100644 --- a/features/account/impl/src/main/java/com/tangem/features/account/archived/ui/ArchivedAccountListContent.kt +++ b/features/account/impl/src/main/java/com/tangem/features/account/archived/ui/ArchivedAccountListContent.kt @@ -11,6 +11,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider @@ -27,6 +28,7 @@ import com.tangem.core.ui.extensions.stringReference 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.accounts.ArchivedAccountsScreenTestTags import com.tangem.features.account.archived.entity.AccountArchivedUM import com.tangem.features.account.archived.entity.ArchivedAccountUM import kotlinx.collections.immutable.toImmutableList @@ -102,7 +104,7 @@ private fun ArchiveAccountError(state: AccountArchivedUM.Error, modifier: Modifi @Composable private fun ArchiveAccountContent(state: AccountArchivedUM.Content, modifier: Modifier = Modifier) { - LazyColumn(modifier = modifier) { + LazyColumn(modifier = modifier.testTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNTS_SCREEN_CONTAINER)) { itemsIndexed( items = state.accounts, key = { index, item -> item.accountId }, @@ -127,7 +129,8 @@ private fun ArchivedAccountRow(item: ArchivedAccountUM, modifier: Modifier = Mod modifier = modifier .fillMaxWidth() .clickable(enabled = !item.isLoading, onClick = item.onClick) - .padding(all = TangemTheme.dimens.spacing12), + .padding(all = TangemTheme.dimens.spacing12) + .testTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNT_ITEM), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), ) { @@ -151,6 +154,7 @@ private fun ArchivedAccountRow(item: ArchivedAccountUM, modifier: Modifier = Mod isLoading = item.isLoading, onClick = item.onClick, ), + modifier = Modifier.testTag(ArchivedAccountsScreenTestTags.RESTORE_BUTTON), ) } } diff --git a/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt b/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt index 792db8d675..1dc4a29253 100644 --- a/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt +++ b/features/account/impl/src/main/java/com/tangem/features/account/createedit/ui/AccountCreateEditContent.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -40,6 +41,7 @@ import com.tangem.core.ui.components.fields.AutoSizeTextField import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.test.accounts.AccountInfoEditScreenTestTags import com.tangem.core.ui.utils.rememberHideKeyboardNestedScrollConnection import com.tangem.domain.models.account.CryptoPortfolioIcon import com.tangem.features.account.createedit.entity.AccountCreateEditUM @@ -128,6 +130,8 @@ private fun AccountSummary(account: Account, isCreateMode: Boolean) { name = account.name.value, icon = account.portfolioIcon, size = AccountIconSize.Large, + modifier = Modifier + .testTag(AccountInfoEditScreenTestTags.SELECTED_ICON), ) Spacer(modifier = Modifier.height(24.dp)) @@ -159,7 +163,9 @@ private fun AccountSummary(account: Account, isCreateMode: Boolean) { account.onNameChange(newName) }, - textFieldModifier = Modifier.focusRequester(focusRequester), + textFieldModifier = Modifier + .focusRequester(focusRequester) + .testTag(AccountInfoEditScreenTestTags.NAME_FIELD), ) SpacerH(20.dp) } diff --git a/features/account/impl/src/main/java/com/tangem/features/account/details/ui/AccountDetailsContent.kt b/features/account/impl/src/main/java/com/tangem/features/account/details/ui/AccountDetailsContent.kt index b8a0613c61..e764b00d99 100644 --- a/features/account/impl/src/main/java/com/tangem/features/account/details/ui/AccountDetailsContent.kt +++ b/features/account/impl/src/main/java/com/tangem/features/account/details/ui/AccountDetailsContent.kt @@ -32,7 +32,7 @@ import com.tangem.core.ui.extensions.stringReference 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.AccountDetailsScreenTestTags +import com.tangem.core.ui.test.accounts.AccountDetailsScreenTestTags import com.tangem.features.account.details.entity.AccountDetailsUM @Composable @@ -42,7 +42,8 @@ internal fun AccountDetailsContent(state: AccountDetailsUM, modifier: Modifier = .background(color = TangemTheme.colors.background.secondary) .fillMaxSize() .imePadding() - .systemBarsPadding(), + .systemBarsPadding() + .testTag(AccountDetailsScreenTestTags.ACCOUNT_DETAILS_CONTAINER), horizontalAlignment = Alignment.CenterHorizontally, ) { AppBarWithBackButton( @@ -95,7 +96,8 @@ private fun ArchiveAccountRow(state: AccountDetailsUM.ArchiveMode.Available) { .clip(RoundedCornerShape(TangemTheme.dimens.radius12)) .background(TangemTheme.colors.background.primary) .clickable(enabled = !state.isLoading, onClick = state.onArchiveAccountClick) - .padding(all = TangemTheme.dimens.spacing12), + .padding(all = TangemTheme.dimens.spacing12) + .testTag(AccountDetailsScreenTestTags.ARCHIVE_ACCOUNT_BUTTON), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), ) { @@ -160,7 +162,8 @@ private fun AccountRow(state: AccountDetailsUM) { .clip(RoundedCornerShape(TangemTheme.dimens.radius12)) .background(TangemTheme.colors.background.primary) .clickable(onClick = state.onAccountEditClick) - .padding(all = TangemTheme.dimens.spacing12), + .padding(all = TangemTheme.dimens.spacing12) + .testTag(AccountDetailsScreenTestTags.EDIT_ACCOUNT_BUTTON), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), ) {