Updated on 2026-08-14
This commit is contained in:
parent
1755406d31
commit
410253dc5a
6 changed files with 225 additions and 25 deletions
|
|
@ -4,10 +4,6 @@ import com.tangem.common.BaseTestCase
|
|||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onMarketsTooltipScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
|
@ -47,7 +43,7 @@ fun BaseTestCase.synchronizeAddresses(balance: String) {
|
|||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
onMainScreen { totalBalanceText.assertTextContains(balance) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ package com.tangem.screens
|
|||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.hasLazyListItemPosition
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.test.NotificationTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
|
@ -72,6 +73,24 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val totalBalanceContainer: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.WALLET_LIST_ITEM)
|
||||
}
|
||||
|
||||
val totalBalanceMenuRenameWallet: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.TOTAL_BALANCE_MENU_ITEM)
|
||||
hasText(getResourceString(R.string.common_rename))
|
||||
}
|
||||
|
||||
val totalBalanceMenuDeleteWallet: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.TOTAL_BALANCE_MENU_ITEM)
|
||||
hasText(getResourceString(R.string.common_delete))
|
||||
}
|
||||
|
||||
val totalBalanceText: KNode = child {
|
||||
hasParent(withTestTag(MainScreenTestTags.WALLET_BALANCE))
|
||||
}
|
||||
|
||||
/**
|
||||
* Find token list item with title and address
|
||||
*/
|
||||
|
|
@ -86,19 +105,6 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find node with wallet balance using lazyList. This construction doesn't affect next step with lazyList.
|
||||
*/
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun walletBalance(): KNode {
|
||||
return lazyList.childWith<LazyListItemNode> {
|
||||
hasAnyDescendant(withTestTag(MainScreenTestTags.WALLET_LIST_ITEM))
|
||||
}.child<KNode> {
|
||||
hasTestTag(MainScreenTestTags.WALLET_BALANCE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun organizeTokensButton(): KNode {
|
||||
return lazyList.childWith<LazyListItemNode> {
|
||||
|
|
@ -129,6 +135,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
fun KNode.assertIsUnreachable() {
|
||||
this {
|
||||
hasAnyAncestor(withText(getResourceString(R.string.common_unreachable)))
|
||||
assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This assertion is required to properly verify the token's absence in the semantic tree.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tests.balance
|
||||
|
||||
import androidx.compose.ui.test.longClick
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class TotalBalanceLongTapTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@AllureId("3965")
|
||||
@DisplayName("Total balance: check long tap on block without biometry")
|
||||
fun whenBiometryIsOffTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Long tap on total balance block") {
|
||||
onMainScreen {
|
||||
totalBalanceContainer.performTouchInput {
|
||||
longClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Rename' button is not displayed") {
|
||||
onMainScreen { totalBalanceMenuRenameWallet.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Delete' button is not displayed") {
|
||||
onMainScreen { totalBalanceMenuDeleteWallet.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.tangem.tests.balance
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
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 TotalBalanceUnavailableTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@AllureId("148")
|
||||
@DisplayName("Total balance: check dash sign when addresses are not derived")
|
||||
fun whenDerivationsDoesNotSyncedTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Do not synchronize addresses") {
|
||||
onMainScreen { synchronizeAddressesButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3993")
|
||||
@DisplayName("Total balance: check dash sign when network is unreachable")
|
||||
fun whenNetworkIsUnreachableTest() {
|
||||
val scenarioName = "eth_network_balance"
|
||||
val scenarioState = "Unreachable"
|
||||
val tokenTitle = "Ethereum"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 1).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3994")
|
||||
@DisplayName("Total balance: check dash sign when quotes are failed")
|
||||
fun whenQuotesAreFailedTest() {
|
||||
val scenarioName = "quotes_api"
|
||||
val scenarioState = "Error"
|
||||
val tokenTitle = "Ethereum"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 1).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3995")
|
||||
@DisplayName("Total balance: check dash sign when added custom token without rate")
|
||||
fun whenCustomTokenWithoutRateAddedTest() {
|
||||
val scenarioName = "user_tokens_api"
|
||||
val scenarioState = "CustomTokenAdded"
|
||||
val tokenTitle = "Myria"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 4).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,11 @@ object MainScreenTestTags {
|
|||
const val MORE_BUTTON = "MAIN_SCREEN_MORE_BUTTON"
|
||||
const val TOP_BAR = "MAIN_SCREEN_TOP_BAR"
|
||||
const val TOKEN_LIST_ITEM = "MAIN_SCREEN_TOKEN_LIST_ITEM"
|
||||
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"
|
||||
|
||||
const val WALLET_BALANCE = "MAIN_SCREEN_WALLET_BALANCE"
|
||||
const val TOTAL_BALANCE_MENU_ITEM = "MAIN_SCREEN_TOTAL_BALANCE_MENU_ITEM"
|
||||
const val TOTAL_BALANCE_CONTAINER = "MAIN_SCREEN_TOTAL_BALANCE_CONTAINER"
|
||||
}
|
||||
|
|
@ -164,6 +164,7 @@ private fun CardContainer(
|
|||
modifier = modifier
|
||||
.defaultMinSize(minHeight = TangemTheme.dimens.size108)
|
||||
.onSizeChanged { itemSize = it }
|
||||
.testTag(MainScreenTestTags.TOTAL_BALANCE_CONTAINER)
|
||||
.then(
|
||||
if (isLockedState || dropDownItems.isEmpty()) {
|
||||
Modifier
|
||||
|
|
@ -244,7 +245,9 @@ private fun ManageWalletContextMenu(
|
|||
private fun MenuItem(text: TextReference, imageVector: ImageVector, onClick: () -> Unit) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = text.resolveReference(), style = TangemTheme.typography.subtitle2) },
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
modifier = Modifier
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.testTag(MainScreenTestTags.TOTAL_BALANCE_MENU_ITEM),
|
||||
trailingIcon = { Icon(imageVector = imageVector, contentDescription = null) },
|
||||
onClick = onClick,
|
||||
colors = MenuDefaults.itemColors(
|
||||
|
|
@ -271,7 +274,7 @@ private fun Balance(state: WalletCardState, isBalanceHidden: Boolean, modifier:
|
|||
AnimatedContent(
|
||||
targetState = (state as? WalletCardState.Content)?.balance?.orMaskWithStars(isBalanceHidden).orEmpty(),
|
||||
label = "Update the balance",
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(MainScreenTestTags.WALLET_BALANCE),
|
||||
transitionSpec = {
|
||||
fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith
|
||||
fadeOut(animationSpec = tween(durationMillis = 90))
|
||||
|
|
@ -280,9 +283,7 @@ private fun Balance(state: WalletCardState, isBalanceHidden: Boolean, modifier:
|
|||
when (state) {
|
||||
is WalletCardState.Content -> {
|
||||
ResizableText(
|
||||
modifier = Modifier
|
||||
.defaultMinSize(minHeight = TangemTheme.dimens.size32)
|
||||
.testTag(MainScreenTestTags.WALLET_BALANCE),
|
||||
modifier = Modifier.defaultMinSize(minHeight = TangemTheme.dimens.size32),
|
||||
text = balance,
|
||||
fontSizeRange = FontSizeRange(min = 16.sp, max = TangemTheme.typography.h2.fontSize),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue