Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-01 13:38:47 +03:00
parent 5b1663edc7
commit 86f12022ef
7 changed files with 347 additions and 1 deletions

View file

@ -4,6 +4,7 @@ object TestConstants {
const val TOTAL_BALANCE = "$3,299.18"
const val RECIPIENT_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"
const val CARDANO_ADDRESS = "addr1q8f9499e58k4hhfd9vhawprxt3xd94x7rmlyp33ee4xkatakcl2zgkrg0p6ceqkndtkw4cumfe9enhdph8yhuswn785srksm9p"
const val WAIT_UNTIL_TIMEOUT = 20_000L

View file

@ -25,7 +25,7 @@ fun BaseTestCase.pullToRefresh() {
direction = SwipeDirection.DOWN,
startHeightRatio = 0.2f,
endHeightRatio = 0.8f,
steps = 2000
steps = 1000
)
}

View file

@ -4,11 +4,14 @@ import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.R
import com.tangem.core.ui.test.BaseButtonTestTags
import com.tangem.core.ui.test.NotificationTestTags
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
import io.github.kakaocup.compose.node.element.KNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
import androidx.compose.ui.test.hasText as withText
import com.tangem.common.ui.R as CommonUiR
class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SendConfirmPageObject>(semanticsProvider = semanticsProvider) {
@ -24,6 +27,41 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
useUnmergedTree = true
}
val minimumSendAmountErrorTitle: KNode = child {
hasTestTag(NotificationTestTags.TITLE)
hasText(getResourceString(CommonUiR.string.send_notification_invalid_amount_title))
useUnmergedTree = true
}
fun minimumSendAmountErrorIcon(amount: String): KNode = child {
hasAnySibling(
withText(
getResourceString(
CommonUiR.string.send_notification_invalid_minimum_amount_text,
amount,
amount,
)
)
)
hasTestTag(NotificationTestTags.ICON)
useUnmergedTree = true
}
fun minimumSendAmountErrorMessage(
amount: String,
): KNode = child {
hasTestTag(NotificationTestTags.MESSAGE)
hasText(
getResourceString(
CommonUiR.string.send_notification_invalid_minimum_amount_text,
amount,
amount,
)
)
useUnmergedTree = true
}
}
internal fun BaseTestCase.onSendConfirmScreen(function: SendConfirmPageObject.() -> Unit) =

View file

