Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-29 11:26:48 +03:00
parent 496072829c
commit 8ec30bd373
40 changed files with 1214 additions and 33 deletions

View file

@ -0,0 +1,96 @@
package com.tangem.common.utils
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import timber.log.Timber
import java.io.IOException
/**
* Method uses to set WireMock scenario state
*/
fun setWireMockScenarioState(
scenarioName: String,
state: String,
baseUrl: String = "[REDACTED_ENV_URL]"
): Boolean {
val client = OkHttpClient()
val json = """{"state": "$state"}"""
val mediaType = "application/json".toMediaType()
val request = Request.Builder()
.url("$baseUrl/__admin/scenarios/$scenarioName/state")
.put(json.toRequestBody(mediaType))
.build()
return try {
client.newCall(request).execute().use { response ->
val body = response.body?.string() ?: ""
Timber.d("WireMock scenario request URL: ${request.url}")
Timber.d("WireMock scenario request body: $json")
Timber.d("WireMock scenario response: ${response.code} - ${response.message}")
Timber.d("WireMock scenario response body: $body")
response.isSuccessful
}
} catch (e: IOException) {
Timber.e(e, "WireMock scenario error")
false
}
}
/**
* Method checks accessibility of WireMock
*/
fun checkWireMockStatus(baseUrl: String = "[REDACTED_ENV_URL]"): Boolean {
val client = OkHttpClient()
val request = Request.Builder()
.url("$baseUrl/__admin/scenarios")
.get()
.build()
return try {
client.newCall(request).execute().use { response ->
val body = response.body?.string() ?: ""
Timber.d("WireMock status check: ${response.code}")
Timber.d("Available scenarios: $body")
response.isSuccessful
}
} catch (e: IOException) {
Timber.e(e, "WireMock not accessible")
false
}
}
/**
* Method to reset all WireMock scenarios
*/
fun resetWireMockScenarios(baseUrl: String = "[REDACTED_ENV_URL]"): Boolean {
Timber.i("=== WireMock Scenarios Reset ===")
Timber.i("Base URL: $baseUrl")
val client = OkHttpClient()
val url = "$baseUrl/__admin/scenarios/reset"
Timber.i("Request URL: $url")
val request = Request.Builder()
.url(url)
.post("".toRequestBody())
.build()
return try {
Timber.d("Sending reset request...")
client.newCall(request).execute().use { response ->
Timber.d("Response code: ${response.code}")
Timber.d("Response message: ${response.message}")
val responseBody = response.body?.string() ?: ""
Timber.d("Response body: $responseBody")
val isSuccessful = response.isSuccessful
Timber.d("Is successful: $isSuccessful")
isSuccessful
}
} catch (e: IOException) {
Timber.e(e, "Exception during reset")
false
}
}

View file

@ -0,0 +1,101 @@
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.BaseButtonTestTags
import com.tangem.core.ui.test.BuyTokenDetailsScreenTestTags
import com.tangem.core.ui.test.NotificationTestTags
import com.tangem.core.ui.test.TopAppBarTestTags
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.hasTestTag as withTestTag
class BuyTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<BuyTokenDetailsPageObject>(semanticsProvider = semanticsProvider) {
val topBarTitle: KNode = child {
hasTestTag(TopAppBarTestTags.TITLE)
useUnmergedTree = true
}
val topBarMoreButton: KNode = child {
hasTestTag(TopAppBarTestTags.MORE_BUTTON)
useUnmergedTree = true
}
val topBarCloseButton: KNode = child {
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
useUnmergedTree = true
}
val errorNotificationTitle: KNode = child {
hasTestTag(NotificationTestTags.TITLE)
hasText(getResourceString(R.string.common_error))
useUnmergedTree = true
}
val errorNotificationText: KNode = child {
hasTestTag(NotificationTestTags.TEXT)
hasText(getResourceString(R.string.common_unknown_error))
useUnmergedTree = true
}
val refreshButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.warning_button_refresh))
}
val fiatCurrencyIcon: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.FIAT_CURRENCY_ICON)
useUnmergedTree = true
}
val expandFiatListButton: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.EXPAND_FIAT_LIST_BUTTON)
useUnmergedTree = true
}
val fiatAmountTextField: KNode = child {
hasParent(withTestTag(BuyTokenDetailsScreenTestTags.FIAT_AMOUNT_TEXT_FIELD))
useUnmergedTree = true
}
val tokenAmountField: KNode = child {
hasParent(withTestTag(BuyTokenDetailsScreenTestTags.TOKEN_AMOUNT))
useUnmergedTree = true
}
val providerLoadingTitle: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TITLE)
}
val providerLoadingText: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TEXT)
}
val providerTitle: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_TITLE)
useUnmergedTree = true
}
val providerText: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_TEXT)
useUnmergedTree = true
}
val buyButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.common_buy))
}
val toSBlock: KNode = child {
hasTestTag(BuyTokenDetailsScreenTestTags.TOS_BLOCK)
useUnmergedTree = true
}
}
internal fun BaseTestCase.onBuyTokenDetailsScreen(function: BuyTokenDetailsPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,38 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.common.utils.LazyListItemNode
import com.tangem.core.ui.test.BuyTokenFiatListTestTags
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
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.compose.node.element.lazylist.KLazyListNode
class BuyTokenFiatListPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<BuyTokenFiatListPageObject>(semanticsProvider = semanticsProvider) {
private val lazyList = KLazyListNode(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(BuyTokenFiatListTestTags.LAZY_LIST) },
itemTypeBuilder = { itemType(::LazyListItemNode) },
positionMatcher = { position ->
SemanticsMatcher.expectValue(
LazyListItemPositionSemantics,
position
)
}
)
fun fiatListItemWithTitle(title: String): KNode {
return lazyList.child<KNode> {
hasText(title)
}
}
}
internal fun BaseTestCase.onBuyTokenFiatListBottomSheet(function: BuyTokenFiatListPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,54 @@
package com.tangem.screens
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.common.utils.LazyListItemNode
import com.tangem.core.ui.R
import com.tangem.core.ui.test.BuyTokenScreenTestTags
import com.tangem.core.ui.test.TokenElementsTestTags
import com.tangem.core.ui.test.TopAppBarTestTags
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
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.compose.node.element.lazylist.KLazyListNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
class BuyTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<BuyTokenPageObject>(semanticsProvider = semanticsProvider) {
val topAppBarTitle: KNode = child {
hasTestTag(TopAppBarTestTags.TITLE)
hasText(getResourceString(R.string.common_buy))
useUnmergedTree = true
}
private val lazyList = KLazyListNode(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(BuyTokenScreenTestTags.LAZY_LIST) },
itemTypeBuilder = { itemType(::LazyListItemNode) },
positionMatcher = { position ->
SemanticsMatcher.expectValue(
LazyListItemPositionSemantics,
position
)
}
)
@OptIn(ExperimentalTestApi::class)
fun tokenWithTitleAndFiatAmount(tokenTitle: String): KNode {
return lazyList.childWith<LazyListItemNode> {
hasTestTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
hasText(tokenTitle)
useUnmergedTree = true
}.child<KNode> {
hasTestTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT)
useUnmergedTree = true
}
}
}
internal fun BaseTestCase.onBuyTokenScreen(function: BuyTokenPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -3,6 +3,7 @@ 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.BaseButtonTestTags
import com.tangem.core.ui.test.DialogTestTags
import io.github.kakaocup.compose.node.element.ComposeScreen
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
@ -17,14 +18,19 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
}
val cancelButton: KNode = child {
hasTestTag(DialogTestTags.BUTTON)
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.common_cancel))
}
val hideButton: KNode = child {
hasTestTag(DialogTestTags.BUTTON)
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.token_details_hide_alert_hide))
}
val confirmButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.common_confirm))
}
}
internal fun BaseTestCase.onDialog(function: DialogPageObject.() -> Unit) =

