Updated on 2026-08-14
This commit is contained in:
parent
ea180bc503
commit
79aaeaf74f
10 changed files with 429 additions and 2 deletions
|
|
@ -30,6 +30,8 @@ import kotlinx.coroutines.runBlocking
|
|||
import org.junit.Rule
|
||||
import org.junit.rules.RuleChain
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.rules.TestWatcher
|
||||
import org.junit.runner.Description
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class BaseTestCase : TestCase(
|
||||
|
|
@ -68,6 +70,12 @@ abstract class BaseTestCase : TestCase(
|
|||
*/
|
||||
val composeTestRule = createEmptyComposeRule()
|
||||
|
||||
private val semanticTreePrinterRule = object : TestWatcher() {
|
||||
override fun failed(e: Throwable?, description: Description?) {
|
||||
runCatching { printAllRoots() }
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val ruleChain: TestRule = RuleChain
|
||||
|
|
@ -76,6 +84,7 @@ abstract class BaseTestCase : TestCase(
|
|||
.around(permissionRule)
|
||||
.around(apiEnvironmentRule)
|
||||
.around(composeTestRule)
|
||||
.around(semanticTreePrinterRule)
|
||||
|
||||
/**
|
||||
* Initialization order is important:
|
||||
|
|
@ -140,6 +149,16 @@ abstract class BaseTestCase : TestCase(
|
|||
.printToLog(tag, maxDepth)
|
||||
}
|
||||
|
||||
fun printAllRoots(
|
||||
tag: String = "ComposeTree",
|
||||
) {
|
||||
val roots = composeTestRule.onAllNodes(isRoot())
|
||||
val count = roots.fetchSemanticsNodes().size
|
||||
repeat(count) { index ->
|
||||
roots[index].printToLog("$tag[$index]")
|
||||
}
|
||||
}
|
||||
|
||||
fun waitForIdle() = composeTestRule.waitForIdle()
|
||||
|
||||
private fun applicationInjectionRule(): ApplicationInjectionExecutionRule {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsNode
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.components.buttons.actions.HasBadgeKey
|
||||
import com.tangem.core.ui.components.buttons.actions.IsDimmedKey
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
fun assertElementDoesNotExist(
|
||||
elementProvider: () -> KNode,
|
||||
|
|
@ -42,4 +46,51 @@ fun Any.assertHasBadge(expectedValue: Boolean = true) {
|
|||
is KNode, is LazyListItemNode -> this.assert(matcher)
|
||||
else -> throw IllegalArgumentException("Unsupported type: ${this::class}")
|
||||
}
|
||||
}
|
||||
|
||||
fun List<SemanticsNode>.assertSortedByVolumeDescending() {
|
||||
val volumes = this.mapNotNull { parseVolume(it) }
|
||||
assertFalse("Trading volumes list should not be empty", volumes.isEmpty())
|
||||
assertTrue(
|
||||
"Exchanges list should be sorted by volume in descending order",
|
||||
volumes == volumes.sortedDescending(),
|
||||
)
|
||||
}
|
||||
|
||||
fun List<SemanticsNode>.assertExchangeTypesAreCexOrDex() {
|
||||
assertFalse("Exchange types list should not be empty", isEmpty())
|
||||
forEach { node ->
|
||||
val text = extractText(node)
|
||||
assertTrue(
|
||||
"Exchange type should be 'CEX' or 'DEX', but found: $text",
|
||||
text == "CEX" || text == "DEX",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun List<SemanticsNode>.assertTrustScoresValid() {
|
||||
val validScores = setOf("Risky", "Caution", "Trusted")
|
||||
assertFalse("Trust scores list should not be empty", isEmpty())
|
||||
forEach { node ->
|
||||
val text = extractText(node)
|
||||
assertTrue(
|
||||
"Trust score should be one of $validScores, but found: $text",
|
||||
text in validScores,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the text value from a semantic node's config.
|
||||
*/
|
||||
private fun extractText(node: SemanticsNode): String? {
|
||||
if (SemanticsProperties.Text in node.config) {
|
||||
return node.config[SemanticsProperties.Text].firstOrNull()?.text
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun parseVolume(node: SemanticsNode): Double? {
|
||||
val text = extractText(node) ?: return null
|
||||
return text.replace("[^0-9.]".toRegex(), "").toDoubleOrNull()
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeMarketsBlock
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onMarketsExchangesScreen
|
||||
import com.tangem.screens.onMarketsScreen
|
||||
import com.tangem.screens.onMarketsTokenDetailsScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
|
@ -23,4 +27,50 @@ fun BaseTestCase.openMarketTokenDetailsScreen(blockchainName: String, tokenName:
|
|||
waitForIdle()
|
||||
onMarketsTokenDetailsScreen { tokenWithTitle(tokenName).clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.assertMarketsExchangesScreen() {
|
||||
step("Assert 'Title' is displayed") {
|
||||
onMarketsExchangesScreen { exchangesTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Exchange name' is displayed") {
|
||||
onMarketsExchangesScreen { exchangeName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Logo' is displayed") {
|
||||
onMarketsExchangesScreen { exchangeLogo.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Exchange type' is displayed") {
|
||||
onMarketsExchangesScreen { exchangeType.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Trust score' is displayed") {
|
||||
onMarketsExchangesScreen { trustScore.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openMarketsScreen() {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Markets' screen") {
|
||||
swipeMarketsBlock(SwipeDirection.UP)
|
||||
waitForIdle()
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openMarketsExchangesScreen(tokenName: String) {
|
||||
openMarketsScreen()
|
||||
step("Click on '$tokenName' token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Scroll down") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on 'Listed on exchanges' block") {
|
||||
onMarketsScreen { listedOnBlockContainer.performClick() }
|
||||
waitForIdle()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsNode
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.hasParent
|
||||
import androidx.compose.ui.test.hasTestTag
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
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
|
||||
|
||||
class MarketsExchangesPageObject(private val provider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<MarketsExchangesPageObject>(semanticsProvider = provider) {
|
||||
|
||||
fun allTradingVolumeNodes(): List<SemanticsNode> =
|
||||
provider
|
||||
.onAllNodes(hasTestTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT_TEXT))
|
||||
.fetchSemanticsNodes()
|
||||
|
||||
fun allExchangeTypeNodes(): List<SemanticsNode> =
|
||||
provider
|
||||
.onAllNodes(hasParent(hasParent(hasTestTag(TokenElementsTestTags.TOKEN_PRICE))))
|
||||
.fetchSemanticsNodes()
|
||||
|
||||
fun allTrustScoreNodes(): List<SemanticsNode> =
|
||||
provider
|
||||
.onAllNodes(hasParent(hasTestTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT)))
|
||||
.fetchSemanticsNodes()
|
||||
|
||||
val exchangesTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.markets_token_details_exchanges_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val exchangeName: KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||
}
|
||||
|
||||
val exchangeLogo: KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_ICON)
|
||||
}
|
||||
|
||||
val tradingVolume: KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT)
|
||||
}
|
||||
|
||||
val exchangeType: KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_PRICE)
|
||||
}
|
||||
|
||||
val trustScore: KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT)
|
||||
}
|
||||
|
||||
val tryAgainButton: KNode = child {
|
||||
hasText(getResourceString(R.string.alert_button_try_again))
|
||||
}
|
||||
|
||||
val errorMessage: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_loading_error_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onMarketsExchangesScreen(function: MarketsExchangesPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -35,6 +35,25 @@ class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val listedOnExchangesCount: KNode = child {
|
||||
hasTestTag(MarketsTestTags.LISTED_ON_EXCHANGES_COUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val listedOnBlockContainer: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_token_details_listed_on), substring = true)
|
||||
}
|
||||
|
||||
val listedOnEmptyText: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_token_details_empty_exchanges))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val seeAllButton: KNode = child {
|
||||
hasText(getResourceString(com.tangem.core.ui.R.string.common_see_all))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenWithTitle(title: String): KNode {
|
||||
return child {
|
||||
hasTestTag(MarketsTestTags.TOKENS_LIST_ITEM)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
package com.tangem.tests.markets
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.annotations.ApiEnv
|
||||
import com.tangem.common.annotations.ApiEnvConfig
|
||||
import com.tangem.common.extensions.*
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.onMarketsExchangesScreen
|
||||
import com.tangem.screens.onMarketsScreen
|
||||
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 MarketsExchangesTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("58")
|
||||
@DisplayName("Markets: verify exchanges list screen")
|
||||
fun marketsExchangesListTest() {
|
||||
val tokenName = "Solana"
|
||||
setupHooks().run {
|
||||
step("Open 'Markets' screen") {
|
||||
openMarketsScreen()
|
||||
}
|
||||
step("Click on 'See all' button") {
|
||||
onMarketsScreen { seeAllButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on '$tokenName' token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Scroll down") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on 'Listed on exchanges' block") {
|
||||
onMarketsScreen { listedOnBlockContainer.performClick() }
|
||||
}
|
||||
step("Assert 'Exchanges' list screen is displayed") {
|
||||
assertMarketsExchangesScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("56")
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@DisplayName("Markets: verify exchanges block is displayed in token details")
|
||||
fun marketsExchangesBlockDisplayedTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Markets' screen") {
|
||||
swipeMarketsBlock(SwipeDirection.UP)
|
||||
waitForIdle()
|
||||
}
|
||||
step("Click on '$tokenName' token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Scroll down") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Assert 'Listed on exchanges' block has title") {
|
||||
onMarketsScreen { listedOnBlockContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Listed on exchanges' block has exchanges count") {
|
||||
onMarketsScreen { listedOnExchangesCount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Listed on exchanges' block has arrow button") {
|
||||
onMarketsScreen { listedOnBlockContainer.assertHasClickAction() }
|
||||
}
|
||||
step("Tap on 'Listed on exchanges' block and navigate to exchanges list") {
|
||||
onMarketsScreen { listedOnBlockContainer.performClick() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Assert 'Exchanges' list screen is displayed") {
|
||||
assertMarketsExchangesScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("60")
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@DisplayName("Markets: verify exchanges list is sorted by volume descending")
|
||||
fun marketsExchangesListSortedByVolumeTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
setupHooks().run {
|
||||
step("Open 'Markets Exhanges Screen with token: $tokenName'") {
|
||||
openMarketsExchangesScreen(tokenName)
|
||||
}
|
||||
step("Assert exchanges are sorted by trading volume in descending order") {
|
||||
flakySafely {
|
||||
onMarketsExchangesScreen { allTradingVolumeNodes().assertSortedByVolumeDescending() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("61")
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@DisplayName("Markets: verify exchange types are CEX or DEX")
|
||||
fun marketsExchangesTypeTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
setupHooks().run {
|
||||
step("Open 'Markets Exhanges Screen with token: $tokenName'") {
|
||||
openMarketsExchangesScreen(tokenName)
|
||||
}
|
||||
step("Assert exchange types list is not empty and all types are 'CEX' or 'DEX'") {
|
||||
flakySafely {
|
||||
onMarketsExchangesScreen { allExchangeTypeNodes().assertExchangeTypesAreCexOrDex() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("62")
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@DisplayName("Markets: verify exchange trust scores are valid")
|
||||
fun marketsExchangesTrustScoreTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
setupHooks().run {
|
||||
step("Open 'Markets Exhanges Screen with token: $tokenName'") {
|
||||
openMarketsExchangesScreen(tokenName)
|
||||
}
|
||||
step("Assert trust scores list is not empty and all scores are valid") {
|
||||
flakySafely {
|
||||
onMarketsExchangesScreen { allTrustScoreNodes().assertTrustScoresValid() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("57")
|
||||
@DisplayName("Markets: verify empty exchanges state")
|
||||
fun marketsExchangesEmptyTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
val scenarioName = "coins_bitcoin"
|
||||
setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = "EmptyExchanges")
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Markets Exhanges Screen with token: $tokenName'") {
|
||||
openMarketsExchangesScreen(tokenName)
|
||||
}
|
||||
step("Assert 'Listed on exchanges' block shows no exchanges") {
|
||||
onMarketsScreen { listedOnEmptyText.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("59")
|
||||
@DisplayName("Markets: verify exchanges error state and retry")
|
||||
fun marketsExchangesErrorStateTest() {
|
||||
val tokenName = "Bitcoin"
|
||||
val scenarioName = "bitcoin_exchange"
|
||||
setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = "Unreachable")
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Markets Exhanges Screen with token: $tokenName'") {
|
||||
openMarketsExchangesScreen(tokenName)
|
||||
}
|
||||
step("Assert 'Unable to load data' error state is displayed") {
|
||||
step("Assert 'Error message' is displayed") {
|
||||
onMarketsExchangesScreen { errorMessage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Try again button' is displayed") {
|
||||
onMarketsExchangesScreen { tryAgainButton.assertIsDisplayed() }
|
||||
}
|
||||
|
||||
}
|
||||
step("Set WireMock scenario '$scenarioName' to state 'Started'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = "Started")
|
||||
}
|
||||
step("Tap 'Try again' button") {
|
||||
onMarketsExchangesScreen { tryAgainButton.clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Assert 'Exchanges' list screen is displayed after retry") {
|
||||
assertMarketsExchangesScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,9 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -121,7 +124,7 @@ private fun FiatAmountText(
|
|||
isFlickering: Boolean = false,
|
||||
) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
modifier = modifier.semantics { testTag = TokenElementsTestTags.TOKEN_FIAT_AMOUNT_TEXT },
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ object MarketsTestTags {
|
|||
const val TOKENS_LIST = "MARKETS_TOKENS_LIST"
|
||||
const val TOKENS_LIST_ITEM = "MARKETS_TOKENS_LIST_ITEM"
|
||||
const val ADD_TO_PORTFOLIO_SWITCH = "MARKETS_ADD_TO_PORTFOLIO_SWITCH"
|
||||
const val LISTED_ON_EXCHANGES_COUNT = "MARKETS_LISTED_ON_EXCHANGES_COUNT"
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ object TokenElementsTestTags {
|
|||
const val TOKEN_ICON = "TOKEN_ICON"
|
||||
const val TOKEN_PRICE = "TOKEN_PRICE"
|
||||
const val TOKEN_FIAT_AMOUNT = "TOKEN_FIAT_AMOUNT"
|
||||
const val TOKEN_FIAT_AMOUNT_TEXT = "TOKEN_FIAT_AMOUNT_TEXT"
|
||||
const val TOKEN_CRYPTO_AMOUNT = "TOKEN_CRYPTO_AMOUNT"
|
||||
const val TOKEN_NON_FIAT_BLOCK = "TOKEN_NON_FIAT_BLOCK"
|
||||
const val TOKEN_YIELD_PROMO_BANNER = "TOKEN_YIELD_PROMO_BANNER"
|
||||
|
|
|
|||
|
|
@ -21,12 +21,15 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.block.information.InformationBlock
|
||||
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.MarketsTestTags
|
||||
import com.tangem.features.feed.ui.market.detailed.state.ListedOnUM
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
|
|
@ -99,7 +102,7 @@ internal fun ListedOnBlockPlaceholder(modifier: Modifier = Modifier) {
|
|||
private fun Description(state: ListedOnUM, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = state.description.resolveReference(),
|
||||
modifier = modifier,
|
||||
modifier = modifier.semantics { testTag = MarketsTestTags.LISTED_ON_EXCHANGES_COUNT },
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue