Updated on 2026-08-14
This commit is contained in:
parent
1ea13a7484
commit
6588ff4fbc
14 changed files with 144 additions and 28 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.compose.ui.test.ComposeTimeoutException
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.ComposeTestRule
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
|
||||
fun KNode.clickWithAssertion() {
|
||||
|
|
@ -34,3 +36,25 @@ fun KNode.assertVisibility(shouldBeDisplayed: Boolean) {
|
|||
assertIsNotDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
fun KNode.clickAndWaitFor(
|
||||
rule: ComposeTestRule,
|
||||
timeoutMs: Long = 5_000,
|
||||
maxRetries: Int = 3,
|
||||
expectedCondition: () -> Unit,
|
||||
) {
|
||||
for (attempt in 1..maxRetries) {
|
||||
performClick()
|
||||
rule.waitForIdle()
|
||||
|
||||
try {
|
||||
rule.waitUntil(timeoutMs) {
|
||||
runCatching { expectedCondition() }.isSuccess
|
||||
}
|
||||
return
|
||||
} catch (_: ComposeTimeoutException) {
|
||||
}
|
||||
}
|
||||
|
||||
throw AssertionError("Condition not met after $maxRetries click attempts")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -46,7 +47,23 @@ fun BaseTestCase.swipeMarketsBlock(direction: SwipeDirection) {
|
|||
}
|
||||
|
||||
fun BaseTestCase.openTheAppFromRecents() {
|
||||
device.uiDevice.waitForIdle()
|
||||
|
||||
device.uiDevice.pressRecentApps()
|
||||
device.uiDevice.waitForIdle()
|
||||
|
||||
val recentsOpened = device.uiDevice.wait(
|
||||
Until.hasObject(By.res("com.android.launcher3:id/snapshot")),
|
||||
3_000
|
||||
)
|
||||
|
||||
if (!recentsOpened) {
|
||||
device.uiDevice.pressRecentApps()
|
||||
device.uiDevice.wait(
|
||||
Until.hasObject(By.res("com.android.launcher3:id/snapshot")),
|
||||
3_000
|
||||
)
|
||||
}
|
||||
|
||||
val centerX = device.uiDevice.displayWidth / 2
|
||||
val centerY = device.uiDevice.displayHeight / 3
|
||||
|
|
@ -54,6 +71,14 @@ fun BaseTestCase.openTheAppFromRecents() {
|
|||
device.uiDevice.click(centerX, centerY)
|
||||
}
|
||||
|
||||
fun BaseTestCase.collapseAppByHomeButton() {
|
||||
device.uiDevice.pressHome()
|
||||
device.uiDevice.wait(
|
||||
Until.hasObject(By.pkg(device.uiDevice.launcherPackageName)),
|
||||
3_000
|
||||
)
|
||||
}
|
||||
|
||||
fun BaseTestCase.disableWiFi() {
|
||||
device.uiDevice.executeShellCommand("svc wifi disable")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val addressesShimmer: KNode = child {
|
||||
hasTestTag(SendAddressScreenTestTags.ADDRESSES_SHIMMER)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val topAppBarTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(CoreUiR.string.common_address))
|
||||
|
|
@ -62,7 +67,7 @@ class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
|
|||
}
|
||||
|
||||
val clearTextFieldButton: KNode = child {
|
||||
hasContentDescription(getResourceString(CoreUiR.string.common_close))
|
||||
hasTestTag(SendAddressScreenTestTags.CROSS_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class TopBarPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
) {
|
||||
val moreButton: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.MORE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.common.BaseTestCase
|
|||
import com.tangem.common.constants.TestConstants.RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.clickAndWaitFor
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.scenarios.checkFailedTransactionDialog
|
||||
|
|
@ -46,6 +47,7 @@ class FeedbackTest : BaseTestCase() {
|
|||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Contact support' button") {
|
||||
waitForIdle()
|
||||
onDetailsScreen { contactSupportButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Gmail' app is open") {
|
||||
|
|
@ -96,17 +98,29 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Enter address") {
|
||||
onSendAddressScreen { addressTextField.performTextInput(recipientAddress) }
|
||||
}
|
||||
step("Click 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
step("Assert text field contains text: $recipientAddress") {
|
||||
onSendAddressScreen { addressTextField.assertTextEquals(recipientAddress) }
|
||||
}
|
||||
step("Assert sеnding text is displayed") {
|
||||
onSendConfirmScreen { sendingText.assertIsDisplayed() }
|
||||
step("Click 'Next' button") {
|
||||
onSendAddressScreen {
|
||||
nextButton.clickAndWaitFor(
|
||||
rule = composeTestRule,
|
||||
expectedCondition = {
|
||||
onSendConfirmScreen { sendingText.assertIsDisplayed() }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
step("Click 'Send' button") {
|
||||
waitForIdle()
|
||||
onSendConfirmScreen {
|
||||
sendButton.assertIsEnabled()
|
||||
sendButton.performClick()
|
||||
sendButton.clickAndWaitFor(
|
||||
rule = composeTestRule,
|
||||
expectedCondition = {
|
||||
onFailedTransactionDialog { dialogContainer.assertIsDisplayed() }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
step("Check 'Failed transaction' dialog") {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Press 'Home' to collapse the app") {
|
||||
device.uiDevice.pressHome()
|
||||
collapseAppByHomeButton()
|
||||
}
|
||||
step("Open the app from recent apps") {
|
||||
openTheAppFromRecents()
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import com.tangem.common.constants.TestConstants.ENS_ETHEREUM_RECIPIENT_SHORTENE
|
|||
import com.tangem.common.constants.TestConstants.ENS_NAME
|
||||
import com.tangem.common.constants.TestConstants.ETHEREUM_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.ETHEREUM_RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.common.constants.TestConstants.XRP_RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.XRP_X_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.XRP_X_RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.XRP_X_RECIPIENT_ADDRESS_WITH_TAG
|
||||
import com.tangem.common.extensions.clickAndWaitFor
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.clearClipboard
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
|
|
@ -115,6 +117,9 @@ class SendAddressScreenTest : BaseTestCase() {
|
|||
clearClipboard()
|
||||
}
|
||||
).run {
|
||||
step("Set clipboard text") {
|
||||
setClipboardText(context, recipientAddress)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
|
|
@ -124,10 +129,11 @@ class SendAddressScreenTest : BaseTestCase() {
|
|||
step("Open 'Send Address' screen") {
|
||||
openSendAddressScreen(tokenName, sendAmount)
|
||||
}
|
||||
step("Set clipboard text") {
|
||||
setClipboardText(context, recipientAddress)
|
||||
step("Assert 'Addresses shimmer' is not displayed") {
|
||||
onSendAddressScreen { addressesShimmer.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Paste' button") {
|
||||
waitForIdle()
|
||||
onSendAddressScreen { addressPasteButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert address text field contains correct recipient address") {
|
||||
|
|
@ -142,8 +148,22 @@ class SendAddressScreenTest : BaseTestCase() {
|
|||
step("Set clipboard text") {
|
||||
setClipboardText(context, invalidAddress)
|
||||
}
|
||||
step("Assert 'Addresses shimmer' is not displayed") {
|
||||
onSendAddressScreen { addressesShimmer.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Cross' button") {
|
||||
onSendAddressScreen { clearTextFieldButton.clickWithAssertion() }
|
||||
waitForIdle()
|
||||
onSendAddressScreen {
|
||||
clearTextFieldButton.clickAndWaitFor(
|
||||
rule = composeTestRule,
|
||||
expectedCondition = {
|
||||
onSendAddressScreen { addressPasteButton.assertIsDisplayed() }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
step("Assert 'Addresses shimmer' is not displayed") {
|
||||
onSendAddressScreen { addressesShimmer.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Paste' button") {
|
||||
onSendAddressScreen { addressPasteButton.clickWithAssertion() }
|
||||
|
|
@ -154,20 +174,38 @@ class SendAddressScreenTest : BaseTestCase() {
|
|||
step("Assert invalid address text field title is displayed") {
|
||||
onSendAddressScreen { addressTextFieldTitle.assertTextContains(notAValidAddress) }
|
||||
}
|
||||
step("Assert 'Next' button is disabled") {
|
||||
onSendAddressScreen { nextButton.assertIsNotEnabled() }
|
||||
}
|
||||
step("Set clipboard text") {
|
||||
setClipboardText(context, walletAddress)
|
||||
}
|
||||
step("Assert 'Next' button is disabled") {
|
||||
onSendAddressScreen { nextButton.assertIsNotEnabled() }
|
||||
}
|
||||
step("Assert 'Addresses shimmer' is not displayed") {
|
||||
onSendAddressScreen { addressesShimmer.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Cross' button") {
|
||||
onSendAddressScreen { clearTextFieldButton.clickWithAssertion() }
|
||||
onSendAddressScreen {
|
||||
clearTextFieldButton.clickAndWaitFor(
|
||||
rule = composeTestRule,
|
||||
expectedCondition = {
|
||||
onSendAddressScreen { addressPasteButton.assertIsDisplayed() }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
step("Assert 'Addresses shimmer' is not displayed") {
|
||||
onSendAddressScreen { addressesShimmer.assertDoesNotExist() }
|
||||
}
|
||||
step("Click on 'Paste' button") {
|
||||
waitForIdle()
|
||||
onSendAddressScreen { addressPasteButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert address text field contains invalid address") {
|
||||
onSendAddressScreen { addressTextField.assertTextContains(walletAddress) }
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
onSendAddressScreen {
|
||||
addressTextField.assertTextContains(walletAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Address is the same as wallet address' error title is displayed") {
|
||||
onSendAddressScreen { addressTextFieldTitle.assertTextContains(sameAsWalletAddress) }
|
||||
|
|
|
|||
|
|
@ -267,22 +267,21 @@ class SendConfirmScreenTest : BaseTestCase() {
|
|||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(POLKADOT_RECIPIENT_ADDRESS) }
|
||||
}
|
||||
step("Turn off internet") {
|
||||
disableWiFi()
|
||||
disableMobileData()
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(POLKADOT_RECIPIENT_ADDRESS) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Turn on internet") {
|
||||
enableWiFi()
|
||||
enableMobileData()
|
||||
}
|
||||
step("Assert 'Network fee info unreachable' warning title is displayed") {
|
||||
onSendConfirmScreen { warningTitle(warningTitle).assertIsDisplayed() }
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
waitForIdle()
|
||||
onSendConfirmScreen { warningTitle(warningTitle).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Check your internet connection' warning message is displayed") {
|
||||
onSendConfirmScreen { warningMessage(warningMessageResId).assertIsDisplayed() }
|
||||
|
|
@ -290,6 +289,10 @@ class SendConfirmScreenTest : BaseTestCase() {
|
|||
step("Assert warning icon is displayed") {
|
||||
onSendConfirmScreen { warningIcon(warningTitle).assertIsDisplayed() }
|
||||
}
|
||||
step("Turn on internet") {
|
||||
enableWiFi()
|
||||
enableMobileData()
|
||||
}
|
||||
step("Click on 'Refresh' button") {
|
||||
waitForIdle()
|
||||
onSendConfirmScreen {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tests.swap
|
|||
import androidx.compose.ui.test.longClick
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.assertHasBadge
|
||||
import com.tangem.common.extensions.restartApp
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
|
|
@ -208,7 +209,10 @@ class SwapStoriesTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Swap' button has badge") {
|
||||
waitForIdle()
|
||||
onMainScreen { swapButton.assertHasBadge() }
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
composeTestRule.mainClock.advanceTimeBy(500)
|
||||
onMainScreen { swapButton.assertHasBadge() }
|
||||
}
|
||||
}
|
||||
step("Open 'Swap' screen") {
|
||||
openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = true)
|
||||
|
|
|
|||
|
|
@ -557,9 +557,6 @@ class SwapTokenScreenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
|
||||
@ApiEnv(
|
||||
ApiEnvConfig(ApiConfig.ID.Express, ApiEnvironment.PROD)
|
||||
)
|
||||
@AllureId("8536")
|
||||
@DisplayName("Swap: check switch fee type (unable to cover 'Market' and 'Fast' fee)")
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ fun InputRowRecipient(
|
|||
onClick = onPasteClick,
|
||||
modifier = Modifier
|
||||
.align(CenterVertically)
|
||||
.padding(start = TangemTheme.dimens.spacing8),
|
||||
.padding(start = TangemTheme.dimens.spacing8)
|
||||
.testTag(SendAddressScreenTestTags.CROSS_ICON),
|
||||
)
|
||||
}
|
||||
Row(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ object SendAddressScreenTestTags {
|
|||
const val ADDRESS_TEXT_FIELD = "SEND_ADDRESS_SCREEN_TEXT_FIELD"
|
||||
const val QR_BUTTON = "SEND_ADDRESS_SCREEN_QR_BUTTON"
|
||||
const val ADDRESS_PASTE_BUTTON = "SEND_ADDRESS_SCREEN_ADDRESS_PASTE_BUTTON"
|
||||
const val CROSS_ICON = "SEND_ADDRESS_SCREEN_ADDRESS_CROSS_ICON"
|
||||
const val RESOLVED_ADDRESS = "SEND_ADDRESS_SCREEN_RESOLVED_ADDRESS"
|
||||
const val ADDRESSES_SHIMMER = "SEND_ADDRESS_SCREEN_ADDRESSES_SHIMMER"
|
||||
|
||||
const val RECENT_ADDRESS_ITEM = "SEND_ADDRESS_SCREEN_RECENT_ADDRESS_ITEM"
|
||||
const val RECENT_ADDRESS_TITLE = "SEND_ADDRESS_SCREEN_RECENT_ADDRESS_TITLE"
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ private fun LazyListScope.listHeaderItem(
|
|||
TextShimmer(
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
text = stringResourceSafe(titleRes),
|
||||
modifier = Modifier.testTag(SendAddressScreenTestTags.ADDRESSES_SHIMMER),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ internal fun WalletTopBar(config: WalletTopBarConfig) {
|
|||
Icon(
|
||||
painter = painterResource(id = action.iconRes),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue