Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-04 19:54:48 +03:00
parent d9d8e9b500
commit 61145f7cc5
5 changed files with 326 additions and 9 deletions

View file

@ -27,3 +27,10 @@ fun KNode.isDisplayedSafely(): Boolean {
}
}
fun KNode.assertVisibility(shouldBeDisplayed: Boolean) {
if (shouldBeDisplayed) {
assertIsDisplayed()
} else {
assertIsNotDisplayed()
}
}

View file

@ -1,8 +1,8 @@
package com.tangem.scenarios
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.assertVisibility
import com.tangem.screens.onSendConfirmScreen
import io.github.kakaocup.compose.node.element.KNode
import io.qameta.allure.kotlin.Allure.step
fun BaseTestCase.checkSendWarning(
@ -45,12 +45,4 @@ fun BaseTestCase.checkSendWarning(
sendButton.assertIsEnabled()
}
}
}
private fun KNode.assertVisibility(shouldBeDisplayed: Boolean) {
if (shouldBeDisplayed) {
assertIsDisplayed()
} else {
assertIsNotDisplayed()
}
}

View file

@ -2,6 +2,7 @@ package com.tangem.scenarios
import androidx.compose.ui.test.click
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.assertVisibility
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.isDisplayedSafely
import com.tangem.screens.*
@ -258,6 +259,44 @@ fun BaseTestCase.chackUnableToCoverFeeNotification(networkName: String, currency
}
}
fun BaseTestCase.checkSwapWarning(
title: String,
message: String,
isDisplayed: Boolean = true,
swapButtonIsDisabled: Boolean = isDisplayed,
) {
val assertDisplay = if (isDisplayed) "displayed" else "not displayed"
step("Assert warning title is $assertDisplay") {
onSwapTokenScreen {
warningTitle(title).assertVisibility(isDisplayed)
}
}
step("Assert warning icon is $assertDisplay") {
onSwapTokenScreen {
warningIcon(message).assertVisibility(isDisplayed)
}
}
step("Assert warning message is $assertDisplay") {
onSwapTokenScreen {
warningMessage(message).assertVisibility(isDisplayed)
}
}
if (swapButtonIsDisabled)
step("Assert 'Swap' button is disabled") {
onSwapTokenScreen {
swapButton.assertIsNotEnabled()
}
}
else
step("Assert 'Swap' button is enabled") {
onSwapTokenScreen {
swapButton.assertIsEnabled()
}
}
}
sealed class SwapEntryPoint {
object MainScreen : SwapEntryPoint()
object TokenDetails : SwapEntryPoint()

View file

@ -113,6 +113,24 @@ class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
useUnmergedTree = true
}
fun warningTitle(title: String): KNode = child {
hasTestTag(NotificationTestTags.TITLE)
hasText(title)
useUnmergedTree = true
}
fun warningMessage(message: String): KNode = child {
hasTestTag(NotificationTestTags.MESSAGE)
hasText(message)
useUnmergedTree = true
}
fun warningIcon(message: String): KNode = child {
hasTestTag(NotificationTestTags.ICON)
hasAnySibling(withText(message))
useUnmergedTree = true
}
val refreshButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.warning_button_refresh))

View file

@ -14,6 +14,7 @@ import com.tangem.datasource.api.common.config.ApiConfig
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.scenarios.SwapEntryPoint
import com.tangem.scenarios.chackUnableToCoverFeeNotification
import com.tangem.scenarios.checkSwapWarning
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.openSwapScreen
import com.tangem.scenarios.synchronizeAddresses
@ -316,4 +317,264 @@ class SwapTokenScreenWarningsTest : BaseTestCase() {
}
}
}
@AllureId("2831")
@DisplayName("Swap: warning is not displayed, if remaining balance is equal to 0")
@Test
fun solanaRemainingBalanceEqualToZeroWarningTest() {
val tokenTitle = "Solana"
val inputAmount = "0.00168933"
val tokensScenarioState = "SolanaUSDC"
val rentAmount = "SOL 0.00089088"
val notificationTitle = getResourceString(R.string.send_notification_invalid_amount_title)
val notificationMessage = getResourceString(
R.string.send_notification_invalid_amount_rent_fee,
rentAmount
)
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
}
).run {
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$tokensScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = tokensScenarioState)
}
step("Set WireMock scenario: '$QUOTES_API_SCENARIO' to state: $tokensScenarioState") {
setWireMockScenarioState(scenarioName = QUOTES_API_SCENARIO, state = tokensScenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
}
step("Assert title: '$tokenTitle' is displayed") {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Open 'Swap' screen") {
openSwapScreen(from = SwapEntryPoint.TokenDetails)
}
step("Assert 'You swap' block is displayed") {
onSwapTokenScreen { youSwapBlock.assertIsDisplayed() }
}
step("Input swap amount = '$inputAmount'") {
waitForIdle()
onSwapTokenScreen {
textInput.clickWithAssertion()
textInput.performTextReplacement(inputAmount)
}
}
step("Assert 'Invalid amount' warning is not displayed") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
checkSwapWarning(
title = notificationTitle,
message = notificationMessage,
isDisplayed = false
)
}
}
}
}
@AllureId("2832")
@DisplayName("Swap: warning is not displayed, if remaining balance is equal to rent amount")
@Test
fun solanaRemainingBalanceEqualToRentAmountTest() {
val tokenTitle = "Solana"
val inputAmount = "0.001689338"
val tokensScenarioState = "SolanaUSDC"
val rentAmount = "SOL 0.00089088"
val notificationTitle = getResourceString(R.string.send_notification_invalid_amount_title)
val notificationMessage = getResourceString(
R.string.send_notification_invalid_amount_rent_fee,
rentAmount
)
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
}
).run {
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$tokensScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = tokensScenarioState)
}
step("Set WireMock scenario: '$QUOTES_API_SCENARIO' to state: $tokensScenarioState") {
setWireMockScenarioState(scenarioName = QUOTES_API_SCENARIO, state = tokensScenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
}
step("Assert title: '$tokenTitle' is displayed") {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Open 'Swap' screen") {
openSwapScreen(from = SwapEntryPoint.TokenDetails)
}
step("Assert 'You swap' block is displayed") {
onSwapTokenScreen { youSwapBlock.assertIsDisplayed() }
}
step("Input swap amount = '$inputAmount'") {
waitForIdle()
onSwapTokenScreen {
textInput.clickWithAssertion()
textInput.performTextReplacement(inputAmount)
}
}
step("Assert 'Invalid amount' warning is not displayed") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
checkSwapWarning(
title = notificationTitle,
message = notificationMessage,
isDisplayed = false
)
}
}
}
}
@AllureId("2833")
@DisplayName("Swap: warning is not displayed, if remaining balance more than rent amount")
@Test
fun solanaRemainingBalanceMoreThanRentAmountTest() {
val tokenTitle = "Solana"
val inputAmount = "0.0000941"
val tokensScenarioState = "SolanaUSDC"
val rentAmount = "SOL 0.00089088"
val notificationTitle = getResourceString(R.string.send_notification_invalid_amount_title)
val notificationMessage = getResourceString(
R.string.send_notification_invalid_amount_rent_fee,
rentAmount
)
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
}
).run {
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$tokensScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = tokensScenarioState)
}
step("Set WireMock scenario: '$QUOTES_API_SCENARIO' to state: $tokensScenarioState") {
setWireMockScenarioState(scenarioName = QUOTES_API_SCENARIO, state = tokensScenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
}
step("Assert title: '$tokenTitle' is displayed") {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Open 'Swap' screen") {
openSwapScreen(from = SwapEntryPoint.TokenDetails)
}
step("Assert 'You swap' block is displayed") {
onSwapTokenScreen { youSwapBlock.assertIsDisplayed() }
}
step("Input swap amount = '$inputAmount'") {
waitForIdle()
onSwapTokenScreen {
textInput.clickWithAssertion()
textInput.performTextReplacement(inputAmount)
}
}
step("Assert 'Invalid amount' warning is not displayed") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
checkSwapWarning(
title = notificationTitle,
message = notificationMessage,
isDisplayed = false
)
}
}
}
}
@AllureId("2830")
@DisplayName("Swap: warning is displayed, if remaining balance less than rent amount")
@Test
fun solanaRemainingBalanceLessThanRentAmountTest() {
val tokenTitle = "Solana"
val inputAmount = "0.0016941"
val tokensScenarioState = "SolanaUSDC"
val rentAmount = "SOL 0.00089088"
val notificationTitle = getResourceString(R.string.send_notification_invalid_amount_title)
val notificationMessage = getResourceString(
R.string.send_notification_invalid_amount_rent_fee,
rentAmount
)
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(QUOTES_API_SCENARIO)
}
).run {
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$tokensScenarioState'") {
setWireMockScenarioState(scenarioName = USER_TOKENS_API_SCENARIO, state = tokensScenarioState)
}
step("Set WireMock scenario: '$QUOTES_API_SCENARIO' to state: $tokensScenarioState") {
setWireMockScenarioState(scenarioName = QUOTES_API_SCENARIO, state = tokensScenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
}
step("Assert title: '$tokenTitle' is displayed") {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Open 'Swap' screen") {
openSwapScreen(from = SwapEntryPoint.TokenDetails)
}
step("Assert 'You swap' block is displayed") {
onSwapTokenScreen { youSwapBlock.assertIsDisplayed() }
}
step("Input swap amount = '$inputAmount'") {
waitForIdle()
onSwapTokenScreen {
textInput.clickWithAssertion()
textInput.performTextReplacement(inputAmount)
}
}
step("Assert 'Invalid amount' warning is displayed") {
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
checkSwapWarning(
title = notificationTitle,
message = notificationMessage
)
}
}
}
}
}