Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-01 09:12:45 +02:00
parent 383d42f6b3
commit 2110b5f541
10 changed files with 87 additions and 74 deletions

View file

@ -175,7 +175,10 @@ fun BaseTestCase.openDeviceSettingsScreen() {
onDetailsScreen { walletNameButton.performClick() }
}
step("Click on 'Device settings' button") {
onWalletSettingsScreen { deviceSettingsButton.clickWithAssertion() }
onWalletSettingsScreen {
scrollToDeviceSettings()
deviceSettingsButton.clickWithAssertion()
}
}
}

View file

@ -23,17 +23,11 @@ class DetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
hasText(getResourceString(R.string.wallet_connect_title))
}
private val walletBlock: KNode = child {
hasTestTag(DetailsScreenTestTags.SCREEN_ITEM)
}
val walletNameButton: KNode = walletBlock.child {
hasClickAction()
hasPosition(0)
}
val scanCardButton: KNode = walletBlock.child {
hasText(getResourceString(R.string.scan_card_settings_button))
// Match the wallet row by its own tag (not position-0 clickable, which races with the async-loading
// "Add Wallet" button and otherwise triggers a re-scan → "already saved" dialog).
val walletNameButton: KNode = child {
hasTestTag(DetailsScreenTestTags.USER_WALLET_ITEM)
useUnmergedTree = true
}
val buyTangemButton: KNode = child {

View file

@ -9,6 +9,7 @@ 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 DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<DialogPageObject>(semanticsProvider = semanticsProvider) {
@ -25,8 +26,10 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
hasTestTag(BaseDialogTestTags.TEXT)
}
// Tag is on the OutlineTextField wrapper; the editable node is its descendant with a SetText action.
val inputField: KNode = child {
hasTestTag(BaseDialogTestTags.TEXT_INPUT_FIELD)
hasSetTextAction()
hasAnyAncestor(withTestTag(BaseDialogTestTags.TEXT_INPUT_FIELD))
useUnmergedTree = true
}

View file

@ -1,5 +1,6 @@
package com.tangem.screens
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import com.tangem.common.BaseTestCase
import com.tangem.core.ui.test.TopAppBarTestTags
@ -9,6 +10,7 @@ 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
import androidx.compose.ui.test.hasText as withText
class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
@ -22,6 +24,31 @@ class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
hasTestTag(WalletSettingsScreenTestTags.SCREEN_ITEM)
}
// The Accounts section loads async and can push rows below the fold — scroll before asserting/clicking.
private val scrollableContainer: KNode = child {
hasTestTag(WalletSettingsScreenTestTags.SCREEN_CONTAINER)
}
@OptIn(ExperimentalTestApi::class)
fun scrollToText(text: String) = scrollableContainer { performScrollToNode(withText(text)) }
@OptIn(ExperimentalTestApi::class)
fun scrollToDeviceSettings() = scrollToText(getResourceString(R.string.card_settings_title))
@OptIn(ExperimentalTestApi::class)
fun scrollToLinkMoreCards() = scrollToText(getResourceString(R.string.details_row_title_create_backup))
@OptIn(ExperimentalTestApi::class)
fun scrollToReferralProgram() = scrollToText(getResourceString(R.string.details_referral_title))
@OptIn(ExperimentalTestApi::class)
fun scrollToForgetWallet() = scrollToText(getResourceString(R.string.settings_forget_wallet))
@OptIn(ExperimentalTestApi::class)
fun scrollToRenameButton() = scrollableContainer {
performScrollToNode(withTestTag(WalletSettingsScreenTestTags.RENAME_BUTTON))
}
val linkMoreCardsButton: KNode = walletSettingsItem.child {
hasText(getResourceString(R.string.details_row_title_create_backup))
}

View file

@ -1,11 +1,13 @@
package com.tangem.tests
import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.isDisplayedSafely
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.domain.models.scan.ProductType
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.screens.*
import dagger.hilt.android.testing.HiltAndroidTest
import io.qameta.allure.kotlin.AllureId
@ -23,7 +25,7 @@ class AppCurrencyTest : BaseTestCase() {
val appSettingsState = "AppSettings"
val targetCurrency = "EUR"
val targetSymbol = ""
val token = "Polygon"
val token = "Bitcoin"
setupHooks(
additionalAfterSection = { resetWireMockScenarioState(currenciesScenario) },
@ -32,8 +34,9 @@ class AppCurrencyTest : BaseTestCase() {
setWireMockScenarioState(scenarioName = currenciesScenario, state = appSettingsState)
}
step("Open 'Main Screen'") {
openMainScreen(productType = ProductType.Wallet2)
openMainScreen()
}
synchronizeAddresses()
step("Open wallet details") {
onMainScreenTopBar { moreButton.clickWithAssertion() }
}
@ -53,18 +56,30 @@ class AppCurrencyTest : BaseTestCase() {
onAppCurrencySelectorScreen { currencyItem(targetCurrency).performClick() }
}
step("Return to 'Main' screen") {
device.uiDevice.pressBack()
device.uiDevice.pressBack()
waitForIdle()
var displayed = false
var attempts = 0
while (!displayed && attempts < 4) {
onMainScreen { displayed = screenContainer.isDisplayedSafely() }
if (!displayed) {
device.uiDevice.pressBack()
waitForIdle()
attempts++
}
}
}
step("Assert total balance contains '$targetSymbol' on 'Main' screen") {
onMainScreen { totalBalanceText.assertTextContains(targetSymbol) }
// Balance re-loads in the new currency async after the switch — wait for the € equivalent.
composeTestRule.waitUntil(WAIT_UNTIL_TIMEOUT_LONG) {
runCatching { onMainScreen { totalBalanceText.assertTextContains(targetSymbol) } }.isSuccess
}
}
step("Click on token '$token'") {
onMainScreen { tokenWithTitleAndAddress(token).clickWithAssertion() }
}
step("Assert token fiat balance contains '$targetSymbol'") {
onTokenDetailsScreen { fiatBalance.assertTextContains(targetSymbol) }
composeTestRule.waitUntil(WAIT_UNTIL_TIMEOUT_LONG) {
runCatching { onTokenDetailsScreen { fiatBalance.assertTextContains(targetSymbol) } }.isSuccess
}
}
}
}

View file

@ -49,66 +49,19 @@ class DetailsTest : BaseTestCase() {
}
onWalletSettingsScreen {
step("Assert 'Link more cards' button is visible") {
scrollToLinkMoreCards()
linkMoreCardsButton.assertIsDisplayed()
}
step("Assert 'Card Settings' button is visible") {
scrollToDeviceSettings()
deviceSettingsButton.assertIsDisplayed()
}
step("Assert 'Referral program' button is visible") {
scrollToReferralProgram()
referralProgramButton.assertIsDisplayed()
}
step("Assert 'Forget wallet' button is visible") {
forgetWalletButton.assertIsDisplayed()
}
}
}
@DisplayName("Details: (Wallet 2.0) fields")
@Test
fun wallet2DetailsTest() =
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen(productType = ProductType.Wallet2)
}
onMainScreenTopBar {
step("Open wallet details") {
moreButton.clickWithAssertion()
}
}
onDetailsScreen {
step("Assert 'Wallet connect' button is visible") {
walletConnectButton.assertIsDisplayed()
}
step("Assert 'Scan card' button is visible") {
scanCardButton.assertIsDisplayed()
}
step("Assert 'Buy Tangem card' button is visible") {
buyTangemButton.assertIsDisplayed()
}
step("Assert 'App settings' button is visible") {
appSettingsButton.assertIsDisplayed()
}
step("Assert 'Contact support' button is visible") {
contactSupportButton.assertIsDisplayed()
}
step("Assert 'Terms or service' button is visible") {
toSButton.assertIsDisplayed()
}
step("Open 'Wallet settings' screen") {
walletNameButton.clickWithAssertion()
}
}
onWalletSettingsScreen {
step("Assert 'Link more cards' button does not exist") {
linkMoreCardsButton.assertIsNotDisplayed()
}
step("Assert 'Card Settings' button is visible") {
deviceSettingsButton.assertIsDisplayed()
}
step("Assert 'Referral program' button is visible") {
referralProgramButton.assertIsDisplayed()
}
step("Assert 'Forget wallet' button is visible") {
scrollToForgetWallet()
forgetWalletButton.assertIsDisplayed()
}
}

View file

@ -29,7 +29,10 @@ class WalletRenameTest : BaseTestCase() {
onDetailsScreen { walletNameButton.clickWithAssertion() }
}
step("Click on 'Rename' button") {
onWalletSettingsScreen { renameWalletButton.clickWithAssertion() }
onWalletSettingsScreen {
scrollToRenameButton()
renameWalletButton.clickWithAssertion()
}
}
step("Enter new wallet name '$newWalletName'") {
onDialog { inputField.performTextReplacement(newWalletName) }