Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-30 11:36:06 +03:00
parent d76fcd143c
commit d197fae012
9 changed files with 459 additions and 11 deletions

View file

@ -0,0 +1,61 @@
package com.tangem.scenarios
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.screens.*
import com.tangem.screens.onMainScreen
import com.tangem.screens.onSendConfirmScreen
import com.tangem.screens.onSendScreen
import com.tangem.screens.onTokenDetailsScreen
import io.qameta.allure.kotlin.Allure.step
fun BaseTestCase.checkNetworkFeeBlock(currentFeeAmount: String, withFeeSelector: Boolean) {
step("Assert fee selector block is displayed") {
onSendConfirmScreen { feeSelectorBlock.assertIsDisplayed() }
}
step("Assert fee selector icon is displayed") {
onSendConfirmScreen { feeSelectorIcon.assertIsDisplayed() }
}
step("Assert fee selector title is displayed") {
onSendConfirmScreen { feeSelectorTitle.assertIsDisplayed() }
}
step("Assert fee selector tooltip icon is displayed") {
onSendConfirmScreen { feeSelectorTooltipIcon.assertIsDisplayed() }
}
step("Assert fee amount = '$currentFeeAmount'") {
onSendConfirmScreen { feeAmount.assertTextContains(currentFeeAmount) }
}
if (withFeeSelector) {
step("Assert select fee icon is displayed") {
onSendConfirmScreen { selectFeeIcon.assertIsDisplayed() }
}
}
}
fun BaseTestCase.openSendConfirmScreen(
tokenName: String,
inputAmount: String,
recipientAddress: String
) {
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Send' button") {
onTokenDetailsScreen { sendButton().performClick() }
}
step("Type '$inputAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(inputAmount)
}
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Type recipient address") {
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
}

View file

@ -9,6 +9,8 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
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 androidx.compose.ui.test.hasTestTag as withTestTag
import com.tangem.core.ui.R as CoreUiR
class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SendConfirmPageObject>(semanticsProvider = semanticsProvider) {
@ -29,6 +31,11 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
useUnmergedTree = true
}
val secondaryAmount: KNode = child {
hasTestTag(BaseAmountBlockTestTags.SECONDARY_AMOUNT)
useUnmergedTree = true
}
fun leaveDepositButton(amount: String): KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasAnyDescendant(withText(getResourceString(R.string.send_notification_leave_button, amount)))
@ -66,6 +73,18 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
useUnmergedTree = true
}
fun warningMessage(messageResId: Int): KNode = child {
hasTestTag(NotificationTestTags.MESSAGE)
hasText(getResourceString(messageResId))
useUnmergedTree = true
}
fun warningIcon(messageResId: Int): KNode = child {
hasTestTag(NotificationTestTags.ICON)
hasAnySibling(withText(getResourceString(messageResId)))
useUnmergedTree = true
}
fun recipientAddress(recipientAddress: String): KNode = child {
hasTestTag(SendConfirmScreenTestTags.RECIPIENT_ADDRESS)
hasText(recipientAddress)
@ -76,6 +95,40 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
hasTestTag(SendConfirmScreenTestTags.BLOCKCHAIN_ADDRESS)
useUnmergedTree = true
}
val feeSelectorBlock: KNode = child {
hasTestTag(FeeSelectorBlockTestTags.SELECTOR_BLOCK)
}
val feeSelectorIcon: KNode = child {
hasTestTag(FeeSelectorBlockTestTags.ICON)
useUnmergedTree = true
}
val feeSelectorTitle: KNode = child {
hasTestTag(FeeSelectorBlockTestTags.TITLE)
useUnmergedTree = true
}
val feeSelectorTooltipIcon: KNode = child {
hasTestTag(FeeSelectorBlockTestTags.TOOLTIP_ICON)
useUnmergedTree = true
}
val selectFeeIcon: KNode = child {
hasTestTag(FeeSelectorBlockTestTags.SELECT_FEE_ICON)
useUnmergedTree = true
}
val feeAmount: KNode = child {
hasParent(withTestTag(FeeSelectorBlockTestTags.FEE_AMOUNT))
useUnmergedTree = true
}
val refreshButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(CoreUiR.string.warning_button_refresh))
}
}
internal fun BaseTestCase.onSendConfirmScreen(function: SendConfirmPageObject.() -> Unit) =

View file

@ -38,6 +38,16 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
useUnmergedTree = true
}
val equivalentInputAmount: KNode = child {
hasTestTag(SendScreenTestTags.EQUIVALENT_INPUT_AMOUNT)
useUnmergedTree = true
}
val exchangeIcon: KNode = child {
hasTestTag(SendScreenTestTags.EXCHANGE_ICON)
useUnmergedTree = true
}
val tokenName: KNode = child {
hasTestTag(SendScreenTestTags.TOKEN_NAME)
useUnmergedTree = true

View file

@ -9,10 +9,7 @@ import com.tangem.common.constants.TestConstants.ETHEREUM_RECIPIENT_ADDRESS
import com.tangem.common.constants.TestConstants.ETHEREUM_RECIPIENT_SHORTENED_ADDRESS
import com.tangem.common.constants.TestConstants.XRP_RECIPIENT_ADDRESS
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.utils.clearClipboard
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setClipboardText
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.common.utils.*
import com.tangem.core.ui.R
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses

View file

@ -0,0 +1,299 @@
package com.tangem.tests.send.confirmScreen
import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.ETHEREUM_RECIPIENT_ADDRESS
import com.tangem.common.constants.TestConstants.POLKADOT_RECIPIENT_ADDRESS
import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
import com.tangem.common.extensions.*
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.*
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 SendConfirmScreenTest : BaseTestCase() {
@AllureId("4003")
@DisplayName("Send (Confirm screen): change sending amount")
@Test
fun changeSendingAmountTest() {
val tokenName = "Ethereum"
val inputAmount = "1"
val newInputAmount = "0.9"
val ethereumAmount = "1.00"
val fiatAmount = "$2,535.63"
val newFiatAmount = "$2,282.07"
val newEthereumAmount = "0.90"
val recipientAddress = ETHEREUM_RECIPIENT_ADDRESS
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Send' button") {
onTokenDetailsScreen { sendButton().performClick() }
}
step("Type '$inputAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(inputAmount)
}
}
step("Assert fiat amount = '$fiatAmount'") {
onSendScreen { equivalentInputAmount.assertTextContains(fiatAmount) }
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Type recipient address") {
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
step("Assert token amount = '$ethereumAmount'") {
onSendConfirmScreen { primaryAmount.assertTextContains(ethereumAmount) }
}
step("Assert fiat amount = '$fiatAmount'") {
onSendConfirmScreen { secondaryAmount.assertTextContains(fiatAmount) }
}
step("Click on token amount") {
onSendConfirmScreen { primaryAmount.performClick() }
}
step("Clear input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextClearance()
}
}
step("Type '$newInputAmount' in input text field") {
onSendScreen {
amountInputTextField.performTextReplacement(newInputAmount)
}
}
step("Assert fiat amount = '$newFiatAmount'") {
onSendScreen { equivalentInputAmount.assertTextContains(newFiatAmount) }
}
step("Click on 'Continue' button") {
onSendScreen { continueButton.clickWithAssertion() }
}
step("Assert token amount = '$newEthereumAmount'") {
onSendConfirmScreen { primaryAmount.assertTextContains(newEthereumAmount) }
}
step("Assert fiat amount = '$newFiatAmount'") {
onSendConfirmScreen { secondaryAmount.assertTextContains(newFiatAmount) }
}
}
}
@AllureId("552")
@DisplayName("Send (Confirm screen): switch to equivalent")
@Test
fun switchToEquivalentTest() {
val tokenName = "Ethereum"
val inputAmount = "1"
val tokenAmount = "1.00"
val ethereumAmount = "ETH 1.00"
val fiatAmount = "$2,535.63"
val recipientAddress = ETHEREUM_RECIPIENT_ADDRESS
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Send' button") {
onTokenDetailsScreen { sendButton().performClick() }
}
step("Type '$inputAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(inputAmount)
}
}
step("Assert fiat amount = '$fiatAmount'") {
onSendScreen { equivalentInputAmount.assertTextContains(fiatAmount) }
}
step("Click on exchange icon") {
onSendScreen { exchangeIcon.performClick() }
}
step("Assert token amount = '$ethereumAmount'") {
onSendScreen { equivalentInputAmount.assertTextContains(ethereumAmount) }
}
step("Click on exchange icon") {
onSendScreen { exchangeIcon.performClick() }
}
step("Assert fiat amount = '$fiatAmount'") {
onSendScreen { equivalentInputAmount.assertTextContains(fiatAmount) }
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Type recipient address") {
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
step("Assert primary amount = '$tokenAmount'") {
onSendConfirmScreen { primaryAmount.assertTextContains(tokenAmount) }
}
step("Assert secondary amount = '$fiatAmount'") {
onSendConfirmScreen { secondaryAmount.assertTextContains(fiatAmount) }
}
}
}
@AllureId("553")
@DisplayName("Send (Confirm screen): check fee for blockchain with unknown fee")
@Test
fun checkFeeForBlockchainWithUnknownFeeTest() {
val tokenName = "Polygon"
val inputAmount = "1"
val recipientAddress = ETHEREUM_RECIPIENT_ADDRESS
val currentFeeAmount = "<$0.01"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Swipe up to token") {
swipeVertical(SwipeDirection.UP)
}
step("Open 'Send Confirm' screen for token '$tokenName'") {
openSendConfirmScreen(
tokenName = tokenName,
inputAmount = inputAmount,
recipientAddress = recipientAddress
)
}
step("Check network fee block") {
checkNetworkFeeBlock(currentFeeAmount = currentFeeAmount, withFeeSelector = true)
}
}
}
@AllureId("4565")
@DisplayName("Send (Confirm screen): check fee for token with unknown fee")
@Test
fun checkFeeForTokenWithUnknownFeeTest() {
val tokenName = "POL (ex-MATIC)"
val inputAmount = "1"
val recipientAddress = ETHEREUM_RECIPIENT_ADDRESS
val currentFeeAmount = "<$0.01"
val scenarioName = "eth_estimate_gas"
val scenarioState = "UnknownFee"
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()
}
step("Swipe up to token") {
swipeVertical(SwipeDirection.UP)
}
step("Open 'Send Confirm' screen for token '$tokenName'") {
openSendConfirmScreen(
tokenName = tokenName,
inputAmount = inputAmount,
recipientAddress = recipientAddress
)
}
step("Check network fee block") {
checkNetworkFeeBlock(currentFeeAmount = currentFeeAmount, withFeeSelector = true)
}
}
}
@AllureId("554")
@DisplayName("Send (Confirm screen): check fee warning")
@Test
fun checkFeeWarningTest() {
val tokenName = "Polkadot"
val tokenAmount = "0.1"
val warningTitleResId = R.string.send_fee_unreachable_error_title
val warningMessageResId = R.string.send_fee_unreachable_error_text
val currentFeeAmount = "$0.05"
setupHooks(
additionalAfterSection = {
enableWiFi()
enableMobileData()
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
}
).run {
step("Open 'Send Screen' with token: $tokenName") {
openSendScreen(tokenName)
}
step("Type '$tokenAmount' in input text field") {
onSendScreen {
amountInputTextField.performClick()
amountInputTextField.performTextReplacement(tokenAmount)
}
}
step("Click on 'Next' button") {
onSendScreen { nextButton.clickWithAssertion() }
}
step("Type address in input text field") {
onSendAddressScreen { addressTextField.performTextReplacement(POLKADOT_RECIPIENT_ADDRESS) }
}
step("Turn off internet") {
disableWiFi()
disableMobileData()
}
step("Click on 'Next' button") {
onSendAddressScreen { nextButton.clickWithAssertion() }
}
step("Turn on internet") {
enableWiFi()
enableMobileData()
}
step("Assert 'Network fee info unreachable' warning title is displayed") {
onSendConfirmScreen { warningTitle(warningTitleResId).assertIsDisplayed() }
}
step("Assert 'Check your internet connection' warning message is displayed") {
onSendConfirmScreen { warningMessage(warningMessageResId).assertIsDisplayed() }
}
step("Assert warning icon is displayed") {
onSendConfirmScreen { warningIcon(warningTitleResId).assertIsDisplayed() }
}
step("Click on 'Refresh' button") {
waitForIdle()
onSendConfirmScreen { refreshButton.clickWithAssertion() }
}
step("Check network fee block") {
checkNetworkFeeBlock(currentFeeAmount = currentFeeAmount, withFeeSelector = false)
}
}
}
}