274 lines
No EOL
13 KiB
Kotlin
274 lines
No EOL
13 KiB
Kotlin
package com.tangem.tests.main
|
|
|
|
import com.tangem.common.BaseTestCase
|
|
import com.tangem.common.constants.TestConstants.COINS_API_SCENARIO
|
|
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
|
import com.tangem.common.extensions.performTextInputInChunks
|
|
import com.tangem.common.utils.resetWireMockScenarioState
|
|
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.navigateBackToMainFromManageTokens
|
|
import com.tangem.scenarios.openAddCustomToken
|
|
import com.tangem.scenarios.openMainScreen
|
|
import com.tangem.scenarios.synchronizeAddresses
|
|
import com.tangem.screens.onAddCustomTokenScreen
|
|
import com.tangem.screens.onMainScreen
|
|
import com.tangem.tap.domain.sdk.mocks.content.Wallet1LegacyDerivationMockContent
|
|
import com.tangem.tap.domain.sdk.mocks.content.Wallet2NoEd25519Slip0010MockContent
|
|
import dagger.hilt.android.testing.HiltAndroidTest
|
|
import io.qameta.allure.kotlin.AllureId
|
|
import io.qameta.allure.kotlin.junit4.DisplayName
|
|
import org.junit.Assert.assertFalse
|
|
import org.junit.Test
|
|
|
|
@HiltAndroidTest
|
|
class AddCustomTokenTest : BaseTestCase() {
|
|
|
|
private val richState = "ManageTokensRich"
|
|
private val tokenTitle = "Tether"
|
|
private val ethereumNetwork = "Ethereum"
|
|
private val solanaNetwork = "Solana"
|
|
private val bitcoinNetworkId = "bitcoin"
|
|
private val ethereumClassicNetworkId = "ethereum-classic"
|
|
private val ethContract = "0xdac17f958d2ee523a2206206994597c13d831ec7"
|
|
private val solanaContract = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
|
|
private val customDerivationPath = "m/44'/60'/0'/0/1"
|
|
|
|
@AllureId("772")
|
|
@DisplayName("Add custom token: added token appears on Main")
|
|
@Test
|
|
fun addCustomTokenAppearsOnMainTest() {
|
|
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("Synchronize addresses") {
|
|
flakySafely { onMainScreen { synchronizeAddressesButton.assertIsDisplayed() } }
|
|
synchronizeAddresses(assertBalance = false)
|
|
}
|
|
step("Open 'Add custom token' screen") { openAddCustomToken() }
|
|
step("Click on network: '$ethereumNetwork'") {
|
|
flakySafely { onAddCustomTokenScreen { scrollToNetwork(ethereumNetwork) } }
|
|
onAddCustomTokenScreen { networkRow(ethereumNetwork).performClick() }
|
|
}
|
|
step("Enter contract address: '$ethContract'") {
|
|
flakySafely { onAddCustomTokenScreen { contractAddressField.assertExists() } }
|
|
// Chunked input spans several validation ticks — the model drops the first sampled form change.
|
|
onAddCustomTokenScreen { contractAddressField.performTextInputInChunks(ethContract) }
|
|
}
|
|
step("Click on 'Add token' button") {
|
|
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) { onAddCustomTokenScreen { addTokenButton.assertIsEnabled() } }
|
|
onAddCustomTokenScreen { addTokenButton.performClick() }
|
|
}
|
|
step("Navigate back to 'Main Screen'") { navigateBackToMainFromManageTokens() }
|
|
step("Assert token: '$tokenTitle' is displayed on Main") {
|
|
flakySafely { onMainScreen { tokenWithTitleAndAddress(tokenTitle).assertIsDisplayed() } }
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("775")
|
|
@DisplayName("Add custom token: custom derivation path is accepted")
|
|
@Test
|
|
fun addCustomTokenWithCustomDerivationTest() {
|
|
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("Synchronize addresses") {
|
|
flakySafely { onMainScreen { synchronizeAddressesButton.assertIsDisplayed() } }
|
|
synchronizeAddresses(assertBalance = false)
|
|
}
|
|
step("Open 'Add custom token' screen") { openAddCustomToken() }
|
|
step("Add custom token with custom derivation on '$ethereumNetwork'") {
|
|
addCustomTokenWithCustomDerivation(
|
|
network = ethereumNetwork,
|
|
contract = ethContract,
|
|
derivationPath = customDerivationPath,
|
|
)
|
|
}
|
|
step("Assert token: '$tokenTitle' is displayed on Main") {
|
|
flakySafely { onMainScreen { tokenWithTitleAndAddress(tokenTitle).assertIsDisplayed() } }
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("771")
|
|
@DisplayName("Add custom token: custom derivation indicator is shown on Main")
|
|
@Test
|
|
fun customDerivationIndicatorOnMainTest() {
|
|
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("Synchronize addresses") {
|
|
flakySafely { onMainScreen { synchronizeAddressesButton.assertIsDisplayed() } }
|
|
synchronizeAddresses(assertBalance = false)
|
|
}
|
|
step("Open 'Add custom token' screen") { openAddCustomToken() }
|
|
step("Add custom token with custom derivation on '$ethereumNetwork'") {
|
|
addCustomTokenWithCustomDerivation(
|
|
network = ethereumNetwork,
|
|
contract = ethContract,
|
|
derivationPath = customDerivationPath,
|
|
)
|
|
}
|
|
step("Assert custom derivation indicator for '$tokenTitle' is displayed on Main") {
|
|
flakySafely { onMainScreen { tokenWithCustomDerivationIcon(tokenTitle).assertIsDisplayed() } }
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("770")
|
|
@DisplayName("Add custom token: derivation field is available for a non-EVM network")
|
|
@Test
|
|
fun derivationAvailableForNonEvmNetworkTest() {
|
|
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("Click on network: '$solanaNetwork'") {
|
|
flakySafely { onAddCustomTokenScreen { scrollToNetwork(solanaNetwork) } }
|
|
onAddCustomTokenScreen { networkRow(solanaNetwork).performClick() }
|
|
}
|
|
step("Assert 'Derivation path' field is available") {
|
|
flakySafely { onAddCustomTokenScreen { derivationSelectorField.assertExists() } }
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("769")
|
|
@DisplayName("Add custom token: Solana token on a modern card shows no unsupported warning")
|
|
@Test
|
|
fun solanaTokenModernCardNoWarningTest() {
|
|
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("Click on network: '$solanaNetwork'") {
|
|
flakySafely { onAddCustomTokenScreen { scrollToNetwork(solanaNetwork) } }
|
|
onAddCustomTokenScreen { networkRow(solanaNetwork).performClick() }
|
|
}
|
|
step("Enter contract address: '$solanaContract'") {
|
|
flakySafely { onAddCustomTokenScreen { contractAddressField.assertExists() } }
|
|
onAddCustomTokenScreen { contractAddressField.performTextInputInChunks(solanaContract) }
|
|
}
|
|
step("Assert 'Add token' button is enabled") {
|
|
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) { onAddCustomTokenScreen { addTokenButton.assertIsEnabled() } }
|
|
}
|
|
step("Assert unsupported-token warning is not displayed") {
|
|
onAddCustomTokenScreen { warningNotification.assertDoesNotExist() }
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("777")
|
|
@DisplayName("Add custom token: network with a missing curve is not offered")
|
|
@Test
|
|
fun missingCurveNetworkNotOfferedTest() {
|
|
val bitcoinNetwork = "Bitcoin"
|
|
|
|
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(mockContent = Wallet2NoEd25519Slip0010MockContent) }
|
|
step("Open 'Add custom token' screen") { openAddCustomToken() }
|
|
step("Assert supported network '$bitcoinNetwork' is displayed") {
|
|
flakySafely { onAddCustomTokenScreen { scrollToNetwork(bitcoinNetwork) } }
|
|
}
|
|
step("Assert '$solanaNetwork' network is not displayed for the missing-curve card") {
|
|
onAddCustomTokenScreen { selectorList.assertIsDisplayed() }
|
|
val solanaOffered = runCatching { onAddCustomTokenScreen { scrollToNetwork(solanaNetwork) } }.isSuccess
|
|
assertFalse("'$solanaNetwork' should not be offered for a missing-curve card", solanaOffered)
|
|
}
|
|
}
|
|
}
|
|
|
|
@AllureId("776")
|
|
@DisplayName("Add custom token: derivation paths match a legacy-batch V1 Wallet card")
|
|
@Test
|
|
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("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",
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@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",
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@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",
|
|
ethereumClassicNetworkId to "m/44'/61'/0'/0/0",
|
|
)
|
|
}
|
|
}
|
|
}
|
|
} |