Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-15 21:39:46 +02:00
parent 4d0cb6a243
commit 2653d35a8b
5 changed files with 190 additions and 2 deletions

View file

@ -206,6 +206,19 @@ fun BaseTestCase.openSendConfirmScreenViaNextButton() {
} }
} }
fun BaseTestCase.openSendConfirmScreenViaContinueButton() {
step("Click on 'Continue' button") {
onSendAddressScreen {
addressesShimmer.assertIsNotDisplayed()
continueButton.assertIsDisplayed()
continueButton.performClick()
}
}
step("Assert 'Send' button on 'Send confirm' screen is displayed") {
onSendConfirmScreen { sendButton.assertIsDisplayed() }
}
}
fun BaseTestCase.openSendSuccessScreenViaLongClickOnSendButton() { fun BaseTestCase.openSendSuccessScreenViaLongClickOnSendButton() {
step("Long click on 'Send' button") { step("Long click on 'Send' button") {
onSendConfirmScreen { onSendConfirmScreen {

View file

@ -108,6 +108,16 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
useUnmergedTree = true useUnmergedTree = true
} }
val recipientBlock: KNode = child {
hasTestTag(SendConfirmScreenTestTags.RECIPIENT_BLOCK)
useUnmergedTree = true
}
val recipientMemo: KNode = child {
hasTestTag(SendConfirmScreenTestTags.RECIPIENT_MEMO)
useUnmergedTree = true
}
val provider: KNode = child { val provider: KNode = child {
hasText(getResourceString(R.string.express_provider)) hasText(getResourceString(R.string.express_provider))
useUnmergedTree = true useUnmergedTree = true

View file

@ -8,6 +8,7 @@ import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO
import com.tangem.common.constants.TestConstants.SOLANA_RECIPIENT_ADDRESS import com.tangem.common.constants.TestConstants.SOLANA_RECIPIENT_ADDRESS
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
import com.tangem.common.constants.TestConstants.SVS_SEED_PHRASE_12 import com.tangem.common.constants.TestConstants.SVS_SEED_PHRASE_12
import com.tangem.common.constants.TestConstants.XRP_ACTIVATED_RECIPIENT_ADDRESS
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
import com.tangem.common.extensions.extractText import com.tangem.common.extensions.extractText
import com.tangem.common.extensions.clickWithAssertion import com.tangem.common.extensions.clickWithAssertion
@ -665,4 +666,163 @@ class SendViaSwapTest : BaseTestCase() {
} }
} }
} }
@AllureId("9924")
@DisplayName("Send via Swap: editing the memo persists the latest value")
@Test
fun sendViaSwapMemoEditPersistsLatestValueTest() {
val tokenName = "Bitcoin"
val swapTokenName = "XRP"
val networkName = "XRP Ledger"
val inputAmount = "0.001"
val recipientAddress = XRP_ACTIVATED_RECIPIENT_ADDRESS
val memoFirst = "11111111"
val memoSecond = "22222222"
val hotWalletScenarioState = "HotWalletSvS"
val quotesScenarioState = "Ripple"
val bitcoinBalanceScenarioName = "bitcoin_utxo"
val bitcoinBalanceScenarioState = "BalanceHotWalletSvS"
val assetsScenarioName = "express_api_assets"
val assetsScenarioState = "BitcoinExchangeEnabledWithXRP"
val coinsScenarioName = "coins_api"
val coinsScenarioState = "WithXRP"
val providersScenarioName = "networks_providers"
val providersScenarioState = "HotWalletSvS"
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
resetWireMockScenarioState(bitcoinBalanceScenarioName)
resetWireMockScenarioState(assetsScenarioName)
resetWireMockScenarioState(coinsScenarioName)
resetWireMockScenarioState(providersScenarioName)
}
).run {
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$hotWalletScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = hotWalletScenarioState)
}
step("Set WireMock scenario: '$QUOTES_API_SCENARIO' to state: '$quotesScenarioState'") {
setWireMockScenarioState(scenarioName = QUOTES_API_SCENARIO, state = quotesScenarioState)
}
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: '$coinsScenarioName' to state: '$coinsScenarioState'") {
setWireMockScenarioState(scenarioName = coinsScenarioName, state = coinsScenarioState)
}
step("Set WireMock scenario: '$providersScenarioName' to state: '$providersScenarioState'") {
setWireMockScenarioState(scenarioName = providersScenarioName, state = providersScenarioState)
}
step("Open 'Main Screen' with existing hot wallet") {
openMainScreenWithExistingHotWallet(SVS_SEED_PHRASE_12)
}
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Transfer' button") {
onTokenDetailsScreen { transferButton.clickWithAssertion() }
}
step("Click on 'Send' button in bottom sheet") {
onTransferBottomSheet { sendButton.clickWithAssertion() }
}
step("Click on 'Swap to another token' button") {
onSendScreen { swapToAnotherTokenButton.performClick() }
}
step("Type '$swapTokenName' in search text field") {
onSendViaSwapScreen {
searchField.performClick()
searchField.performTextInput(swapTokenName)
}
}
step("Click on token: '$swapTokenName'") {
onSendViaSwapScreen { tokenItem(swapTokenName).performClick() }
}
step("Click on '$networkName' network") {
onChooseNetworkBottomSheet { networkItem(networkName).performClick() }
}
step("Type '$inputAmount' in text field") {
onSendScreen { amountInputTextField.performTextInput(inputAmount) }
}
step("Click on 'Next' button") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendScreen {
nextButton.assertIsEnabled()
nextButton.performClick()
}
}
}
step("Type recipient address") {
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
}
step("Type '$memoFirst' in 'Destination Tag' field") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendAddressScreen { destinationTagTextField.performTextReplacement(memoFirst) }
}
}
step("Assert 'Destination Tag' field value is '$memoFirst'") {
onSendAddressScreen { destinationTagTextField.assertTextContains(memoFirst) }
}
step("Open 'Send confirm' screen via 'Next' button") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
openSendConfirmScreenViaNextButton()
}
}
step("Assert recipient memo on 'Send confirm' screen contains '$memoFirst'") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendConfirmScreen { recipientMemo.assertTextContains(memoFirst, substring = true) }
}
}
// Edit-mode re-entry from Confirm uses the 'Continue' button, not 'Next'.
step("Click on recipient block to edit memo") {
onSendConfirmScreen { recipientBlock.performClick() }
}
step("Replace 'Destination Tag' field value with '$memoSecond'") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendAddressScreen { destinationTagTextField.performTextReplacement(memoSecond) }
}
}
step("Assert 'Destination Tag' field value is '$memoSecond'") {
onSendAddressScreen { destinationTagTextField.assertTextContains(memoSecond) }
}
step("Return to 'Send confirm' screen via 'Continue' button") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
openSendConfirmScreenViaContinueButton()
}
}
step("Assert recipient memo on 'Send confirm' screen contains '$memoSecond'") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendConfirmScreen { recipientMemo.assertTextContains(memoSecond, substring = true) }
}
}
step("Click on recipient block to edit memo") {
onSendConfirmScreen { recipientBlock.performClick() }
}
step("Replace 'Destination Tag' field value back with '$memoFirst'") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendAddressScreen { destinationTagTextField.performTextReplacement(memoFirst) }
}
}
step("Assert 'Destination Tag' field value is '$memoFirst'") {
onSendAddressScreen { destinationTagTextField.assertTextContains(memoFirst) }
}
step("Return to 'Send confirm' screen via 'Continue' button") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
openSendConfirmScreenViaContinueButton()
}
}
step("Assert recipient memo on 'Send confirm' screen contains '$memoFirst'") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
onSendConfirmScreen { recipientMemo.assertTextContains(memoFirst, substring = true) }
}
}
}
}
} }

View file

@ -2,7 +2,9 @@ package com.tangem.core.ui.test
object SendConfirmScreenTestTags { object SendConfirmScreenTestTags {
const val SENDING_TEXT = "SEND_CONFIRM_SCREEN_SENDING_TEXT" const val SENDING_TEXT = "SEND_CONFIRM_SCREEN_SENDING_TEXT"
const val RECIPIENT_BLOCK = "SEND_CONFIRM_SCREEN_RECIPIENT_BLOCK"
const val RECIPIENT_ADDRESS = "SEND_CONFIRM_SCREEN_RECIPIENT_ADDRESS" const val RECIPIENT_ADDRESS = "SEND_CONFIRM_SCREEN_RECIPIENT_ADDRESS"
const val RECIPIENT_MEMO = "SEND_CONFIRM_SCREEN_RECIPIENT_MEMO"
const val BLOCKCHAIN_ADDRESS = "SEND_CONFIRM_SCREEN_BLOCKCHAIN_ADDRESS" const val BLOCKCHAIN_ADDRESS = "SEND_CONFIRM_SCREEN_BLOCKCHAIN_ADDRESS"
const val RECIPIENT_ADDRESS_ICON = "SEND_CONFIRM_SCREEN_RECIPIENT_ADDRESS_ICON" const val RECIPIENT_ADDRESS_ICON = "SEND_CONFIRM_SCREEN_RECIPIENT_ADDRESS_ICON"
const val PROVIDER_NAME = "SEND_CONFIRM_SCREEN_PROVIDER_NAME" const val PROVIDER_NAME = "SEND_CONFIRM_SCREEN_PROVIDER_NAME"

View file

@ -43,7 +43,8 @@ internal fun DestinationBlock(
.clip(TangemTheme.shapes.roundedCornersXMedium) .clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action) .background(TangemTheme.colors.background.action)
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick) .clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
.padding(TangemTheme.dimens.spacing12), .padding(TangemTheme.dimens.spacing12)
.testTag(SendConfirmScreenTestTags.RECIPIENT_BLOCK),
) { ) {
AddressWithMemoBlock( AddressWithMemoBlock(
address = destinationUM.addressTextField, address = destinationUM.addressTextField,
@ -99,7 +100,9 @@ private fun AddressWithMemoBlock(
text = stringResourceSafe(R.string.send_memo, memo.value), text = stringResourceSafe(R.string.send_memo, memo.value),
style = TangemTheme.typography.caption2, style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary, color = TangemTheme.colors.text.tertiary,
modifier = Modifier.padding(top = TangemTheme.dimens.spacing8), modifier = Modifier
.padding(top = TangemTheme.dimens.spacing8)
.testTag(SendConfirmScreenTestTags.RECIPIENT_MEMO),
) )
} }
} }