@ -132,6 +132,18 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
useUnmergedTree = true
}
val topUpYourWalletNotificationTitle: KNode = child {
hasTestTag(NotificationTestTags.TITLE)
hasText(getResourceString(R.string.warning_no_account_title))
useUnmergedTree = true
}
val topUpYourWalletNotificationIcon: KNode = child {
hasAnySibling(withText(getResourceString(R.string.warning_no_account_title)))
hasTestTag(NotificationTestTags.ICON)
useUnmergedTree = true
}
fun networkFeeNotificationMessage(
currencyName: String,
networkName: String,
@ -152,6 +164,23 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
useUnmergedTree = true
}
fun topUpYourWalletNotificationMessage(
networkName: String,
amount: String,
currencySymbol: String,
): KNode = child {
hasTestTag(NotificationTestTags.MESSAGE)
hasText(
getResourceString(
R.string.no_account_generic,
networkName,
amount,
currencySymbol,
)
)
useUnmergedTree = true
}
fun goToBuyCurrencyButton(feeCurrencySymbol: String): KNode = child {
hasTestTag(BaseButtonTestTags.TEXT)
hasText(getResourceString(R.string.common_buy_currency, feeCurrencySymbol))

View file

@ -0,0 +1,209 @@
package com.tangem.tests
import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.CARDANO_ADDRESS
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.pullToRefresh
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.screens.*
import com.tangem.screens.onMainScreen
import com.tangem.screens.onSendAddressScreen
import com.tangem.screens.onSendScreen
import com.tangem.screens.onTokenDetailsScreen
import dagger.hilt.android.testing.HiltAndroidTest
import io.qameta.allure.kotlin.AllureId
import io.qameta.allure.kotlin.junit4.DisplayName
import org.junit.Test
@HiltAndroidTest
class BlockchainTest : BaseTestCase() {
@AllureId("3644")
@DisplayName("ADA: Checking the min amount/change = 1ADA")
@Test
fun adaCheckMinAmountTest() {
val tokenName = "Cardano"
val balance = "$0.00"
val errorSendAmount = "0.1"
val validSendAmount = "10"
val minAmount = "ADA 1.00"
val address = CARDANO_ADDRESS
val scenarioName = "user_tokens_api"
val scenarioState = "Cardano"
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(scenarioName)
}
).run {
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses(balance)
}
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Send' button") {
onTokenDetailsScreen { sendButton.performClick() }
}
step("Type '$errorSendAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(errorSendAmount)
}
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Type address in input text field") {
onSendAddressScreen { addressTextField.performTextReplacement(address) }
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
step("Assert 'Invalid amount' error title is displayed") {
onSendConfirmScreen { minimumSendAmountErrorTitle.assertIsDisplayed() }
}
step("Assert 'Invalid amount' error icon is displayed") {
onSendConfirmScreen { minimumSendAmountErrorIcon(minAmount).assertIsDisplayed() }
}
step("Assert 'Invalid amount' error message is displayed") {
onSendConfirmScreen { minimumSendAmountErrorMessage(minAmount).assertIsDisplayed() }
}
step("Press system 'Back' button") {
device.uiDevice.pressBack()
}
step("Assert address text field is displayed") {
onSendAddressScreen { addressTextField.assertIsDisplayed() }
}
step("Press system 'Back' button") {
device.uiDevice.pressBack()
}
step("Type '$validSendAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(errorSendAmount)
}
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Assert address text field is displayed") {
onSendAddressScreen { addressTextField.assertIsDisplayed() }
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
step("Assert 'Invalid amount' error title is not displayed") {
onSendConfirmScreen { minimumSendAmountErrorTitle.assertIsNotDisplayed() }
}
step("Assert 'Invalid amount' error icon is not displayed") {
onSendConfirmScreen { minimumSendAmountErrorIcon(minAmount).assertIsNotDisplayed() }
}
step("Assert 'Invalid amount' error message is not displayed") {
onSendConfirmScreen { minimumSendAmountErrorMessage(minAmount).assertIsNotDisplayed() }
}
}
}
@AllureId("990")
@DisplayName("XRP: Check warning")
@Test
fun xrpCheckWarningTest() {
val tokenName = "XRP Ledger"
val amount = "1.00"
val currencySymbol = "XRP"
val balance = "$0.00"
val userTokensScenarioName = "user_tokens_api"
val userTokensScenarioState = "XRP"
val ripplePostServerStateScenarioName = "ripple_post_server_state_android"
val ripplePostServerStateScenarioState = "Started"
val rippleAccountInfoScenarioName = "ripple_account_info_android"
val rippleAccountInfoStartedState = "Started"
val rippleAccountInfoErrorState = "AccountNotFound"
val rippleAccountLinesScenarioName = "ripple_account_lines_android"
val rippleAccountLinesStartedState = "Started"
val rippleAccountLinesErrorState = "AccountNotFound"
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(userTokensScenarioName)
resetWireMockScenarioState(ripplePostServerStateScenarioName)
resetWireMockScenarioState(rippleAccountInfoScenarioName)
resetWireMockScenarioState(rippleAccountLinesScenarioName)
}
).run {
step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") {
setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState)
}
step("Set WireMock scenario: '$rippleAccountInfoScenarioName' to state: '$rippleAccountInfoErrorState'") {
setWireMockScenarioState(scenarioName = rippleAccountInfoScenarioName, state = rippleAccountInfoErrorState)
}
step("Set WireMock scenario: '$rippleAccountLinesScenarioName' to state: '$rippleAccountLinesErrorState'") {
setWireMockScenarioState(scenarioName = rippleAccountLinesScenarioName, state = rippleAccountLinesErrorState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses(balance)
}
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() }
}
step("Assert 'Top up wallet' notification title is displayed") {
onTokenDetailsScreen { topUpYourWalletNotificationTitle.assertIsDisplayed() }
}
step("Assert 'Top up wallet' notification message is displayed") {
onTokenDetailsScreen {
topUpYourWalletNotificationMessage(
networkName = tokenName,
amount = amount,
currencySymbol = currencySymbol,
).assertIsDisplayed()
}
}
step("Assert 'Top up wallet' notification icon is displayed") {
onTokenDetailsScreen { topUpYourWalletNotificationIcon.assertIsDisplayed() }
}
step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") {
setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState)
}
step("Set WireMock scenario: '$ripplePostServerStateScenarioName' to state: '$ripplePostServerStateScenarioState'") {
setWireMockScenarioState(scenarioName = ripplePostServerStateScenarioName, state = ripplePostServerStateScenarioState)
}
step("Set WireMock scenario: '$rippleAccountInfoScenarioName' to state: '$rippleAccountInfoStartedState'") {
setWireMockScenarioState(scenarioName = rippleAccountInfoScenarioName, state = rippleAccountInfoStartedState)
}
step("Set WireMock scenario: '$rippleAccountLinesScenarioName' to state: '$rippleAccountLinesStartedState'") {
setWireMockScenarioState(scenarioName = rippleAccountLinesScenarioName, state = rippleAccountLinesStartedState)
}
step("Pull to refresh") {
pullToRefresh()
}
step("Assert 'Top up wallet' notification title is not displayed") {
onTokenDetailsScreen { topUpYourWalletNotificationTitle.assertIsNotDisplayed() }
}
step("Assert 'Top up wallet' notification message not is displayed") {
onTokenDetailsScreen {
topUpYourWalletNotificationMessage(
networkName = tokenName,
amount = amount,
currencySymbol = currencySymbol,
).assertIsNotDisplayed()
}
}
step("Assert 'Top up wallet' notification icon not is displayed") {
onTokenDetailsScreen { topUpYourWalletNotificationIcon.assertIsNotDisplayed() }
}
}
}
}