View file

@ -39,6 +39,11 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
hasText(getResourceString(R.string.common_generate_addresses))
}
val buyButton: KNode = child {
hasTestTag(MainScreenTestTags.MULTI_CURRENCY_ACTION_BUTTON)
hasText(getResourceString(R.string.common_buy))
}
/**
* Find token list item with title and address
*/

View file

@ -0,0 +1,46 @@
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.ResidenceSettingsScreenTestTags
import com.tangem.core.ui.test.TopAppBarTestTags
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 com.tangem.features.onramp.impl.R as OnrampImplR
class ResidenceSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<ResidenceSettingsPageObject>(semanticsProvider = semanticsProvider) {
val topBarTitle: KNode = child {
hasTestTag(TopAppBarTestTags.TITLE)
hasText(getResourceString(R.string.onramp_settings_title))
useUnmergedTree = true
}
val topBarCloseButton: KNode = child {
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
useUnmergedTree = true
}
val residenceButton: KNode = child {
hasText(getResourceString(OnrampImplR.string.onramp_settings_residence))
useUnmergedTree = true
}
val countryName: KNode = child {
hasTestTag(ResidenceSettingsScreenTestTags.COUNTRY_NAME)
useUnmergedTree = true
}
val residenceSettingsDescription: KNode = child {
hasText(getResourceString(OnrampImplR.string.onramp_settings_residence_description))
useUnmergedTree = true
}
}
internal fun BaseTestCase.onResidenceSettingsScreen(function: ResidenceSettingsPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,59 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.common.utils.LazyListItemNode
import com.tangem.core.ui.test.SelectCountryBottomSheetTestTags
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
import com.tangem.features.onramp.impl.R
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.compose.node.element.lazylist.KLazyListNode
import io.github.kakaocup.kakao.common.utilities.getResourceString
import androidx.compose.ui.test.hasText as withText
import androidx.compose.ui.test.hasTestTag as withTestTag
class SelectCountryPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SelectCountryPageObject>(semanticsProvider = semanticsProvider) {
private val lazyList = KLazyListNode(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(SelectCountryBottomSheetTestTags.LAZY_LIST) },
itemTypeBuilder = { itemType(::LazyListItemNode) },
positionMatcher = { position ->
SemanticsMatcher.expectValue(
LazyListItemPositionSemantics,
position
)
}
)
val searchBar: KNode = child {
hasTestTag(SelectCountryBottomSheetTestTags.SEARCH_BAR)
useUnmergedTree = true
}
fun countryWithNameAndIcon(name: String): KNode {
return lazyList.child<KNode> {
hasText(name)
hasAnySibling(withTestTag(SelectCountryBottomSheetTestTags.COUNTRY_ICON))
useUnmergedTree = true
}
}
fun unavailableCountryWithNameAndIcon(name: String): KNode {
return lazyList.child<KNode> {
hasText(name)
hasAnySibling(withText(getResourceString(R.string.onramp_country_unavailable)))
hasAnySibling(withTestTag(SelectCountryBottomSheetTestTags.UNAVAILABLE_COUNTRY_ICON))
useUnmergedTree = true
}
}
}
internal fun BaseTestCase.onSelectCountryBottomSheet(function: SelectCountryPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,50 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.common.utils.LazyListItemNode
import com.tangem.core.ui.test.SelectPaymentMethodBottomSheetTestTags
import com.tangem.core.ui.test.TopAppBarTestTags
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
import com.tangem.features.onramp.impl.R
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.compose.node.element.lazylist.KLazyListNode
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 SelectPaymentMethodPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SelectPaymentMethodPageObject>(semanticsProvider = semanticsProvider) {
private val lazyList = KLazyListNode(
semanticsProvider = semanticsProvider,
viewBuilderAction = { hasTestTag(SelectPaymentMethodBottomSheetTestTags.LAZY_LIST) },
itemTypeBuilder = { itemType(::LazyListItemNode) },
positionMatcher = { position ->
SemanticsMatcher.expectValue(
LazyListItemPositionSemantics,
position
)
}
)
val title: KNode = child {
hasTestTag(TopAppBarTestTags.TITLE)
hasText(getResourceString(R.string.onramp_pay_with))
}
fun paymentMethodWithNameAndIcon(name: String): KNode {
return lazyList.child<KNode> {
hasAnyDescendant(withText(name))
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.PAYMENT_METHOD_ICON))
useUnmergedTree = true
}
}
}
internal fun BaseTestCase.onSelectPaymentMethodBottomSheet(function: SelectPaymentMethodPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,91 @@
package com.tangem.screens
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.test.SelectProviderBottomSheetTestTags
import com.tangem.features.onramp.impl.R
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 SelectProviderPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SelectProviderPageObject>(semanticsProvider = semanticsProvider) {
val title: KNode = child {
hasText(getResourceString(R.string.onramp_choose_provider_title_hint))
useUnmergedTree = true
}
val paymentMethodIcon: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_ICON)
useUnmergedTree = true
}
val paymentMethodTitle: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_NAME)
useUnmergedTree = true
}
val paymentMethodName: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_NAME)
useUnmergedTree = true
}
val paymentMethodExpandButton: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_EXPAND_BUTTON)
useUnmergedTree = true
}
val availableProviderItem: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_ITEM)
useUnmergedTree = true
}
val availableProviderName: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_NAME)
useUnmergedTree = true
}
val tokenAmount: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.TOKEN_AMOUNT)
useUnmergedTree = true
}
val unavailableProviderItem: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_ITEM)
useUnmergedTree = true
}
val unavailableProviderName: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_NAME)
useUnmergedTree = true
}
val moreProvidersIcon: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_ICON)
useUnmergedTree = true
}
val moreProvidersText: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_TEXT)
useUnmergedTree = true
}
val bestRateLabel: KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.BEST_RATE_LABEL)
useUnmergedTree = true
}
fun availableProviderWithName(name: String, tokenAmount: String, rate: String): KNode = child {
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_ITEM)
hasAnyChild(withText(name))
hasAnyChild(withText(tokenAmount))
hasAnyChild(withText(rate))
useUnmergedTree = true
}
}
internal fun BaseTestCase.onSelectProviderBottomSheet(function: SelectProviderPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,469 @@
package com.tangem.tests
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.utils.resetWireMockScenarios
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.scenarios.OpenMainScreenScenario
import com.tangem.screens.*
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 BuyTokenTest : BaseTestCase() {
@AllureId("3478")
@DisplayName("Onramp: error in providers loading")
@Test
fun errorInProvidersLoadingTest() {
setupHooks(
additionalAfterSection = {
resetWireMockScenarios()
}
).run {
val tokenTitle = "Bitcoin"
val balance = "$184.85"
resetWireMockScenarios()
step("Setup WireMock scenario for 'Error' state") {
setWireMockScenarioState("payment_methods", "Error")
}
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = $balance") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Assert error notification title is displayed") {
onBuyTokenDetailsScreen { errorNotificationTitle.assertIsDisplayed() }
}
step("Assert error notification text is displayed") {
onBuyTokenDetailsScreen { errorNotificationText.assertIsDisplayed() }
}
step("Assert 'Refresh' button is displayed and clickable") {
onBuyTokenDetailsScreen { refreshButton.clickWithAssertion() }
}
}
}
@AllureId("2565")
@DisplayName("Onramp: validate currency selector")
@Test
fun validateCurrencySelectorTest() {
setupHooks().run {
val tokenTitle = "Polygon"
val balance = "$184.85"
val popularFiatsTitle = "Popular Fiats"
val otherCurrenciesTitle = "Other currencies"
val australianDollar = "AUD"
val fiatAmount = "1"
val tokenAmount = "POL 488.24938338"
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Click on 'Confirm' button in 'Dialog'") {
onDialog { confirmButton.clickWithAssertion() }
}
step("Write fiat amount = '$fiatAmount'") {
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
}
step("Assert 'Provider loading block' is displayed") {
onBuyTokenDetailsScreen {
providerLoadingTitle.assertIsDisplayed()
providerLoadingText.assertIsDisplayed()
}
}
step("Assert 'Provider block' is displayed") {
onBuyTokenDetailsScreen {
providerTitle.assertIsDisplayed()
providerText.assertIsDisplayed()
}
}
step("Assert token amount = '$tokenAmount'") {
onBuyTokenDetailsScreen {
tokenAmountField.assertTextContains(tokenAmount)
}
}
step("Fiat currency icon is displayed") {
onBuyTokenDetailsScreen { fiatCurrencyIcon.assertIsDisplayed() }
}
step("Click on 'Expand fiat list' button") {
onBuyTokenDetailsScreen { expandFiatListButton.clickWithAssertion() }
}
step("Assert '$popularFiatsTitle' is displayed") {
onBuyTokenFiatListBottomSheet {
fiatListItemWithTitle(popularFiatsTitle).assertIsDisplayed()
}
}
step("Assert '$otherCurrenciesTitle' is displayed") {
onBuyTokenFiatListBottomSheet {
fiatListItemWithTitle(otherCurrenciesTitle).assertIsDisplayed()
}
}
step("Click on fiat with title: '$australianDollar'") {
onBuyTokenFiatListBottomSheet {
fiatListItemWithTitle(australianDollar).performClick()
}
}
step("Assert new fiat currency: '$australianDollar' is displayed") {
onBuyTokenDetailsScreen {
fiatAmountTextField.assertTextContains(australianDollar + fiatAmount)
}
}
step("Assert token amount = '$tokenAmount'") {
onBuyTokenDetailsScreen {
tokenAmountField.assertTextContains(tokenAmount)
}
}
}
}
@AllureId("2566")
@DisplayName("Onramp: validate 'Buy token' screen")
@Test
fun validateBuyTokenScreenTest() {
setupHooks().run {
val tokenTitle = "Polygon"
val balance = "$184.85"
val euro = "EUR"
val fiatAmount = "1"
val tokenAmount = "POL 488.24938338"
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Click on 'Confirm' button in 'Dialog'") {
onDialog { confirmButton.clickWithAssertion() }
}
step("Assert 'Buy Token' title is displayed") {
onBuyTokenDetailsScreen { topBarTitle.assertTextContains("Buy $tokenTitle") }
}
step("Assert 'More button' in top bar is displayed") {
onBuyTokenDetailsScreen { topBarMoreButton.assertIsDisplayed() }
}
step("Write fiat amount = '$fiatAmount'") {
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
}
step("Assert fiat amount = '$fiatAmount'") {
onBuyTokenDetailsScreen { fiatAmountTextField.assertTextContains(euro + fiatAmount) }
}
step("Assert 'Provider loading block' is displayed") {
onBuyTokenDetailsScreen {
providerLoadingTitle.assertIsDisplayed()
providerLoadingText.assertIsDisplayed()
}
}
step("Assert 'Provider block' is displayed") {
onBuyTokenDetailsScreen {
providerTitle.assertIsDisplayed()
providerText.assertIsDisplayed()
}
}
step("Assert token amount = '$tokenAmount'") {
onBuyTokenDetailsScreen { tokenAmountField.assertTextContains(tokenAmount) }
}
step("Assert 'ToS' block is displayed") {
onBuyTokenDetailsScreen { toSBlock.assertIsDisplayed()}
}
step("Assert 'Buy' button is displayed") {
onBuyTokenDetailsScreen { buyButton.assertIsDisplayed()}
}
step("Assert 'Close' button in top bar is displayed") {
onBuyTokenDetailsScreen { topBarCloseButton.assertIsDisplayed() }
}
}
}
@AllureId("2563")
@DisplayName("Onramp: validate 'Residence' settings screen")
@Test
fun validateResidenceSettingsScreenTest() {
setupHooks().run {
val tokenTitle = "Polygon"
val balance = "$184.85"
val country = "Albania"
val unavailableCountry = "Lebanon"
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Click on 'Confirm' button in 'Dialog'") {
onDialog { confirmButton.clickWithAssertion() }
}
step("Assert 'Buy $tokenTitle' title is displayed") {
onBuyTokenDetailsScreen { topBarTitle.assertTextContains("Buy $tokenTitle") }
}
step("Click 'More' button in tab bar") {
onBuyTokenDetailsScreen { topBarMoreButton.clickWithAssertion() }
}
step("Assert 'Residence Settings' screen top bar title is displayed") {
onResidenceSettingsScreen { topBarTitle.assertIsDisplayed() }
}
step("Assert 'Residence Settings' screen top bar 'Close' button is displayed") {
onResidenceSettingsScreen { topBarCloseButton.assertIsDisplayed() }
}
step("Assert 'Residence' button is displayed on 'Residence Settings' screen") {
onResidenceSettingsScreen { residenceButton.assertIsDisplayed() }
}
step("Assert country name is displayed on 'Residence Settings' screen") {
onResidenceSettingsScreen { countryName.assertIsDisplayed() }
}
step("Assert residence settings description is displayed on 'Residence Settings' screen") {
onResidenceSettingsScreen { residenceSettingsDescription.assertIsDisplayed() }
}
step("Click 'Residence button'") {
onResidenceSettingsScreen { residenceButton.clickWithAssertion() }
}
step("Assert 'Search bar' is displayed") {
onSelectCountryBottomSheet { searchBar.assertIsDisplayed() }
}
step("Type unavailable country name: '$unavailableCountry' in 'Search bar'") {
onSelectCountryBottomSheet { searchBar.performTextReplacement(unavailableCountry) }
}
step("Unavailable country: '$unavailableCountry' is displayed") {
onSelectCountryBottomSheet { unavailableCountryWithNameAndIcon(unavailableCountry).assertIsDisplayed() }
}
step("Type country name: '$country' in 'Search bar'") {
onSelectCountryBottomSheet { searchBar.performTextReplacement(country) }
}
step("Available country: '$country' is displayed") {
onSelectCountryBottomSheet { countryWithNameAndIcon(country).assertIsDisplayed() }
}
step("Click on country: '$country'") {
onSelectCountryBottomSheet { countryWithNameAndIcon(country).clickWithAssertion() }
}
step("Assert country: '$country' is displayed on 'Residence Settings' screen") {
onResidenceSettingsScreen { countryName.assertTextContains(country) }
}
}
}
@AllureId("2570")
@DisplayName("Onramp: validate 'Select provider' bottom sheet")
@Test
fun validateProvidersScreenTest() {
setupHooks().run {
val tokenTitle = "Polygon"
val balance = "$184.85"
val paymentMethod = "Card"
val fiatAmount = "1"
val providerNameMercuryo = "Mercuryo"
val providerNameSimplex = "Simplex"
val tokenAmount = "POL 488.24938338"
val bestRate = "Best rate"
val rate = "-0.00%"
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Click on 'Confirm' button in 'Dialog'") {
onDialog { confirmButton.clickWithAssertion() }
}
step("Write fiat amount = '$fiatAmount'") {
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
}
step("Assert 'Provider block' is displayed") {
onBuyTokenDetailsScreen {
providerTitle.assertIsDisplayed()
providerText.assertIsDisplayed()
}
}
step("Open 'Select Provider' bottom sheet") {
onBuyTokenDetailsScreen { providerTitle.performClick() }
}
step("Assert available provider name is displayed") {
onSelectProviderBottomSheet { availableProviderItem.assertIsDisplayed() }
}
step("Assert unavailable provider name is displayed") {
onSelectProviderBottomSheet { unavailableProviderItem.assertIsDisplayed() }
}
step("Click on 'Expand payment methods' button") {
onSelectProviderBottomSheet { paymentMethodExpandButton.clickWithAssertion() }
}
step("Click on payment method: '$paymentMethod'") {
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(paymentMethod).clickWithAssertion() }
}
step("Assert 'Select Provider' bottom sheet title is displayed") {
onSelectProviderBottomSheet { title.assertIsDisplayed() }
}
step("Assert payment method icon is displayed") {
onSelectProviderBottomSheet { paymentMethodIcon.assertIsDisplayed() }
}
step("Assert payment method title is displayed") {
onSelectProviderBottomSheet { paymentMethodTitle.assertIsDisplayed() }
}
step("Assert payment method name is displayed") {
onSelectProviderBottomSheet { paymentMethodName.assertIsDisplayed() }
}
step("Assert provider with name: '$providerNameMercuryo' and rate: '$bestRate' is displayed") {
onSelectProviderBottomSheet {
availableProviderWithName(providerNameMercuryo, tokenAmount, bestRate).assertIsDisplayed()
}
}
step("Assert provider with name: '$providerNameSimplex' and rate: '$rate' is displayed") {
onSelectProviderBottomSheet {
availableProviderWithName(providerNameSimplex, tokenAmount, rate).assertIsDisplayed()
}
}
step("Assert 'More providers' icon is displayed") {
onSelectProviderBottomSheet { moreProvidersIcon.assertIsDisplayed() }
}
step("Assert 'More providers' text is displayed") {
onSelectProviderBottomSheet { moreProvidersText.assertIsDisplayed() }
}
step("Assert 'Best rate' label is displayed") {
onSelectProviderBottomSheet { bestRateLabel.assertIsDisplayed() }
}
}
}
@AllureId("2570")
@DisplayName("Onramp: validate 'Select payment method' bottom sheet")
@Test
fun validatePaymentMethodScreenTest() {
setupHooks().run {
val tokenTitle = "Polygon"
val balance = "$184.85"
val card = "Card"
val googlePay = "Google Pay"
val invoiceRevolutPay = "Invoice Revolut Pay"
val sepa = "Sepa"
val fiatAmount = "1"
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))
}
step("Click on 'Synchronize addresses' button") {
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
}
step("Assert wallet balance = '$balance'") {
onMainScreen { walletBalance().assertTextContains(balance) }
}
step("Click on 'Buy' button") {
onMainScreen { buyButton.clickWithAssertion() }
}
step("Click on token with name: '$tokenTitle'") {
onBuyTokenScreen {
topAppBarTitle.assertIsDisplayed()
tokenWithTitleAndFiatAmount(tokenTitle).clickWithAssertion()
}
}
step("Click on 'Confirm' button in 'Dialog'") {
onDialog { confirmButton.clickWithAssertion() }
}
step("Write fiat amount = '$fiatAmount'") {
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
}
step("Assert 'Provider block' is displayed") {
onBuyTokenDetailsScreen {
providerTitle.assertIsDisplayed()
providerText.assertIsDisplayed()
}
}
step("Open 'Select Provider' bottom sheet") {
onBuyTokenDetailsScreen { providerTitle.performClick() }
}
step("Click on 'Expand payment methods' button") {
onSelectProviderBottomSheet { paymentMethodExpandButton.clickWithAssertion() }
}
step("Assert 'Select Payment Method' bottom sheet title is displayed") {
onSelectPaymentMethodBottomSheet { title.assertIsDisplayed() }
}
step("Assert payment method: '$card' is displayed") {
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(card).assertIsDisplayed() }
}
step("Assert payment method: '$googlePay' is displayed") {
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(googlePay).assertIsDisplayed() }
}
step("Assert payment method: '$invoiceRevolutPay' is displayed") {
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(invoiceRevolutPay).assertIsDisplayed() }
}
step("Assert payment method: '$sepa' is displayed") {
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(sepa).assertIsDisplayed() }
}
step("Press 'Back' button") {
onSelectPaymentMethodBottomSheet { device.uiDevice.pressBack() }
}
step("Assert 'Select Provider' bottom sheet title is displayed") {
onSelectProviderBottomSheet { title.assertIsDisplayed() }
}
}
}
}

View file

@ -17,7 +17,7 @@ class HideTokenTest : BaseTestCase() {
@Test
fun hideWalletTokenByHideButtonTest() {
val tokenTitle = "Polygon"
val balance = "<$0.01"
val balance = "$184.85"
setupHooks().run {
step("Open 'Main Screen'") {
scenario(OpenMainScreenScenario(composeTestRule))

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -20,6 +21,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TopAppBarTestTags
/**
* [TangemTopAppBar] height options.
@ -127,6 +129,7 @@ fun TangemTopAppBar(
TopAppBarButton(
button = endButton,
tint = iconTint,
modifier = modifier.testTag(TopAppBarTestTags.MORE_BUTTON),
)
}
},
@ -172,6 +175,7 @@ fun TangemTopAppBar(
TopAppBarButton(
button = startButton,
tint = iconTint,
modifier = modifier.testTag(TopAppBarTestTags.CLOSE_BUTTON),
)
}
}
@ -222,6 +226,7 @@ private fun TopAppBarTitle(
color = textColor,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.testTag(TopAppBarTestTags.TITLE),
)
AnimatedVisibility(

View file

@ -25,7 +25,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.core.ui.components.ResizableText
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.DialogTestTags
import com.tangem.core.ui.test.BaseButtonTestTags
import com.tangem.core.ui.utils.MultipleClickPreventer
@Suppress("LongParameterList")
@ -51,7 +51,7 @@ fun TangemButton(
Button(
modifier = modifier
.heightIn(min = size.toHeightDp())
.testTag(DialogTestTags.BUTTON),
.testTag(BaseButtonTestTags.BUTTON),
onClick = {
multipleClickPreventer.processEvent { if (!showProgress) onClick() }
},

View file

@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@ -35,6 +36,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.SelectCountryBottomSheetTestTags
@Composable
fun SearchBar(
@ -57,7 +59,8 @@ fun SearchBar(
} else {
state.onActiveChange(false)
}
},
}
.testTag(SelectCountryBottomSheetTestTags.SEARCH_BAR),
enabled = enabled,
value = state.query,
onValueChange = state.onQueryChange,

View file

@ -20,6 +20,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
@ -35,6 +36,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.NotificationTestTags
import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsState as NotificationButtonsState
/**
@ -206,6 +208,7 @@ internal fun TextsBlock(
text = titleText,
color = titleColor,
style = TangemTheme.typography.button,
modifier = modifier.testTag(NotificationTestTags.TITLE),
)
SpacerH(height = TangemTheme.dimens.spacing2)
@ -215,6 +218,7 @@ internal fun TextsBlock(
text = subtitle.resolveReference(),
color = subtitleColor,
style = TangemTheme.typography.caption2,
modifier = modifier.testTag(NotificationTestTags.TEXT),
)
}
}

View file

@ -0,0 +1,5 @@
package com.tangem.core.ui.test
object BaseButtonTestTags {
const val BUTTON = "BASE_BUTTON"
}

View file

@ -0,0 +1,16 @@
package com.tangem.core.ui.test
object BuyTokenDetailsScreenTestTags {
const val EXPAND_FIAT_LIST_BUTTON = "BUY_TOKEN_DETAILS_SCREEN_EXPAND_FIAT_LIST_BUTTON"
const val FIAT_CURRENCY_ICON = "BUY_TOKEN_DETAILS_SCREEN_FIAT_CURRENCY_ICON"
const val FIAT_AMOUNT_TEXT_FIELD = "BUY_TOKEN_DETAILS_SCREEN_FIAT_AMOUNT_TEXT_FIELD"
const val TOKEN_AMOUNT = "BUY_TOKEN_DETAILS_SCREEN_TOKEN_AMOUNT"
const val PROVIDER_LOADING_TITLE = "BUY_TOKEN_DETAILS_SCREEN_PROVIDER_LOADING_TITLE"
const val PROVIDER_LOADING_TEXT = "BUY_TOKEN_DETAILS_SCREEN_PROVIDER_LOADING_TITLE"
const val PROVIDER_TITLE = "BUY_TOKEN_DETAILS_SCREEN_PROVIDER_TITLE"
const val PROVIDER_TEXT = "BUY_TOKEN_DETAILS_SCREEN_PROVIDER_TEXT"
const val TOS_BLOCK = "BUY_TOKEN_DETAILS_SCREEN_TOS_BLOCK"
}

View file

@ -0,0 +1,6 @@
package com.tangem.core.ui.test
object BuyTokenFiatListTestTags {
const val LAZY_LIST = "BUY_TOKEN_FIAT_LIST_LAZY_LIST"
const val LAZY_LIST_ITEM = "BUY_TOKEN_FIAT_LIST_LAZY_LIST_ITEM"
}

View file

@ -0,0 +1,6 @@
package com.tangem.core.ui.test
object BuyTokenScreenTestTags {
const val LAZY_LIST = "BUY_TOKEN_SCREEN_LAZY_LIST"
const val LAZY_LIST_ITEM = "BUY_TOKEN_SCREEN_LAZY_LIST_ITEM"
}

View file

@ -2,5 +2,4 @@ package com.tangem.core.ui.test
object DialogTestTags {
const val DIALOG_CONTAINER = "DIALOG_CONTAINER"
const val BUTTON = "DIALOG_BUTTON"
}

View file

@ -8,4 +8,5 @@ object MainScreenTestTags {
const val WALLET_BALANCE = "MAIN_SCREEN_WALLET_BALANCE"
const val WALLET_LIST_ITEM = "MAIN_SCREEN_WALLET_LIST_ITEM"
const val ORGANIZE_TOKENS_BUTTON = "MAIN_SCREEN_ORGANIZE_TOKENS_BUTTON"
const val MULTI_CURRENCY_ACTION_BUTTON = "MAIN_SCREEN_MULTI_CURRENCY_ACTION_BUTTON"
}

View file

@ -0,0 +1,6 @@
package com.tangem.core.ui.test
object NotificationTestTags {
const val TITLE = "NOTIFICATION_TITLE"
const val TEXT = "NOTIFICATION_TEXT"
}

View file

@ -0,0 +1,5 @@
package com.tangem.core.ui.test
object ResidenceSettingsScreenTestTags {
const val COUNTRY_NAME = "RESIDENCE_SETTINGS_SCREEN_COUNTRY_NAME"
}

View file

@ -0,0 +1,12 @@
package com.tangem.core.ui.test
object SelectCountryBottomSheetTestTags {
const val LAZY_LIST = "SELECT_COUNTRY_BOTTOM_SHEET_LAZY_LIST"
const val COUNTRY_ITEM = "SELECT_COUNTRY_BOTTOM_SHEET_COUNTRY_ITEM"
const val UNAVAILABLE_COUNTRY_ITEM = "SELECT_COUNTRY_BOTTOM_SHEET_UNAVAILABLE_COUNTRY_ITEM"
const val SEARCH_BAR = "SELECT_COUNTRY_BOTTOM_SHEET_SEARCH_BAR"
const val COUNTRY_ICON = "SELECT_COUNTRY_BOTTOM_SHEET_COUNTRY_ICON"
const val UNAVAILABLE_COUNTRY_ICON = "SELECT_COUNTRY_BOTTOM_SHEET_UNAVAILABLE_COUNTRY_ICON"
const val COUNTRY_NAME = "SELECT_COUNTRY_BOTTOM_SHEET_COUNTRY_NAME"
}

View file

@ -0,0 +1,7 @@
package com.tangem.core.ui.test
object SelectPaymentMethodBottomSheetTestTags {
const val LAZY_LIST = "SELECT_PAYMENT_METHOD_LAZY_LIST"
const val PAYMENT_METHOD_ICON = "PAYMENT_METHOD_NAME"
}

View file

@ -0,0 +1,18 @@
package com.tangem.core.ui.test
object SelectProviderBottomSheetTestTags {
const val PAYMENT_METHOD_ICON = "SELECT_PROVIDER_BOTTOM_SHEET_PAYMENT_METHOD_ICON"
const val PAYMENT_METHOD_TITLE = "SELECT_PROVIDER_BOTTOM_SHEET_PAYMENT_METHOD_TITLE"
const val PAYMENT_METHOD_NAME = "SELECT_PROVIDER_BOTTOM_SHEET_PAYMENT_METHOD_NAME"
const val PAYMENT_METHOD_EXPAND_BUTTON = "SELECT_PROVIDER_BOTTOM_SHEET_PAYMENT_METHOD_EXPAND_BUTTON"
const val TOKEN_AMOUNT = "SELECT_PROVIDER_BOTTOM_SHEET_TOKEN_AMOUNT"
const val AVAILABLE_PROVIDER_NAME = "SELECT_PROVIDER_BOTTOM_SHEET_AVAILABLE_PROVIDER_NAME"
const val AVAILABLE_PROVIDER_ITEM = "SELECT_PROVIDER_BOTTOM_SHEET_AVAILABLE_PROVIDER_ITEM"
const val UNAVAILABLE_PROVIDER_ITEM = "SELECT_PROVIDER_BOTTOM_SHEET_UNAVAILABLE_PROVIDER_ITEM"
const val UNAVAILABLE_PROVIDER_NAME = "SELECT_PROVIDER_BOTTOM_SHEET_UNAVAILABLE_PROVIDER_NAME"
const val UNAVAILABLE_PROVIDER_SUBTITLE = "SELECT_PROVIDER_BOTTOM_SHEET_UNAVAILABLE_PROVIDER_SUBTITLE"
const val MORE_PROVIDERS_ICON = "SELECT_PROVIDER_BOTTOM_SHEET_MORE_PROVIDERS_ICON"
const val MORE_PROVIDERS_TEXT = "SELECT_PROVIDER_BOTTOM_SHEET_MORE_PROVIDERS_TEXT"
const val BEST_RATE_LABEL = "SELECT_PROVIDER_BOTTOM_SHEET_BEST_RATE_LABEL"
}

View file

@ -0,0 +1,7 @@
package com.tangem.core.ui.test
object TopAppBarTestTags {
const val TITLE = "TOP_APP_BAR_TITLE"
const val MORE_BUTTON = "TOP_APP_BAR_MORE_BUTTON"
const val CLOSE_BUTTON = "TOP_APP_BAR_CLOSE_BUTTON"
}

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection
@ -26,6 +27,7 @@ import com.tangem.core.ui.components.fields.AmountTextField
import com.tangem.core.ui.components.fields.visualtransformations.AmountVisualTransformation
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.BuyTokenDetailsScreenTestTags
import com.tangem.core.ui.utils.rememberDecimalFormat
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.main.entity.OnrampAmountBlockUM
@ -84,7 +86,8 @@ private fun OnrampAmountField(amountField: AmountFieldModel) {
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
)
.requiredHeightIn(min = TangemTheme.dimens.size32),
.requiredHeightIn(min = TangemTheme.dimens.size32)
.testTag(BuyTokenDetailsScreenTestTags.FIAT_AMOUNT_TEXT_FIELD),
)
LaunchedEffect(key1 = Unit) {
@ -101,7 +104,8 @@ private fun OnrampAmountSecondary(state: OnrampAmountSecondaryFieldUM) {
top = TangemTheme.dimens.spacing8,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
),
)
.testTag(BuyTokenDetailsScreenTestTags.TOKEN_AMOUNT),
contentAlignment = Alignment.Center,
) {
when (state) {
@ -138,12 +142,15 @@ private fun OnrampCurrencyIcon(currencyUM: OnrampCurrencyUM, modifier: Modifier
AsyncImage(
modifier = Modifier
.size(TangemTheme.dimens.size40)
.clip(CircleShape),
.clip(CircleShape)
.testTag(BuyTokenDetailsScreenTestTags.FIAT_CURRENCY_ICON),
model = currencyUM.iconUrl,
contentDescription = null,
)
Icon(
modifier = Modifier.size(TangemTheme.dimens.size16),
modifier = Modifier
.size(TangemTheme.dimens.size16)
.testTag(BuyTokenDetailsScreenTestTags.EXPAND_FIAT_LIST_BUTTON),
painter = painterResource(id = R.drawable.ic_chevron_24),
tint = TangemTheme.colors.icon.informative,
contentDescription = null,

View file

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.ClickableText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@ -15,6 +16,7 @@ import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.extensions.appendColored
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.BuyTokenDetailsScreenTestTags
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
import com.tangem.features.onramp.main.entity.OnrampProviderBlockUM
@ -77,6 +79,7 @@ private fun OnrampTosText(provider: OnrampProviderBlockUM.Content?) {
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
),
modifier = Modifier.testTag(BuyTokenDetailsScreenTestTags.TOS_BLOCK),
onClick = { offset ->
clickableAnnotation.getStringAnnotations(
tag = TERMS_OF_USE_KEY,

View file

@ -13,12 +13,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import com.tangem.core.ui.extensions.appendSpace
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.BuyTokenDetailsScreenTestTags
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.main.entity.OnrampProviderBlockUM
import com.tangem.features.onramp.paymentmethod.ui.PaymentMethodIcon
@ -60,6 +62,7 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
},
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.body2,
modifier = modifier.testTag(BuyTokenDetailsScreenTestTags.PROVIDER_TITLE),
)
Text(
text = buildAnnotatedString {
@ -69,6 +72,7 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
},
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
modifier = modifier.testTag(BuyTokenDetailsScreenTestTags.PROVIDER_TEXT),
)
}
AnimatedVisibility(
@ -108,6 +112,7 @@ private fun OnrampProviderLoading(modifier: Modifier = Modifier) {
text = stringResourceSafe(id = R.string.express_provider),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TITLE),
)
Row(
verticalAlignment = Alignment.CenterVertically,
@ -122,6 +127,7 @@ private fun OnrampProviderLoading(modifier: Modifier = Modifier) {
text = stringResourceSafe(id = R.string.express_fetch_best_rates),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TEXT),
)
}
}

View file

@ -7,10 +7,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.SelectProviderBottomSheetTestTags
@Composable
internal fun PaymentMethodIcon(imageUrl: String, modifier: Modifier = Modifier) {
@ -19,7 +21,8 @@ internal fun PaymentMethodIcon(imageUrl: String, modifier: Modifier = Modifier)
.size(TangemTheme.dimens.size40)
.clip(TangemTheme.shapes.roundedCorners8)
.background(TangemColorPalette.Light1)
.padding(TangemTheme.dimens.spacing6),
.padding(TangemTheme.dimens.spacing6)
.testTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_ICON),
model = ImageRequest.Builder(context = LocalContext.current)
.data(imageUrl)
.crossfade(enable = true)

View file

@ -11,11 +11,13 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.selectedBorder
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.SelectPaymentMethodBottomSheetTestTags
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM
import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodsBottomSheetConfig
@ -49,7 +51,7 @@ private fun SelectPaymentMethodBottomSheetContent(
modifier: Modifier = Modifier,
) {
LazyColumn(
modifier = modifier,
modifier = modifier.testTag(SelectPaymentMethodBottomSheetTestTags.LAZY_LIST),
) {
items(
items = methods,
@ -86,7 +88,10 @@ private fun PaymentMethodItem(paymentMethod: PaymentMethodUM, isSelected: Boolea
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
PaymentMethodIcon(paymentMethod.imageUrl)
PaymentMethodIcon(
imageUrl = paymentMethod.imageUrl,
modifier = Modifier.testTag(SelectPaymentMethodBottomSheetTestTags.PAYMENT_METHOD_ICON),
)
Text(
text = paymentMethod.name,
style = TangemTheme.typography.subtitle2,

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
@ -32,6 +33,7 @@ import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.SelectProviderBottomSheetTestTags
import com.tangem.domain.onramp.model.OnrampPaymentMethod
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.paymentmethod.ui.PaymentMethodIcon
@ -101,15 +103,19 @@ private fun PaymentMethodBlock(
text = stringResourceSafe(id = R.string.onramp_pay_with),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_TITLE),
)
Text(
text = state.name,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.primary1,
modifier = Modifier.testTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_NAME),
)
}
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
modifier = Modifier
.size(TangemTheme.dimens.size24)
.testTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_EXPAND_BUTTON),
painter = painterResource(id = R.drawable.ic_chevron_24),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
@ -149,14 +155,16 @@ private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, m
modifier = modifier
.selectedBorder(isSelected = state.isSelected)
.clickable(onClick = state.onClick)
.padding(all = TangemTheme.dimens.spacing12),
.padding(all = TangemTheme.dimens.spacing12)
.testTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_ITEM),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
SubcomposeAsyncImage(
modifier = Modifier
.size(size = TangemTheme.dimens.size40)
.clip(TangemTheme.shapes.roundedCorners8),
.clip(TangemTheme.shapes.roundedCorners8)
.testTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_NAME),
model = ImageRequest.Builder(context = LocalContext.current)
.data(state.imageUrl)
.crossfade(enable = true)
@ -166,7 +174,9 @@ private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, m
contentDescription = null,
)
Text(
modifier = Modifier.weight(1F),
modifier = Modifier
.weight(1F)
.testTag(SelectProviderBottomSheetTestTags.TOKEN_AMOUNT),
text = state.name,
style = TangemTheme.typography.subtitle2,
color = if (state.isSelected) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.secondary,
@ -189,7 +199,8 @@ private fun AvailableProviderItem(state: ProviderListItemUM.Available.Content, m
modifier = Modifier
.clip(RoundedCornerShape(4.dp))
.background(TangemTheme.colors.icon.accent)
.padding(vertical = 1.dp, horizontal = 6.dp),
.padding(vertical = 1.dp, horizontal = 6.dp)
.testTag(SelectProviderBottomSheetTestTags.BEST_RATE_LABEL),
)
}
state.diffRate != null -> {
@ -218,7 +229,8 @@ private fun UnavailableProviderItem(
Row(
modifier = modifier
.selectedBorder(isSelected = isSelected)
.padding(all = TangemTheme.dimens.spacing12),
.padding(all = TangemTheme.dimens.spacing12)
.testTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_ITEM),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
@ -240,11 +252,13 @@ private fun UnavailableProviderItem(
text = providerName,
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier.testTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_NAME),
)
Text(
text = subtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_SUBTITLE),
)
}
}
@ -259,7 +273,8 @@ private fun OnrampMoreProviders() {
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
modifier = Modifier
.padding(top = 16.dp),
.padding(top = 16.dp)
.testTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_ICON),
)
Text(
text = stringResourceSafe(R.string.express_more_providers_soon),
@ -267,7 +282,8 @@ private fun OnrampMoreProviders() {
color = TangemTheme.colors.icon.informative,
modifier = Modifier
.padding(top = 4.dp, bottom = 24.dp)
.padding(horizontal = TangemTheme.dimens.spacing56),
.padding(horizontal = TangemTheme.dimens.spacing56)
.testTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_TEXT),
textAlign = TextAlign.Center,
)
}

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import coil.compose.AsyncImage
@ -25,6 +26,7 @@ import com.tangem.core.ui.components.fields.SearchBar
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.SelectCountryBottomSheetTestTags
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.selectcountry.entity.CountryItemState
import com.tangem.features.onramp.selectcountry.entity.CountryListUM
@ -40,7 +42,7 @@ internal fun SelectCountryBottomSheet(config: TangemBottomSheetConfig, content:
@Composable
internal fun OnrampCountryList(state: CountryListUM, modifier: Modifier = Modifier) {
LazyColumn(
modifier = modifier,
modifier = modifier.testTag(SelectCountryBottomSheetTestTags.LAZY_LIST),
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
) {
item(key = "search_bar") {
@ -102,13 +104,15 @@ private fun LazyListScope.countryListWithContent(state: CountryListUM.Content) {
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = item.onClick)
.padding(vertical = TangemTheme.dimens.spacing16),
.padding(vertical = TangemTheme.dimens.spacing16)
.testTag(SelectCountryBottomSheetTestTags.COUNTRY_ITEM),
state = item,
)
is CountryItemState.WithContent.Unavailable -> UnavailableCountryItem(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = TangemTheme.dimens.spacing16),
.padding(vertical = TangemTheme.dimens.spacing16)
.testTag(SelectCountryBottomSheetTestTags.UNAVAILABLE_COUNTRY_ITEM),
state = item,
)
}
@ -138,13 +142,17 @@ private fun ContentCountryItem(state: CountryItemState.WithContent.Content, modi
verticalAlignment = Alignment.CenterVertically,
) {
AsyncImage(
modifier = Modifier.size(TangemTheme.dimens.size36),
modifier = Modifier
.size(TangemTheme.dimens.size36)
.testTag(SelectCountryBottomSheetTestTags.COUNTRY_ICON),
model = state.flagUrl,
contentDescription = null,
)
Text(
text = state.countryName,
modifier = Modifier.weight(1F),
modifier = Modifier
.weight(1F)
.testTag(SelectCountryBottomSheetTestTags.COUNTRY_NAME),
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = TangemTheme.typography.subtitle2,
@ -172,7 +180,8 @@ private fun UnavailableCountryItem(state: CountryItemState.WithContent.Unavailab
AsyncImage(
modifier = Modifier
.size(TangemTheme.dimens.size36)
.alpha(0.4F),
.alpha(0.4F)
.testTag(SelectCountryBottomSheetTestTags.UNAVAILABLE_COUNTRY_ICON),
model = state.flagUrl,
contentDescription = null,
)

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.util.fastForEach
import coil.compose.AsyncImage
import com.tangem.core.ui.components.CircleShimmer
@ -25,6 +26,7 @@ import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.BuyTokenFiatListTestTags
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.selectcurrency.entity.CurrenciesListUM
import com.tangem.features.onramp.selectcurrency.entity.CurrencyItemState
@ -40,7 +42,7 @@ internal fun SelectCurrencyBottomSheet(config: TangemBottomSheetConfig, content:
@Composable
internal fun OnrampCurrencyList(state: CurrenciesListUM, modifier: Modifier = Modifier) {
LazyColumn(
modifier = modifier,
modifier = modifier.testTag(BuyTokenFiatListTestTags.LAZY_LIST),
contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16),
) {
item(key = "search_bar") {
@ -106,7 +108,8 @@ private fun LazyListScope.currencyListContent(state: CurrenciesListUM.Content) {
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = item.onClick)
.padding(vertical = TangemTheme.dimens.spacing16),
.padding(vertical = TangemTheme.dimens.spacing16)
.testTag(BuyTokenFiatListTestTags.LAZY_LIST_ITEM),
currency = item,
)
},

View file

@ -10,10 +10,12 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.BuyTokenScreenTestTags
import com.tangem.core.ui.utils.rememberHideKeyboardNestedScrollConnection
import com.tangem.features.onramp.hottokens.HotCryptoComponent
import com.tangem.features.onramp.impl.R
@ -36,7 +38,8 @@ internal fun OnrampSelectToken(
.nestedScroll(nestedScrollConnection)
.background(TangemTheme.colors.background.secondary)
.imePadding()
.systemBarsPadding(),
.systemBarsPadding()
.testTag(BuyTokenScreenTestTags.LAZY_LIST),
) {
stickyHeader(key = "header") {
AppBarWithBackButton(

View file

@ -12,6 +12,7 @@ import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.util.fastForEach
import coil.compose.AsyncImage
@ -19,6 +20,7 @@ import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.ResidenceSettingsScreenTestTags
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.settings.entity.OnrampSettingsItemUM
@ -95,6 +97,7 @@ private fun ResidenceSection(state: OnrampSettingsItemUM.Residence, modifier: Mo
text = state.countryName,
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.body2,
modifier = Modifier.testTag(ResidenceSettingsScreenTestTags.COUNTRY_NAME),
)
Icon(
painter = painterResource(id = R.drawable.ic_chevron_right_24),

View file

@ -9,6 +9,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
@ -24,6 +26,8 @@ import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.BuyTokenScreenTestTags
import com.tangem.core.ui.utils.lazyListItemPosition
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
import com.tangem.features.onramp.tokenlist.ui.preview.PreviewTokenListUMProvider
import kotlinx.collections.immutable.ImmutableList
@ -90,7 +94,9 @@ private fun ItemsBlock(items: ImmutableList<TokensListItemUM>, isBalanceHidden:
lastIndex = items.lastIndex,
addDefaultPadding = false,
backgroundColor = TangemTheme.colors.background.primary,
),
)
.testTag(BuyTokenScreenTestTags.LAZY_LIST_ITEM)
.semantics { lazyListItemPosition = index },
)
}
}

View file

@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
@ -14,6 +15,7 @@ import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
import com.tangem.core.ui.components.buttons.actions.ActionButtonContent
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.MainScreenTestTags
/**
[REDACTED_AUTHOR]
@ -48,7 +50,7 @@ internal fun MultiCurrencyAction(
paddingBetweenIconAndText = 4.dp,
)
},
modifier = modifier,
modifier = modifier.testTag(MainScreenTestTags.MULTI_CURRENCY_ACTION_BUTTON),
color = TangemTheme.colors.button.secondary,
)
}