Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-17 11:00:59 +03:00
parent 2a5a05fe83
commit 5618f44c8b
8 changed files with 151 additions and 4 deletions

View file

@ -3,11 +3,17 @@ package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase import com.tangem.common.BaseTestCase
import com.tangem.core.ui.R import com.tangem.core.ui.R
import com.tangem.core.ui.test.AddFundsBottomSheetTestTags
import com.tangem.core.ui.test.BaseBottomSheetTestTags import com.tangem.core.ui.test.BaseBottomSheetTestTags
import com.tangem.core.ui.test.BuyTokenScreenTestTags
import com.tangem.core.ui.test.MarketsTestTags
import com.tangem.core.ui.test.TokenActionsTestTags
import com.tangem.core.ui.test.TokenElementsTestTags
import io.github.kakaocup.compose.node.element.ComposeScreen 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.ComposeScreen.Companion.onComposeScreen
import io.github.kakaocup.compose.node.element.KNode import io.github.kakaocup.compose.node.element.KNode
import io.github.kakaocup.kakao.common.utilities.getResourceString import io.github.kakaocup.kakao.common.utilities.getResourceString
import androidx.compose.ui.test.hasTestTag as withTestTag
import androidx.compose.ui.test.hasText as withText import androidx.compose.ui.test.hasText as withText
class AddFundsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : class AddFundsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
@ -32,7 +38,25 @@ class AddFundsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractions
} }
val closeButton: KNode = child { val closeButton: KNode = child {
hasAnyChild(withText(getResourceString(R.string.common_close))) hasTestTag(AddFundsBottomSheetTestTags.CLOSE_BUTTON)
useUnmergedTree = true
}
val buyTokenButton: KNode = child {
hasTestTag(TokenActionsTestTags.BUY_ACTION)
useUnmergedTree = true
}
fun userTokenWithTitle(tokenTitle: String): KNode = child {
hasTestTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
hasAnyDescendant(withTestTag(TokenElementsTestTags.TOKEN_TITLE))
hasAnyDescendant(withText(tokenTitle))
useUnmergedTree = true
}
fun trendingTokenWithTitle(tokenTitle: String): KNode = child {
hasTestTag(MarketsTestTags.TOKENS_LIST_ITEM)
hasAnyDescendant(withText(tokenTitle))
useUnmergedTree = true useUnmergedTree = true
} }
} }

View file

@ -21,6 +21,11 @@ class AddTokenBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractions
hasText(getResourceString(R.string.common_add_token)) hasText(getResourceString(R.string.common_add_token))
} }
val closeButton: KNode = child {
hasTestTag(BaseBottomSheetTestTags.CLOSE_BUTTON)
useUnmergedTree = true
}
val addButton: KNode = child { val addButton: KNode = child {
hasTestTag(BaseButtonTestTags.TEXT) hasTestTag(BaseButtonTestTags.TEXT)
hasText(getResourceString(R.string.common_add)) hasText(getResourceString(R.string.common_add))

View file

@ -439,6 +439,14 @@ class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteracti
.onAllNodes(withTestTag(MainScreenTestTags.TOKEN_LIST_ITEM), useUnmergedTree = true) .onAllNodes(withTestTag(MainScreenTestTags.TOKEN_LIST_ITEM), useUnmergedTree = true)
.assertCountEquals(expectedCount) .assertCountEquals(expectedCount)
} }
fun assertTokenExists(tokenTitle: String) {
lazyList.child<KNode> {
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
hasAnyDescendant(withText(tokenTitle))
useUnmergedTree = true
}.assertIsDisplayed()
}
} }
internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) = internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) =

View file

@ -0,0 +1,86 @@
package com.tangem.tests.addFunds
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.assertTextContainsSafe
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.screens.onAddTokenBottomSheet
import com.tangem.screens.onAddFundsBottomSheet
import com.tangem.screens.onBuyTokenDetailsScreen
import com.tangem.screens.onMainScreen
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 BuyTest : BaseTestCase() {
@AllureId("587")
@DisplayName("Buy. Display tokens available for purchase")
@Test
fun buyDisplayTokensAvailableForPurchaseTest() {
val token = "Bitcoin"
setupHooks().run {
step("Open 'Main' screen") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on 'Add Funds' button") {
onMainScreen { addFundsButton.clickWithAssertion() }
}
step("Click on $token in Wallet list") {
onAddFundsBottomSheet { userTokenWithTitle(token).clickWithAssertion() }
}
step("Click on 'Buy' button") {
onAddFundsBottomSheet { buyTokenButton.clickWithAssertion() }
}
step("Verify 'Buy $token' title is displayed") {
onBuyTokenDetailsScreen {
topBarTitle.assertTextContainsSafe("Buy $token", substring = true)
}
}
}
}
@AllureId("590")
@DisplayName("Buy. Adding trending token to the main screen")
@Test
fun buyAddingTrendingTokenToMainScreenTest() {
val token = "Solana"
setupHooks().run {
step("Open 'Main' screen") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on 'Add Funds' button") {
onMainScreen { addFundsButton.clickWithAssertion() }
}
step("Click on $token in Trending list") {
onAddFundsBottomSheet { trendingTokenWithTitle(token).clickWithAssertion() }
}
step("Click on 'Add' button") {
onAddTokenBottomSheet { addButton.clickWithAssertion() }
}
step("Close 'Get token' screen") {
onAddFundsBottomSheet { closeButton.clickWithAssertion() }
}
step("Verify token $token exists on main screen") {
onMainScreen { assertTokenExists(token) }
}
step("Click on 'Add Funds' button") {
onMainScreen { addFundsButton.clickWithAssertion() }
}
step("Verify token $token in Wallet list") {
onAddFundsBottomSheet { userTokenWithTitle(token).assertIsDisplayed() }
}
}
}
}

View file

@ -0,0 +1,5 @@
package com.tangem.core.ui.test
object AddFundsBottomSheetTestTags {
const val CLOSE_BUTTON = "ADD_FUNDS_BOTTOM_SHEET_CLOSE_BUTTON"
}

View file

@ -0,0 +1,5 @@
package com.tangem.core.ui.test
object TokenActionsTestTags {
const val BUY_ACTION = "TOKEN_ACTIONS_BUY_ACTION"
}

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.AppComponentContext
@ -26,6 +27,7 @@ import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.extensions.clickableSingle import com.tangem.core.ui.extensions.clickableSingle
import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemeRedesign import com.tangem.core.ui.res.TangemThemeRedesign
import com.tangem.core.ui.test.AddFundsBottomSheetTestTags
import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent import com.tangem.features.commonfeatures.api.addfunds.AddFundsComponent
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenComponent
import com.tangem.features.commonfeatures.impl.R import com.tangem.features.commonfeatures.impl.R
@ -198,7 +200,11 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
null null
}, },
endContent = { endContent = {
CircleIconButton(iconRes = R.drawable.ic_close_24, onClick = onCloseClick) CircleIconButton(
iconRes = R.drawable.ic_close_24,
onClick = onCloseClick,
modifier = Modifier.testTag(AddFundsBottomSheetTestTags.CLOSE_BUTTON),
)
}, },
) )
} }
@ -213,12 +219,12 @@ internal class DefaultAddFundsComponent @AssistedInject constructor(
} }
@Composable @Composable
private fun CircleIconButton(iconRes: Int, onClick: () -> Unit) { private fun CircleIconButton(iconRes: Int, onClick: () -> Unit, modifier: Modifier = Modifier) {
Icon( Icon(
imageVector = ImageVector.vectorResource(id = iconRes), imageVector = ImageVector.vectorResource(id = iconRes),
contentDescription = null, contentDescription = null,
tint = TangemTheme.colors2.graphic.neutral.primary, tint = TangemTheme.colors2.graphic.neutral.primary,
modifier = Modifier modifier = modifier
.size(TangemTheme.dimens2.x11) .size(TangemTheme.dimens2.x11)
.background( .background(
color = TangemTheme.colors2.button.backgroundSecondary, color = TangemTheme.colors2.button.backgroundSecondary,

View file

@ -18,6 +18,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
@ -42,6 +43,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.formatStyled import com.tangem.core.ui.format.bigdecimal.formatStyled
import com.tangem.core.ui.format.bigdecimal.price import com.tangem.core.ui.format.bigdecimal.price
import com.tangem.core.ui.res.* import com.tangem.core.ui.res.*
import com.tangem.core.ui.test.TokenActionsTestTags
import com.tangem.features.commonfeatures.impl.R import com.tangem.features.commonfeatures.impl.R
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.PortfolioBadgeUM import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.PortfolioBadgeUM
import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM import com.tangem.features.commonfeatures.impl.tokenactions.ui.state.TokenActionsUM
@ -120,7 +122,13 @@ private fun QuickActionsList(state: TokenActionsUM, modifier: Modifier = Modifie
enter = fadeIn() + expandVertically(), enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(), exit = fadeOut() + shrinkVertically(),
) { ) {
val actionModifier = when (actionUM) {
is QuickActionUM.V1.Buy, is QuickActionUM.V2.Buy ->
Modifier.testTag(TokenActionsTestTags.BUY_ACTION)
else -> Modifier
}
TokenActionRow( TokenActionRow(
modifier = actionModifier,
iconRes = actionUM.icon, iconRes = actionUM.icon,
title = actionUM.title, title = actionUM.title,
description = actionUM.description, description = actionUM.description,