From 7595aeb6faac38644536e704cdb4a7fa9514795d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 7 Nov 2025 10:55:58 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/common/constants/TestConstants.kt | 3 + .../com/tangem/scenarios/SendScenarios.kt | 18 ++ .../tangem/screens/SendAddressPageObject.kt | 14 +- .../addressScreen/SendAddressScreenTest.kt | 265 +++++++++++++++--- 4 files changed, 253 insertions(+), 47 deletions(-) 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 cfefe6cebc..f1dd77d01f 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/constants/TestConstants.kt @@ -12,7 +12,10 @@ object TestConstants { "addr1q8f9499e58k4hhfd9vhawprxt3xd94x7rmlyp33ee4xkatakcl2zgkrg0p6ceqkndtkw4cumfe9enhdph8yhuswn785srksm9p" const val SOLANA_RECIPIENT_ADDRESS = "5fcy9woa8Di1QHcce65CsV3XKrxdB2pD4HJx5xx82ipM" const val POLKADOT_RECIPIENT_ADDRESS = "143TfgFYAFfM86LRzt4UcFNU3KosxCndBCVz2U5HCxpLidKZ" + const val XRP_X_ADDRESS = "XVVzUQZFrRo3MUW3HT1WUaAfE5iNr7USr9ER3DvsKmguJRa" const val XRP_RECIPIENT_ADDRESS = "rNeY28BPda6jp5N5oESZzd2ZN7eMZy8jNf" + const val XRP_X_RECIPIENT_ADDRESS = "XVNpatGaPNpPbiAJsQz6ZczZFt97QBbFimbtGZnxBMC7ug9" + const val XRP_X_RECIPIENT_ADDRESS_WITH_TAG = "XVNpatGaPNpPbiAJsQz6ZczZFt97QB6jeQWyCM3uCaDHVix" const val ENS_NAME = "louded.eth" const val ENS_ETHEREUM_RECIPIENT_ADDRESS = "0x0211ff638298adcbdc99c177dc2e95ec69948865" const val ENS_ETHEREUM_RECIPIENT_SHORTENED_ADDRESS = "0x0211ff63829..." diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt index e2c3756dba..829c4456be 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt @@ -85,4 +85,22 @@ fun BaseTestCase.checkScanQrScreen() { step("Assert 'Paste from clipboard' is displayed") { onScanQrScreen { pasteFromClipboardButton.assertIsDisplayed() } } +} + +fun BaseTestCase.checkDestinationTagBlock(hint: String) { + step("Assert 'Destination Tag' title is displayed") { + onSendAddressScreen { destinationTagBlockTitle().assertIsDisplayed() } + } + step("Assert 'Destination Tag' text is displayed") { + onSendAddressScreen { destinationTagBlockText.assertIsDisplayed() } + } + step("Assert 'Destination Tag' text field hint contains text '$hint'") { + onSendAddressScreen { destinationTagTextFieldHint.assertTextContains(hint) } + } + step("Assert 'Destination Tag' text field is displayed") { + onSendAddressScreen { destinationTagTextField.assertIsDisplayed() } + } + step("Assert 'Destination Tag' caution is displayed") { + onSendAddressScreen { destinationTagBlockCaution.assertIsDisplayed() } + } } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt index 32dc483d80..dc334145ac 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt @@ -70,6 +70,11 @@ class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider useUnmergedTree = true } + val destinationTagTextFieldHint: KNode = child { + hasParent(withTestTag(SendAddressScreenTestTags.DESTINATION_TAG_TEXT_FIELD)) + useUnmergedTree = true + } + val destinationTagBlockText: KNode = child { hasText( getResourceString(CoreUiR.string.send_recipient_memo_footer_v2) + "\n" + @@ -79,7 +84,14 @@ class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider } val destinationTagBlockCaution: KNode = child { - hasText(getResourceString(CoreUiR.string.send_recipient_memo_footer_v2_highlighted)) + hasText( + getResourceString( + CoreUiR.string.send_recipient_memo_footer_v2, + CoreUiR.string.send_recipient_memo_footer_v2_highlighted + ), + substring = true + ) + useUnmergedTree = true } val destinationTagPasteButton: KNode = child { diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt index 924598a36f..9b0a46ded9 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt @@ -1,6 +1,7 @@ package com.tangem.tests.send.addressScreen import android.Manifest +import androidx.compose.ui.test.hasText import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.ENS_ETHEREUM_RECIPIENT_ADDRESS import com.tangem.common.constants.TestConstants.ENS_ETHEREUM_RECIPIENT_SHORTENED_ADDRESS @@ -9,16 +10,16 @@ import com.tangem.common.constants.TestConstants.ETHEREUM_ADDRESS 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.constants.TestConstants.XRP_X_ADDRESS +import com.tangem.common.constants.TestConstants.XRP_X_RECIPIENT_ADDRESS +import com.tangem.common.constants.TestConstants.XRP_X_RECIPIENT_ADDRESS_WITH_TAG 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.core.ui.R -import com.tangem.scenarios.checkScanQrScreen -import com.tangem.scenarios.openMainScreen -import com.tangem.scenarios.openSendAddressScreen -import com.tangem.scenarios.synchronizeAddresses +import com.tangem.scenarios.* import com.tangem.screens.* import com.tangem.wallet.BuildConfig import dagger.hilt.android.testing.HiltAndroidTest @@ -46,20 +47,8 @@ class SendAddressScreenTest : BaseTestCase() { 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 '$sendAmount' in input text field") { - onSendScreen { - amountInputTextField.performClick() - amountInputTextField.performTextReplacement(sendAmount) - } - } - step("Click on 'Next' button") { - onSendScreen { nextButton.clickWithAssertion() } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) } step("Click on previous address") { onSendAddressScreen { recentAddressWithText(recipientShortenedAddress).clickWithAssertion() } @@ -121,20 +110,8 @@ class SendAddressScreenTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses() } - step("Click on token with name: '$tokenName'") { - onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() } - } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } - } - step("Type '$sendAmount' in input text field") { - onSendScreen { - amountInputTextField.performClick() - amountInputTextField.performTextReplacement(sendAmount) - } - } - step("Click on 'Next' button") { - onSendScreen { nextButton.clickWithAssertion() } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) } step("Set clipboard text") { setClipboardText(context, correctMemo) @@ -197,20 +174,8 @@ class SendAddressScreenTest : BaseTestCase() { 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 '$sendAmount' in input text field") { - onSendScreen { - amountInputTextField.performClick() - amountInputTextField.performTextReplacement(sendAmount) - } - } - step("Click on 'Next' button") { - onSendScreen { nextButton.clickWithAssertion() } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) } step("Set clipboard text") { setClipboardText(context, recipientAddress) @@ -460,4 +425,212 @@ class SendAddressScreenTest : BaseTestCase() { } } } + + @AllureId("4590") + @DisplayName("Send (address screen): enter 'r' address (XRP)") + @Test + fun xrpEnterRAddressTest() { + val tokenName = "XRP Ledger" + val sendAmount = "1" + val xrpRecipientAddress = XRP_RECIPIENT_ADDRESS + val userTokensScenarioName = "user_tokens_api" + val userTokensScenarioState = "XRP" + val optionalText = getResourceString(R.string.send_optional_field) + + setupHooks( + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenarioName) + } + ).run { + step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") { + setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState) + } + step("Open 'Main Screen'") { + openMainScreen() + } + step("Synchronize addresses") { + synchronizeAddresses() + } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) + } + step("Type address in input text field") { + onSendAddressScreen { addressTextField.performTextReplacement(xrpRecipientAddress) } + } + step("Check 'Destination tag' block") { + checkDestinationTagBlock(hint = optionalText) + } + } + } + + @AllureId("4591") + @DisplayName("Send (address screen): enter 'X' address without tag (XRP)") + @Test + fun xrpEnterXAddressWithoutTagTest() { + val tokenName = "XRP Ledger" + val sendAmount = "1" + val xrpRecipientAddress = XRP_X_RECIPIENT_ADDRESS + val userTokensScenarioName = "user_tokens_api" + val userTokensScenarioState = "XRP" + val tagAlreadyIncluded = getResourceString(R.string.send_additional_field_already_included) + + setupHooks( + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenarioName) + } + ).run { + step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") { + setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState) + } + step("Open 'Main Screen'") { + openMainScreen() + } + step("Synchronize addresses") { + synchronizeAddresses() + } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) + } + step("Type address in input text field") { + onSendAddressScreen { addressTextField.performTextReplacement(xrpRecipientAddress) } + } + step("Check 'Destination tag' block") { + checkDestinationTagBlock(hint = tagAlreadyIncluded) + } + step("Assert 'Next' button is enabled") { + onSendAddressScreen { nextButton.assertIsEnabled() } + } + } + } + + @AllureId("4592") + @DisplayName("Send (address screen): enter 'X' address with tag (XRP)") + @Test + fun xrpEnterXAddressWithTagTest() { + val tokenName = "XRP Ledger" + val sendAmount = "1" + val xrpRecipientAddress = XRP_X_RECIPIENT_ADDRESS_WITH_TAG + val userTokensScenarioName = "user_tokens_api" + val userTokensScenarioState = "XRP" + val tagAlreadyIncluded = getResourceString(R.string.send_additional_field_already_included) + + setupHooks( + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenarioName) + } + ).run { + step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") { + setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState) + } + step("Open 'Main Screen'") { + openMainScreen() + } + step("Synchronize addresses") { + synchronizeAddresses() + } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) + } + step("Type address in input text field") { + onSendAddressScreen { addressTextField.performTextReplacement(xrpRecipientAddress) } + } + step("Check 'Destination tag' block") { + checkDestinationTagBlock(hint = tagAlreadyIncluded) + } + step("Assert 'Next' button is enabled") { + onSendAddressScreen { nextButton.assertIsEnabled() } + } + } + } + + @AllureId("4594") + @DisplayName("Send (address screen): enter own address (XRP)") + @Test + fun xrpEnterOwnXAddressTest() { + val tokenName = "XRP Ledger" + val sendAmount = "1" + val walletAddress = XRP_X_ADDRESS + val userTokensScenarioName = "user_tokens_api" + val userTokensScenarioState = "XRP" + val sameAsWalletAddress = getResourceString(R.string.send_error_address_same_as_wallet) + + setupHooks( + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenarioName) + } + ).run { + step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") { + setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState) + } + step("Open 'Main Screen'") { + openMainScreen() + } + step("Synchronize addresses") { + synchronizeAddresses() + } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) + } + step("Type address in input text field") { + onSendAddressScreen { addressTextField.performTextReplacement(walletAddress) } + } + step("Assert 'Address is the same as wallet address' error title is displayed") { + onSendAddressScreen { addressTextFieldTitle.assertTextContains(sameAsWalletAddress) } + } + step("Assert 'Next' button is disabled") { + onSendAddressScreen { nextButton.assertIsNotEnabled() } + } + } + } + + @AllureId("4593") + @DisplayName("Send (address screen): enter tag before address (XRP)") + @Test + fun xrpEnterTagBeforeAddressTest() { + val tokenName = "XRP Ledger" + val sendAmount = "1" + val xrpRecipientAddress = XRP_X_RECIPIENT_ADDRESS + val destinationTag = "12345" + val emptyText = "" + val userTokensScenarioName = "user_tokens_api" + val userTokensScenarioState = "XRP" + val tagAlreadyIncluded = getResourceString(R.string.send_additional_field_already_included) + + setupHooks( + additionalAfterSection = { + resetWireMockScenarioState(userTokensScenarioName) + } + ).run { + step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") { + setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState) + } + step("Open 'Main Screen'") { + openMainScreen() + } + step("Synchronize addresses") { + synchronizeAddresses() + } + step("Open 'Send Address' screen") { + openSendAddressScreen(tokenName, sendAmount) + } + step("Type destination tag in input text field") { + onSendAddressScreen { destinationTagTextField.performTextReplacement(destinationTag) } + } + step("Type X address in input text field") { + onSendAddressScreen { addressTextField.performTextReplacement(xrpRecipientAddress) } + } + step("Destination tag text field doesn't contains destination tag: '$destinationTag'") { + onSendAddressScreen { destinationTagTextField.assert (!hasText(destinationTag)) } + } + step("Destination tag text field cleared") { + onSendAddressScreen { destinationTagTextField.assertTextEquals(emptyText) } + } + step("Check 'Destination tag' block") { + checkDestinationTagBlock(hint = tagAlreadyIncluded) + } + step("Assert 'Next' button is enabled") { + onSendAddressScreen { nextButton.assertIsEnabled() } + } + } + } } \ No newline at end of file