Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-10 15:48:14 +03:00
parent 3e95ebf89a
commit 49cf3b9cef
8 changed files with 230 additions and 16 deletions

View file

@ -0,0 +1,32 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.R
import com.tangem.core.ui.test.TokenElementsTestTags
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
class SwapChooseTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SwapChooseTokenPageObject>(semanticsProvider = semanticsProvider) {
val title: KNode = child {
hasText(getResourceString(R.string.common_choose_token))
}
val myTokensTitle: KNode = child {
hasText(getResourceString(R.string.exchange_tokens_available_tokens_header))
}
fun tokenWithTitle(tokenTitle: String): KNode = child {
hasTestTag(TokenElementsTestTags.TOKEN_TITLE)
hasAnyDescendant(withText(tokenTitle))
useUnmergedTree = true
}
}
internal fun BaseTestCase.onSwapChooseTokenScreen(function: SwapChooseTokenPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -9,6 +9,7 @@ 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.hasTestTag as withTestTag
import androidx.compose.ui.test.hasText as withText
class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SwapTokenPageObject>(semanticsProvider = semanticsProvider) {
@ -80,11 +81,45 @@ class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
hasText(getResourceString(R.string.common_swap))
}
fun tokenSymbol(symbol: String): KNode = child {
hasTestTag(SwapTokenScreenTestTags.TOKEN_SYMBOL)
hasText(symbol)
val youSwapBlock: KNode = child {
hasTestTag(SwapTokenScreenTestTags.SWAP_BLOCK_HEADER)
hasAnyDescendant(withText(getResourceString(R.string.swapping_from_title)))
hasAnyDescendant(withTestTag(SwapTokenScreenTestTags.BALANCE))
useUnmergedTree = true
}
val youReceiveBlock: KNode = child {
hasTestTag(SwapTokenScreenTestTags.SWAP_BLOCK_HEADER)
hasAnyDescendant(withText(getResourceString(R.string.swapping_to_title)))
hasAnyDescendant(withTestTag(SwapTokenScreenTestTags.BALANCE))
useUnmergedTree = true
}
val receiveFiatAmount: KNode = child {
hasTestTag(SwapTokenScreenTestTags.RECEIVE_FIAT_AMOUNT)
}
val swapFiatAmount: KNode = child {
hasTestTag(SwapTokenScreenTestTags.SWAP_FIAT_AMOUNT)
}
val changeTokenIcon: KNode = child {
hasTestTag(SwapTokenScreenTestTags.SELECT_TOKEN_ICON)
}
fun swapTokenSymbol(symbol: String): KNode = child {
hasAnyAncestor(withTestTag(SwapTokenScreenTestTags.SWAP_CARD))
hasTestTag(SwapTokenScreenTestTags.TOKEN_SYMBOL)
hasText(symbol)
useUnmergedTree = true
}
fun receiveTokenSymbol(symbol: String): KNode = child {
hasAnyAncestor(withTestTag(SwapTokenScreenTestTags.RECEIVE_CARD))
hasTestTag(SwapTokenScreenTestTags.TOKEN_SYMBOL)
hasText(symbol)
useUnmergedTree = true
}
}
internal fun BaseTestCase.onSwapTokenScreen(function: SwapTokenPageObject.() -> Unit) =

View file

@ -208,7 +208,7 @@ class MainScreenActionButtonsTest : BaseTestCase() {
onSwapTokenScreen { title.assertIsDisplayed() }
}
step("Assert token symbol: '$tokenSymbol' is displayed") {
onSwapTokenScreen { tokenSymbol(tokenSymbol).assertIsDisplayed() }
onSwapTokenScreen { swapTokenSymbol(tokenSymbol).assertIsDisplayed() }
}
}
}

View file

@ -119,7 +119,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
onSwapTokenScreen { title.assertIsDisplayed() }
}
step("Assert token symbol: '$tokenSymbol' is displayed") {
onSwapTokenScreen { tokenSymbol(tokenSymbol).assertIsDisplayed() }
onSwapTokenScreen { swapTokenSymbol(tokenSymbol).assertIsDisplayed() }
}
}
}

View file

@ -135,7 +135,7 @@ class SwapStoriesTest : BaseTestCase() {
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Assert 'Swap' button has badge") {
step("Assert 'Swap' button has not badge") {
onMainScreen { swapButton.assertHasBadge(false) }
}
step("Open 'Swap' screen") {
@ -191,7 +191,7 @@ class SwapStoriesTest : BaseTestCase() {
step("Click on token with name: '$tokenName'") {
onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() }
}
step("Assert 'Swap' button has badge") {
step("Assert 'Swap' button has not badge") {
onTokenDetailsScreen { swapButton().assertHasBadge(false) }
}
step("Open 'Swap' screen") {
@ -216,7 +216,7 @@ class SwapStoriesTest : BaseTestCase() {
}
}
@AllureId("5471")
@AllureId("5470")
@DisplayName("Check unavailable swap stories on 'Markets' token details screen")
@Test
fun checkUnavailableSwapStoriesOnMarketsTokenDetailsScreen() {
@ -245,7 +245,7 @@ class SwapStoriesTest : BaseTestCase() {
step("Open 'Markets' token details screen for token '$tokenName'") {
openMarketTokenDetailsScreen(blockchainName = tokenName, tokenName = tokenName)
}
step("Assert 'Swap' button has badge") {
step("Assert 'Swap' button has not badge") {
waitForIdle()
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertIsDisplayed() }
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeHidden) }

View file

@ -10,7 +10,9 @@ import com.tangem.common.extensions.*
import com.tangem.common.utils.resetWireMockScenarios
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.openMainScreen
import com.tangem.scenarios.openSwapScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.screens.*
import dagger.hilt.android.testing.HiltAndroidTest
@ -218,7 +220,6 @@ class SwapTokenScreenTest : BaseTestCase() {
onSwapSelectNetworkFeeBottomSheet { title.assertIsDisplayed() }
}
step("Assert 'Market' item is displayed") {
printSemanticTree(rootIndex = 1, useUnmergedTree = true)
onSwapSelectNetworkFeeBottomSheet { marketSelectorItem.assertIsDisplayed() }
}
step("Assert 'Fast' item is displayed") {
@ -283,10 +284,138 @@ class SwapTokenScreenTest : BaseTestCase() {
}
}
step("Assert token symbol: '$swapTokenSymbol' is displayed") {
onSwapTokenScreen { tokenSymbol(swapTokenSymbol).assertIsDisplayed() }
onSwapTokenScreen { swapTokenSymbol(swapTokenSymbol).assertIsDisplayed() }
}
step("Assert token symbol: '$receiveTokenSymbol' is displayed") {
onSwapTokenScreen { tokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
onSwapTokenScreen { receiveTokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
}
}
}
@AllureId("575")
@DisplayName("Swap: check UI")
@Test
fun checkSwapUiTest() {
val swapTokenSymbol = "POL"
val receiveTokenSymbol = "ETH"
val newReceiveToken = "POL (ex-MATIC)"
val tokenTitle = "Polygon"
val inputAmount = "1"
setupHooks().run {
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 'Close' button is displayed") {
onSwapTokenScreen { closeButton.assertIsDisplayed() }
}
step("Assert swap token symbol: '$swapTokenSymbol' is displayed") {
onSwapTokenScreen { swapTokenSymbol(swapTokenSymbol).assertIsDisplayed() }
}
step("Assert receive token symbol: '$receiveTokenSymbol' is displayed") {
onSwapTokenScreen { receiveTokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
}
step("Click on 'Select token' icon") {
onSwapTokenScreen { changeTokenIcon.performClick() }
}
step("Select new receive token: $newReceiveToken") {
onSwapChooseTokenScreen { tokenWithTitle(newReceiveToken).performClick() }
}
step("Assert new receive token symbol: '$swapTokenSymbol' is displayed") {
onSwapTokenScreen { receiveTokenSymbol(swapTokenSymbol).assertIsDisplayed() }
}
step("Input swap amount = '$inputAmount'") {
waitForIdle()
onSwapTokenScreen {
textInput.clickWithAssertion()
textInput.performTextReplacement(inputAmount)
}
}
step("Assert input amount = '$inputAmount'") {
onSwapTokenScreen { textInput.assertTextEquals(inputAmount) }
}
step("Press 'Delete' button on keyboard") {
device.uiDevice.pressDelete()
waitForIdle()
}
step("Assert 'You swap' block is displayed") {
onSwapTokenScreen { youSwapBlock.assertIsDisplayed() }
}
step("Assert 'You receive' block is displayed") {
onSwapTokenScreen { youReceiveBlock }
}
step("Assert send token fiat amount is displayed") {
onSwapTokenScreen { swapFiatAmount.assertIsDisplayed() }
}
step("Assert receive token fiat amount is displayed") {
onSwapTokenScreen { receiveFiatAmount.assertIsDisplayed() }
}
step("Assert 'Swap tokens on screen' button is displayed") {
onSwapTokenScreen {
flakySafely(WAIT_UNTIL_TIMEOUT) {
swapTokensOnscreenButton.assertIsDisplayed()
}
}
}
step("Assert 'Swap' button is disabled") {
onSwapTokenScreen { swapButton.assertIsNotEnabled() }
}
}
}
@AllureId("5162")
@DisplayName("Swap: check swap tokens switch")
@Test
fun checkSwapTokensSwitchTest() {
val swapTokenSymbol = "POL"
val receiveTokenSymbol = "ETH"
val tokenTitle = "Polygon"
setupHooks().run {
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 swap token symbol: '$swapTokenSymbol' is displayed") {
onSwapTokenScreen { swapTokenSymbol(swapTokenSymbol).assertIsDisplayed() }
}
step("Assert receive token symbol: '$receiveTokenSymbol' is displayed") {
onSwapTokenScreen { receiveTokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
}
step("Click on 'Swap tokens on screen' button") {
onSwapTokenScreen { swapTokensOnscreenButton.performClick() }
waitForIdle()
}
step("Assert new swap token symbol: '$receiveTokenSymbol' is displayed") {
onSwapTokenScreen { swapTokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
}
step("Assert new receive token symbol: '$swapTokenSymbol' is displayed") {
onSwapTokenScreen { receiveTokenSymbol(swapTokenSymbol).assertIsDisplayed() }
}
}
}