127 lines
No EOL
4.4 KiB
Kotlin
127 lines
No EOL
4.4 KiB
Kotlin
package com.tangem.common.extensions
|
|
|
|
import androidx.compose.ui.semantics.SemanticsNode
|
|
import androidx.compose.ui.semantics.SemanticsProperties
|
|
import androidx.compose.ui.test.SemanticsMatcher
|
|
import androidx.compose.ui.test.onAllNodesWithText
|
|
import com.tangem.common.BaseTestCase
|
|
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
|
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 BaseTestCase.assertSnackbarWithText(text: String, timeoutMs: Long = WAIT_UNTIL_TIMEOUT) {
|
|
composeTestRule.waitUntil(timeoutMillis = timeoutMs) {
|
|
composeTestRule
|
|
.onAllNodesWithText(text, substring = true)
|
|
.fetchSemanticsNodes()
|
|
.isNotEmpty()
|
|
}
|
|
}
|
|
|
|
fun assertElementDoesNotExist(
|
|
elementProvider: () -> KNode,
|
|
elementDescription: String,
|
|
) {
|
|
try {
|
|
elementProvider().assertExists()
|
|
throw AssertionError("$elementDescription should not exist but was found")
|
|
} catch (e: AssertionError) {
|
|
val isNotFoundError = e.message?.let { message ->
|
|
message.contains("No node found") ||
|
|
message.contains("scrollable container") ||
|
|
message.contains("There are no existing nodes") ||
|
|
message.contains("There are no existing nodes for that selector")
|
|
} ?: false
|
|
if (isNotFoundError) {
|
|
return
|
|
} else {
|
|
throw e
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Any.assertIsDimmed(expectedValue: Boolean = true) {
|
|
val matcher = SemanticsMatcher.expectValue(IsDimmedKey, expectedValue)
|
|
when (this) {
|
|
is KNode, is LazyListItemNode -> this.assert(matcher)
|
|
else -> throw IllegalArgumentException("Unsupported type: ${this::class}")
|
|
}
|
|
}
|
|
|
|
fun Any.assertHasBadge(expectedValue: Boolean = true) {
|
|
val matcher = SemanticsMatcher.expectValue(HasBadgeKey, expectedValue)
|
|
when (this) {
|
|
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 content from a [KNode]'s semantics.
|
|
* Useful when the displayed value is dynamic and you need to capture it for later assertions.
|
|
*/
|
|
fun KNode.extractText(): String {
|
|
val node = delegate.interaction.semanticsNodeInteraction.fetchSemanticsNode(
|
|
"Failed to extract text from KNode",
|
|
)
|
|
return extractText(node) ?: error("Node does not contain SemanticsProperties.Text")
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
val multiplier = when {
|
|
text.contains('T', ignoreCase = true) -> 1_000_000_000_000.0
|
|
text.contains('B', ignoreCase = true) -> 1_000_000_000.0
|
|
text.contains('M', ignoreCase = true) -> 1_000_000.0
|
|
text.contains('K', ignoreCase = true) -> 1_000.0
|
|
else -> 1.0
|
|
}
|
|
val number = text.replace("[^0-9.]".toRegex(), "").toDoubleOrNull() ?: return null
|
|
return number * multiplier
|
|
} |