Updated on 2026-08-14
This commit is contained in:
commit
df1ddfaa36
7 changed files with 378 additions and 9 deletions
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsNode
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.semantics.getOrNull
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
|
||||
/** Returns the first non-blank text found in this node or its subtree (unmerged tree). */
|
||||
fun SemanticsNode.firstTextOrNull(): String? {
|
||||
config.getOrNull(SemanticsProperties.Text)
|
||||
?.firstOrNull()?.text?.takeIf { it.isNotBlank() }
|
||||
?.let { return it }
|
||||
children.forEach { child -> child.firstTextOrNull()?.let { return it } }
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the first text of every currently displayed node in this collection, in visual order
|
||||
* (top-to-bottom, then left-to-right). Non-displayed nodes and nodes without text are skipped.
|
||||
*/
|
||||
fun SemanticsNodeInteractionCollection.displayedTextsInVisualOrder(): List<String> {
|
||||
val count = fetchSemanticsNodes().size
|
||||
return (0 until count)
|
||||
.mapNotNull { index ->
|
||||
val interaction = get(index)
|
||||
if (runCatching { interaction.assertIsDisplayed() }.isFailure) return@mapNotNull null
|
||||
val node = interaction.fetchSemanticsNode()
|
||||
val text = node.firstTextOrNull() ?: return@mapNotNull null
|
||||
node.boundsInRoot to text
|
||||
}
|
||||
.sortedWith(compareBy({ it.first.top }, { it.first.left }))
|
||||
.map { it.second }
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.screens.onAddAndManageBottomSheet
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onOrganizeTokensScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
import org.junit.Assert.assertEquals
|
||||
|
||||
fun BaseTestCase.openOrganizeTokensScreen() {
|
||||
step("Swipe to 'Add & Manage' button") {
|
||||
|
|
@ -20,3 +23,29 @@ fun BaseTestCase.openOrganizeTokensScreen() {
|
|||
onAddAndManageBottomSheet { organizeTokensButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.getMainScreenTokensOrder(): List<String> {
|
||||
var tokens: List<String> = emptyList()
|
||||
step("Read displayed token titles from 'Main' screen") {
|
||||
awaitSuccess(timeoutMillis = WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
onMainScreen { tokens = getDisplayedTokenTitles() }
|
||||
require(tokens.isNotEmpty()) { "No token titles found on the main screen" }
|
||||
}
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
|
||||
fun BaseTestCase.assertOrganizeTokensMatch(expectedTokens: List<String>) {
|
||||
step("Open 'Organize tokens' bottom-sheet") {
|
||||
onMainScreen { clickDisplayedAddAndManageButton() }
|
||||
onAddAndManageBottomSheet { organizeTokensButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Organize tokens' list matches the main screen order") {
|
||||
onOrganizeTokensScreen {
|
||||
assertEquals(expectedTokens, getDisplayedTokenTitles())
|
||||
}
|
||||
}
|
||||
step("Return to 'Main' screen") {
|
||||
onOrganizeTokensScreen { cancelButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,21 @@ fun BaseTestCase.addNewCardWallet(mockContent: MockContent) {
|
|||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.addNewCardWalletWithoutSync(mockContent: MockContent) {
|
||||
step("Click 'More' button on TopBar") {
|
||||
onMainScreenTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
MockProvider.setMocks(mockContent)
|
||||
step("Click on 'Add Wallet' button (scans a new hardware wallet)") {
|
||||
onDetailsScreen { addWalletButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Main' screen is displayed with the new wallet") {
|
||||
composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_VERY_LONG) {
|
||||
runCatching { onMainScreenTopBar { moreButton.assertIsDisplayed() } }.isSuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.clickDisplayedTokenOnMain(tokenName: String) {
|
||||
step("Click on token '$tokenName' on the visible wallet") {
|
||||
onMainScreen { clickDisplayedToken(tokenName) }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.test.*
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.displayedTextsInVisualOrder
|
||||
import com.tangem.common.extensions.firstTextOrNull
|
||||
import com.tangem.common.extensions.getQuantityString
|
||||
import com.tangem.common.extensions.hasLazyListItemPosition
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
|
|
@ -14,6 +17,7 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
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 kotlin.math.abs
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
import com.tangem.core.res.R as CoreResR
|
||||
|
|
@ -121,16 +125,75 @@ class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteracti
|
|||
error("Token '$tokenName' is not displayed on the current wallet page")
|
||||
}
|
||||
|
||||
// Adjacent pager pages stay mounted; swipe the wallet card that's actually on-screen.
|
||||
/**
|
||||
* Switches to the previous/next wallet in the pager. A horizontal swipe is a silent no-op unless
|
||||
* the collapsing balance header is fully expanded and pinned to the top, so we retry: swipe, and
|
||||
* whenever the wallet identity doesn't change, expand the header and try again.
|
||||
*/
|
||||
fun swipeToAdjacentWallet(toPrevious: Boolean) {
|
||||
val nodes = semanticsProvider.onAllNodes(withTestTag(MainScreenTestTags.WALLET_LIST_ITEM))
|
||||
for (i in 0 until nodes.fetchSemanticsNodes().size) {
|
||||
val swiped = runCatching {
|
||||
nodes[i].assertIsDisplayed()
|
||||
nodes[i].performTouchInput { if (toPrevious) swipeRight() else swipeLeft() }
|
||||
}.isSuccess
|
||||
if (swiped) return
|
||||
val before = displayedWalletIdentity()
|
||||
repeat(times = WALLET_SWITCH_ATTEMPTS) {
|
||||
swipeCurrentPage(toPrevious)
|
||||
val now = displayedWalletIdentity()
|
||||
if (now != null && now != before) return
|
||||
expandCollapsingHeader()
|
||||
}
|
||||
error("Wallet did not switch from '$before' after $WALLET_SWITCH_ATTEMPTS attempts")
|
||||
}
|
||||
|
||||
// Expand only *after* a swipe that didn't page: if the header is already pinned, a swipe-down here
|
||||
// would trigger pull-to-refresh and un-pin it, breaking the horizontal swipe.
|
||||
private fun expandCollapsingHeader() {
|
||||
onScreenPage()?.performTouchInput {
|
||||
swipeDown(startY = visibleSize.height * 0.3f, endY = visibleSize.height * 0.8f)
|
||||
}
|
||||
}
|
||||
|
||||
private fun swipeCurrentPage(toPrevious: Boolean) {
|
||||
onScreenPage()?.performTouchInput { if (toPrevious) swipeRight() else swipeLeft() }
|
||||
}
|
||||
|
||||
// Identity = title + balance: a still-restoring wallet has no CARD_TITLE but always a WALLET_BALANCE.
|
||||
private fun displayedWalletIdentity(): String? {
|
||||
val title = onScreenPageChild(withTestTag(MainScreenTestTags.CARD_TITLE))?.firstText()
|
||||
val balance = onScreenPageChild(withTestTag(MainScreenTestTags.WALLET_BALANCE))?.firstText()
|
||||
return listOfNotNull(title, balance).joinToString(separator = "|").ifBlank { null }
|
||||
}
|
||||
|
||||
/**
|
||||
* The full-width pager-page container currently on-screen. The pager keeps adjacent pages composed
|
||||
* off-screen at ±pageWidth (so [assertIsDisplayed] can't tell them apart), hence selection by
|
||||
* geometry: the on-screen page is the only one whose left edge is within half a page of x=0.
|
||||
*/
|
||||
private fun onScreenPage(): SemanticsNodeInteraction? =
|
||||
firstNodeMatching(withTestTag(MainScreenTestTags.SCREEN_CONTAINER), useUnmergedTree = false) {
|
||||
abs(it.left) < it.width / 2f
|
||||
}
|
||||
|
||||
/** A node matching [matcher] whose centre lies within the on-screen page (skips zero-size off-screen copies). */
|
||||
private fun onScreenPageChild(matcher: SemanticsMatcher): SemanticsNodeInteraction? {
|
||||
val page = onScreenPage()?.fetchSemanticsNode()?.boundsInRoot ?: return null
|
||||
return firstNodeMatching(matcher) {
|
||||
it.width > 0f && it.height > 0f && it.center.x >= page.left && it.center.x < page.right
|
||||
}
|
||||
}
|
||||
|
||||
private fun SemanticsNodeInteraction.firstText(): String? = fetchSemanticsNode().firstTextOrNull()
|
||||
|
||||
// Single geometry primitive behind the pager helpers: the first node matching [matcher] whose
|
||||
// bounds satisfy [predicate]. Replaces the per-caller onAllNodes(...)[i] loops.
|
||||
private fun firstNodeMatching(
|
||||
matcher: SemanticsMatcher,
|
||||
useUnmergedTree: Boolean = true,
|
||||
predicate: (Rect) -> Boolean,
|
||||
): SemanticsNodeInteraction? {
|
||||
val nodes = semanticsProvider.onAllNodes(matcher, useUnmergedTree = useUnmergedTree)
|
||||
repeat(times = nodes.fetchSemanticsNodes().size) { index ->
|
||||
val node = nodes[index]
|
||||
val matches = runCatching { predicate(node.fetchSemanticsNode().boundsInRoot) }.getOrDefault(false)
|
||||
if (matches) return node
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val restoringProgressText: KNode = child {
|
||||
|
|
@ -380,6 +443,23 @@ class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteracti
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
/** Collapses the header, scrolls to and clicks the 'Add & manage' button on the on-screen wallet page. */
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun clickDisplayedAddAndManageButton() {
|
||||
val container = onScreenPage() ?: error("No on-screen wallet page found")
|
||||
// Best-effort: the button is a footer outside the scrollable list, so performScrollToNode can
|
||||
// throw when it's already visible — that must not abort the click below.
|
||||
runCatching {
|
||||
container.performTouchInput {
|
||||
swipeUp(startY = visibleSize.height * 0.6f, endY = visibleSize.height * 0.1f)
|
||||
}
|
||||
container.performScrollToNode(withTestTag(MainScreenTestTags.ADD_AND_MANAGE_BUTTON))
|
||||
}
|
||||
val button = onScreenPageChild(withTestTag(MainScreenTestTags.ADD_AND_MANAGE_BUTTON))
|
||||
?: error("'Add & manage' button is not displayed on the current wallet page")
|
||||
button.performClick()
|
||||
}
|
||||
|
||||
val searchThroughMarketPlaceholder: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_search_title_placeholder))
|
||||
useUnmergedTree = true
|
||||
|
|
@ -485,6 +565,21 @@ class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteracti
|
|||
useUnmergedTree = true
|
||||
}.assertIsDisplayed()
|
||||
}
|
||||
|
||||
/**
|
||||
* Token titles displayed on the current wallet page, in visual order. Reads the
|
||||
* [TokenElementsTestTags.TOKEN_TITLE] rows so network group headers (which share the
|
||||
* TOKEN_LIST_ITEM tag) are excluded, keeping the result symmetric with the 'Organize tokens' reader.
|
||||
*/
|
||||
fun getDisplayedTokenTitles(): List<String> =
|
||||
semanticsProvider.onAllNodes(
|
||||
withTestTag(TokenElementsTestTags.TOKEN_TITLE),
|
||||
useUnmergedTree = true,
|
||||
).displayedTextsInVisualOrder()
|
||||
|
||||
private companion object {
|
||||
const val WALLET_SWITCH_ATTEMPTS = 4
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.geometry.lerp
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.hasAnyDescendant
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.displayedTextsInVisualOrder
|
||||
import com.tangem.common.extensions.hasLazyListItemPosition
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.OrganizeTokensScreenTestTags
|
||||
|
|
@ -14,12 +18,13 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
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.hasAnyAncestor as withAnyAncestor
|
||||
import androidx.compose.ui.test.hasAnyChild as withAnyChild
|
||||
import androidx.compose.ui.test.hasAnySibling as withAnySibling
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
class OrganizeTokensPageObject(private val semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<OrganizeTokensPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
// region TopBar
|
||||
|
|
@ -93,6 +98,15 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
}
|
||||
}
|
||||
|
||||
// Read TOKEN_TITLE nodes, not the outer TOKEN_LIST_ITEM: the item container here doesn't merge its
|
||||
// descendants, so the nested title Text never surfaces on the item node's semantics.
|
||||
fun getDisplayedTokenTitles(): List<String> =
|
||||
semanticsProvider.onAllNodes(
|
||||
withTestTag(TokenElementsTestTags.TOKEN_TITLE) and
|
||||
withAnyAncestor(withTestTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST)),
|
||||
useUnmergedTree = true,
|
||||
).displayedTextsInVisualOrder()
|
||||
|
||||
fun tokenDraggableButton(tokenTitle: String): KNode {
|
||||
return lazyList.child {
|
||||
hasTestTag(OrganizeTokensScreenTestTags.DRAGGABLE_IMAGE)
|
||||
|
|
@ -108,6 +122,47 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder by synthesizing a drag on the source row's handle: down, hold, step to the destination
|
||||
// centre, lift — a single `swipe` won't engage the reorder detector. Only valid within one network
|
||||
// group (isValidDropTarget), so source and destination must share a group.
|
||||
fun dragToken(source: String, destination: String) {
|
||||
val sourceHandle = semanticsProvider.onNode(dragHandleMatcher(source), useUnmergedTree = true)
|
||||
val sourceNode = sourceHandle.fetchSemanticsNode()
|
||||
val destinationNode = semanticsProvider
|
||||
.onNode(tokenItemMatcher(destination), useUnmergedTree = true)
|
||||
.fetchSemanticsNode()
|
||||
|
||||
// performTouchInput coordinates are local to the source node; express both endpoints there.
|
||||
val origin = sourceNode.positionInRoot
|
||||
val start = sourceNode.boundsInRoot.center - origin
|
||||
val end = destinationNode.boundsInRoot.center - origin
|
||||
|
||||
sourceHandle.performTouchInput {
|
||||
down(start)
|
||||
advanceEventTime(DRAG_HOLD_MS)
|
||||
repeat(times = DRAG_STEPS) { step ->
|
||||
moveTo(lerp(start = start, stop = end, fraction = (step + 1).toFloat() / DRAG_STEPS))
|
||||
advanceEventTime(DRAG_STEP_MS)
|
||||
}
|
||||
up()
|
||||
}
|
||||
}
|
||||
|
||||
// The drag handle sits under an untagged wrapper inside TOKEN_NON_FIAT_BLOCK, so anchor on the
|
||||
// enclosing TOKEN_LIST_ITEM (one handle + one title per item) instead of the direct parent.
|
||||
private fun dragHandleMatcher(tokenTitle: String): SemanticsMatcher =
|
||||
withTestTag(OrganizeTokensScreenTestTags.DRAGGABLE_IMAGE) and
|
||||
withAnyAncestor(tokenItemMatcher(tokenTitle))
|
||||
|
||||
private fun tokenItemMatcher(tokenTitle: String): SemanticsMatcher =
|
||||
withTestTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM) and hasAnyDescendant(withText(tokenTitle))
|
||||
|
||||
private companion object {
|
||||
const val DRAG_HOLD_MS = 200L
|
||||
const val DRAG_STEPS = 16
|
||||
const val DRAG_STEP_MS = 16L
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onOrganizeTokensScreen(function: OrganizeTokensPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.tests.main
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.scenarios.addNewCardWalletWithoutSync
|
||||
import com.tangem.scenarios.assertOrganizeTokensMatch
|
||||
import com.tangem.scenarios.getMainScreenTokensOrder
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.switchToPreviousWallet
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onAddAndManageBottomSheet
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onOrganizeTokensScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.content.Wallet2MockContent
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class OrganizeTokensTest : BaseTestCase() {
|
||||
|
||||
@AllureId("71")
|
||||
@DisplayName("Organize tokens: Correct tokens list displaying for current wallet")
|
||||
@Test
|
||||
fun organizeTokensCorrectTokensListDisplaying() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Add a second card wallet") {
|
||||
addNewCardWalletWithoutSync(Wallet2MockContent)
|
||||
}
|
||||
step("Switch to first wallet Main screen") {
|
||||
switchToPreviousWallet()
|
||||
}
|
||||
|
||||
val firstWalletTokens = getMainScreenTokensOrder()
|
||||
assertOrganizeTokensMatch(firstWalletTokens)
|
||||
|
||||
step("Switch to second wallet Main screen") {
|
||||
onMainScreen { swipeToAdjacentWallet(toPrevious = false) }
|
||||
}
|
||||
|
||||
val secondWalletTokens = getMainScreenTokensOrder()
|
||||
assertOrganizeTokensMatch(secondWalletTokens)
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("2753")
|
||||
@DisplayName("Organize tokens: Tokens order changing")
|
||||
@Test
|
||||
fun organizeTokensOrderChanging() {
|
||||
setupHooks().run{
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Organize tokens' bottom-sheet") {
|
||||
onMainScreen { clickDisplayedAddAndManageButton() }
|
||||
onAddAndManageBottomSheet { organizeTokensButton.clickWithAssertion() }
|
||||
}
|
||||
step("Drag the 3rd token onto the 2nd position and assert the new order") {
|
||||
onOrganizeTokensScreen {
|
||||
val sourceIndex = 2
|
||||
val destinationIndex = 1
|
||||
val before = getDisplayedTokenTitles()
|
||||
require(before.size > sourceIndex && before.size > destinationIndex) {
|
||||
"Expected at least ${maxOf(sourceIndex, destinationIndex) + 1} tokens to reorder, but got ${before.size}: $before"
|
||||
}
|
||||
dragToken(source = before[sourceIndex], destination = before[destinationIndex])
|
||||
val expected = before.toMutableList().apply {
|
||||
add(destinationIndex, removeAt(sourceIndex))
|
||||
}
|
||||
assertEquals(expected, getDisplayedTokenTitles())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,17 @@ import com.tangem.common.BaseTestCase
|
|||
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.addNewCardWalletWithoutSync
|
||||
import com.tangem.scenarios.getMainScreenTokensOrder
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.content.Wallet2MockContent
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
|
|
@ -48,4 +53,54 @@ class TokenListTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
|
||||
@AllureId("177")
|
||||
@DisplayName("Main: token list differs after switching to a second wallet")
|
||||
@Test
|
||||
fun tokenListChangedAfterSwitchingWalletTest() {
|
||||
val userTokensState = "ReducedTokens"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
|
||||
val firstWalletTokens = getMainScreenTokensOrder()
|
||||
|
||||
step("Set WireMock scenario: '$USER_TOKENS_API_SCENARIO' to state: '$userTokensState'") {
|
||||
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, userTokensState)
|
||||
}
|
||||
step("Add a second card wallet") {
|
||||
addNewCardWalletWithoutSync(Wallet2MockContent)
|
||||
}
|
||||
|
||||
val secondWalletTokens = getMainScreenTokensOrder()
|
||||
|
||||
step("Assert both wallets exposed a non-empty token list") {
|
||||
assertTrue(
|
||||
"First wallet token list should not be empty",
|
||||
firstWalletTokens.isNotEmpty(),
|
||||
)
|
||||
assertTrue(
|
||||
"Second wallet token list should not be empty",
|
||||
secondWalletTokens.isNotEmpty(),
|
||||
)
|
||||
}
|
||||
step("Assert the two wallets show different token lists") {
|
||||
assertNotEquals(
|
||||
"Expected the second wallet's token list to differ from the first " +
|
||||
"(first=$firstWalletTokens, second=$secondWalletTokens)",
|
||||
firstWalletTokens,
|
||||
secondWalletTokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue