Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-07 11:00:41 +02:00
commit e3868e3ecd
3 changed files with 146 additions and 50 deletions

View file

@ -4,7 +4,6 @@ import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.performTextInputInChunks
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.screens.accounts.onAccountDetailsScreen
import com.tangem.screens.onAddCustomTokenScreen
import com.tangem.screens.onDetailsScreen
@ -13,7 +12,6 @@ import com.tangem.screens.onManageTokensScreen
import com.tangem.screens.onWalletSettingsScreen
import io.github.kakaocup.kakao.common.utilities.getResourceString
import io.qameta.allure.kotlin.Allure.step
import kotlinx.coroutines.runBlocking
import com.tangem.core.res.R as CoreResR
private fun mainAccountName(): String = getResourceString(CoreResR.string.account_main_account_title)
@ -68,18 +66,6 @@ fun BaseTestCase.addCustomTokenWithCustomDerivation(network: String, contract: S
navigateBackToMainFromManageTokens()
}
private const val MAX_BACKS_TO_MANAGE_TOKENS = 5
// The device-backs to close the sheet vary — press back until Manage Tokens is shown, then fail loudly.
private fun BaseTestCase.closeAddCustomTokenSheet() {
repeat(MAX_BACKS_TO_MANAGE_TOKENS) {
if (runCatching { onManageTokensScreen { searchField.assertIsDisplayed() } }.isSuccess) return
device.uiDevice.pressBack()
waitForIdle()
}
onManageTokensScreen { searchField.assertIsDisplayed() }
}
private fun BaseTestCase.navigateBackToWalletSettings() {
step("Click on 'Manage tokens' screen 'Back' button") {
waitForIdle()
@ -91,28 +77,6 @@ private fun BaseTestCase.navigateBackToWalletSettings() {
}
}
fun BaseTestCase.forgetCurrentWalletAndReArmForNextScan() {
step("Close 'Add custom token' bottom sheet") { closeAddCustomTokenSheet() }
navigateBackToWalletSettings()
step("Click on 'Forget wallet' button") {
waitForIdle()
onWalletSettingsScreen {
scrollToForgetWallet()
forgetWalletButton.clickWithAssertion()
}
}
step("Confirm forgetting the wallet") {
awaitSuccess { onDialog { forgetButton.assertIsDisplayed() } }
onDialog { forgetButton.clickWithAssertion() }
}
// Markets tooltip is a one-time app-level flag; re-arm it so the next scan's openMainScreen can dismiss it.
step("Re-arm the markets tooltip for the next scan") {
runBlocking {
appPreferencesStore.editData { it.set(PreferencesKeys.SHOULD_SHOW_MARKETS_TOOLTIP_KEY, value = true) }
}
}
}
fun BaseTestCase.assertDerivationPathsInSelector(networkToOpen: String, vararg expectedPaths: Pair<String, String>) {
step("Click on network: '$networkToOpen'") {
awaitSuccess { onAddCustomTokenScreen { scrollToNetwork(networkToOpen) } }

View file

@ -9,7 +9,6 @@ import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.domain.models.scan.ProductType
import com.tangem.scenarios.addCustomTokenWithCustomDerivation
import com.tangem.scenarios.assertDerivationPathsInSelector
import com.tangem.scenarios.forgetCurrentWalletAndReArmForNextScan
import com.tangem.scenarios.navigateBackToMainFromManageTokens
import com.tangem.scenarios.openAddCustomToken
import com.tangem.scenarios.openMainScreen
@ -208,38 +207,62 @@ class AddCustomTokenTest : BaseTestCase() {
}
@AllureId("776")
@DisplayName("Add custom token: derivation paths match the card version (V1/V2/V3)")
@DisplayName("Add custom token: derivation paths match a legacy-batch V1 Wallet card")
@Test
fun derivationPathsMatchCardVersionTest() {
fun derivationPathsLegacyBatchWalletTest() {
setupHooks(
additionalAfterSection = { resetWireMockScenarioState(COINS_API_SCENARIO) },
).run {
step("Set WireMock scenario: '$COINS_API_SCENARIO' to state: '$richState'") {
setWireMockScenarioState(COINS_API_SCENARIO, richState)
}
step("Assert derivation paths for a legacy-batch V1 Wallet card") {
openMainScreen(mockContent = Wallet1LegacyDerivationMockContent)
openAddCustomToken()
step("Open 'Main Screen'") { openMainScreen(mockContent = Wallet1LegacyDerivationMockContent) }
step("Open 'Add custom token' screen") { openAddCustomToken() }
step("Assert V1 derivation paths are displayed in the selector") {
assertDerivationPathsInSelector(
ethereumNetwork,
bitcoinNetworkId to "m/44'/0'/0'/0/0",
ethereumClassicNetworkId to "m/44'/61'/0'/0/0",
)
forgetCurrentWalletAndReArmForNextScan()
}
step("Assert derivation paths for a V2 Wallet card") {
openMainScreen()
openAddCustomToken()
}
}
@AllureId("10204")
@DisplayName("Add custom token: derivation paths match a V2 Wallet card")
@Test
fun derivationPathsWalletTest() {
setupHooks(
additionalAfterSection = { resetWireMockScenarioState(COINS_API_SCENARIO) },
).run {
step("Set WireMock scenario: '$COINS_API_SCENARIO' to state: '$richState'") {
setWireMockScenarioState(COINS_API_SCENARIO, richState)
}
step("Open 'Main Screen'") { openMainScreen() }
step("Open 'Add custom token' screen") { openAddCustomToken() }
step("Assert V2 derivation paths are displayed in the selector") {
assertDerivationPathsInSelector(
ethereumNetwork,
bitcoinNetworkId to "m/44'/0'/0'/0/0",
ethereumClassicNetworkId to "m/44'/60'/0'/0/0",
)
forgetCurrentWalletAndReArmForNextScan()
}
step("Assert derivation paths for a V3 Wallet 2 card") {
openMainScreen(productType = ProductType.Wallet2)
openAddCustomToken()
}
}
@AllureId("10205")
@DisplayName("Add custom token: derivation paths match a V3 Wallet 2 card")
@Test
fun derivationPathsWallet2Test() {
setupHooks(
additionalAfterSection = { resetWireMockScenarioState(COINS_API_SCENARIO) },
).run {
step("Set WireMock scenario: '$COINS_API_SCENARIO' to state: '$richState'") {
setWireMockScenarioState(COINS_API_SCENARIO, richState)
}
step("Open 'Main Screen'") { openMainScreen(productType = ProductType.Wallet2) }
step("Open 'Add custom token' screen") { openAddCustomToken() }
step("Assert V3 derivation paths are displayed in the selector") {
assertDerivationPathsInSelector(
ethereumNetwork,
bitcoinNetworkId to "m/84'/0'/0'/0/0",

View file

@ -14,6 +14,7 @@ import com.tangem.common.extensions.extractText
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.domain.models.scan.ProductType
import com.tangem.scenarios.*
import com.tangem.screens.*
import com.tangem.tap.domain.sdk.mocks.content.Wallet2WithDerivationsMockContent
@ -825,4 +826,112 @@ class SendViaSwapTest : BaseTestCase() {
}
}
}
@AllureId("3972")
@DisplayName("Send via Swap: single-currency card has no 'Convert' button in Send")
@Test
fun singleCurrencyCardNoConvertButtonInSendTest() {
val cardType = ProductType.Note
val tokenTitle = "Dogecoin"
setupHooks().run {
step("Open 'Main Screen' on '${cardType.name}' card") {
openMainScreen(cardType)
}
step("Assert 'Add funds' button is displayed") {
onMainScreen { addFundsButton.assertIsDisplayed() }
}
step("Assert 'Transfer' button is displayed") {
onMainScreen { transferButton.assertIsDisplayed() }
}
step("Assert 'Swap' button is not displayed") {
onMainScreen { swapButton.assertIsNotDisplayed() }
}
step("Click on 'Transfer' button") {
onMainScreen { transferButton.performClick() }
}
step("Click on token: '$tokenTitle'") {
onChooseTokenBottomSheet { tokenWithTitle(tokenTitle).clickWithAssertion() }
}
step("Click on 'Send' button in bottom sheet") {
onTransferBottomSheet { sendButton.clickWithAssertion() }
}
step("Assert amount input text field is displayed") {
flakySafely { onSendScreen { amountInputTextField.assertIsDisplayed() } }
}
step("Assert 'Swap to another token' button is not displayed") {
onSendScreen { swapToAnotherTokenButton.assertDoesNotExist() }
}
}
}
@AllureId("10196")
@DisplayName("Send via Swap: memo-restricted network is not selectable as a receive token")
@Test
fun memoRestrictedNetworkNotSelectableAsReceiveTokenTest() {
val tokenName = "Bitcoin"
val algorand = "Algorand"
val bitcoinBalanceScenarioName = "bitcoin_utxo"
val bitcoinBalanceScenarioState = "Balance"
val assetsScenarioName = "express_api_assets"
val assetsScenarioState = "BitcoinExchangeEnabled"
val userTokensScenarioState = "Wallet2"
val coinsScenarioName = "coins_api"
val coinsScenarioState = "WithAlgorand"
val warningTitle = getResourceString(R.string.express_swap_not_supported_title, algorand)
val warningMessage = getResourceString(R.string.express_swap_not_supported_text)
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(bitcoinBalanceScenarioName)
resetWireMockScenarioState(assetsScenarioName)
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(coinsScenarioName)
}
).run {
step("Set WireMock scenario: '$bitcoinBalanceScenarioName' to state: '$bitcoinBalanceScenarioState'") {
setWireMockScenarioState(scenarioName = bitcoinBalanceScenarioName, state = bitcoinBalanceScenarioState)
}
step("Set WireMock scenario: '$assetsScenarioName' to state: '$assetsScenarioState'") {
setWireMockScenarioState(scenarioName = assetsScenarioName, state = assetsScenarioState)
}
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$userTokensScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = userTokensScenarioState)
}
step("Set WireMock scenario: '$coinsScenarioName' to state: '$coinsScenarioState'") {
setWireMockScenarioState(scenarioName = coinsScenarioName, state = coinsScenarioState)
}
step("Open 'Send' screen") {
openSendScreen(tokenName, mockContent = Wallet2WithDerivationsMockContent)
}
step("Click on 'Swap to another token' button") {
onSendScreen { swapToAnotherTokenButton.performClick() }
}
step("Type '$algorand' in search text field") {
onSendViaSwapScreen {
searchField.performClick()
searchField.performTextInput(algorand)
}
}
step("Click on token: '$algorand'") {
onSendViaSwapScreen { tokenItem(algorand).performClick() }
}
step("Assert warning bottom sheet icon is displayed") {
onWarningBottomSheet { icon.assertIsDisplayed() }
}
step("Assert warning bottom sheet title is displayed") {
onWarningBottomSheet { title(warningTitle).assertIsDisplayed() }
}
step("Assert warning bottom sheet message is displayed") {
onWarningBottomSheet { message(warningMessage).assertIsDisplayed() }
}
step("Click on 'Ok, Got it!' button") {
onWarningBottomSheet { okGotItButton.performClick() }
}
step("Assert 'Swap to another token' screen is displayed") {
onSendViaSwapScreen { tokenItem(algorand).assertIsDisplayed() }
}
}
}
}