Updated on 2026-08-14
This commit is contained in:
parent
173ee13120
commit
4b2eb80765
13 changed files with 123 additions and 74 deletions
|
|
@ -19,6 +19,7 @@ class ApplicationInjectionExecutionRule : TestRule {
|
|||
OnComponentReadyRunner.addListener(
|
||||
tangemApplication, ApplicationEntryPoint::class.java
|
||||
) { _: ApplicationEntryPoint ->
|
||||
tangemApplication.preInit()
|
||||
tangemApplication.init()
|
||||
}
|
||||
base.evaluate()
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ abstract class BaseTestCase : TestCase(
|
|||
composeTestRule.onRoot(useUnmergedTree = useUnmergedTree).printToLog(tag, maxDepth)
|
||||
}
|
||||
|
||||
fun waitForIdle() = composeTestRule.waitForIdle()
|
||||
|
||||
private fun setFeatureToggles() {
|
||||
runBlocking {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ object TestConstants {
|
|||
const val CARDANO_ADDRESS = "addr1q8f9499e58k4hhfd9vhawprxt3xd94x7rmlyp33ee4xkatakcl2zgkrg0p6ceqkndtkw4cumfe9enhdph8yhuswn785srksm9p"
|
||||
|
||||
const val WAIT_UNTIL_TIMEOUT = 20_000L
|
||||
const val WAIT_UNTIL_TIMEOUT_LONG = 30_000L
|
||||
|
||||
const val MARKETS_MAIN_NETWORK_SUFFIX = "MAIN"
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,31 @@ fun BaseTestCase.openTheAppFromRecents() {
|
|||
device.uiDevice.click(centerX, centerY)
|
||||
}
|
||||
|
||||
fun BaseTestCase.disableWiFi() {
|
||||
device.uiDevice.executeShellCommand("svc wifi disable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.disableMobileData() {
|
||||
device.uiDevice.executeShellCommand("svc data disable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.enableWiFi() {
|
||||
device.uiDevice.executeShellCommand("svc wifi enable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.enableMobileData() {
|
||||
device.uiDevice.executeShellCommand("svc data enable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.stopApp(packageName: String) {
|
||||
device.apps.kill(packageName)
|
||||
}
|
||||
|
||||
fun BaseTestCase.launchApp(packageName: String) {
|
||||
device.apps.waitForAppLaunchAndReady(packageName = packageName)
|
||||
device.apps.launch(packageName)
|
||||
}
|
||||
|
||||
enum class SwipeDirection {
|
||||
UP, DOWN
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ fun BaseTestCase.scanCard(
|
|||
}
|
||||
if (alreadyActivatedDialogIsShown) {
|
||||
step("Click on 'This is my wallet' button") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
AlreadyUsedWalletDialogPageObject { thisIsMyWalletButton.click() }
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ fun BaseTestCase.synchronizeAddresses(balance: String) {
|
|||
|
||||
fun BaseTestCase.openDeviceSettingsScreen() {
|
||||
step("Open wallet details") {
|
||||
waitForIdle()
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Open 'Wallet settings' screen") {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.assertElementDoesNotExist
|
||||
import com.tangem.screens.onMainScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
|
|
@ -14,30 +13,6 @@ fun BaseTestCase.checkSingleCurrencyMainScreen(
|
|||
step("Assert card title equal '$cardTitle'") {
|
||||
onMainScreen { walletNameText.assertTextEquals(cardTitle) }
|
||||
}
|
||||
if (withTransactions) {
|
||||
step("Assert 'Transactions' block is displayed") {
|
||||
onMainScreen { transactionsExplorerText().assertExists() }
|
||||
}
|
||||
step("Assert 'Transactions' title is displayed") {
|
||||
onMainScreen { transactionsTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Explorer' icon is displayed") {
|
||||
onMainScreen { transactionsExplorerIcon.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert empty 'Transactions' block is displayed") {
|
||||
onMainScreen { emptyTransactionBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block icon is displayed") {
|
||||
onMainScreen { emptyTransactionBlockIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block text is displayed") {
|
||||
onMainScreen { emptyTransactionBlockText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block 'Explore' button is displayed") {
|
||||
onMainScreen { emptyTransactionBlockExploreButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
if (withWalletImage) {
|
||||
step("Assert card image is displayed") { //TODO: create assertion method for checking images
|
||||
onMainScreen { walletImage.assertIsDisplayed() }
|
||||
|
|
@ -63,15 +38,37 @@ fun BaseTestCase.checkSingleCurrencyMainScreen(
|
|||
onMainScreen { swapButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' on single card main screen is displayed") {
|
||||
onMainScreen { marketPriceBlock.assertIsDisplayed() }
|
||||
onMainScreen { marketPriceBlock().assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' title equals $cardBlockchain Market Price") {
|
||||
onMainScreen { marketPriceText.assertTextContains("$cardBlockchain Market Price") }
|
||||
}
|
||||
step("Assert 'Organize tokens' button is not displayed") {
|
||||
onMainScreen {
|
||||
assertElementDoesNotExist({ organizeTokensButtonWithoutLazySearch() }, "Organize tokens button")
|
||||
if (withTransactions) {
|
||||
step("Assert 'Transactions' block is displayed") {
|
||||
onMainScreen { transactionsExplorerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Transactions' title is displayed") {
|
||||
onMainScreen { transactionsTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Explorer' icon is displayed") {
|
||||
onMainScreen { transactionsExplorerIcon.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert empty 'Transactions' block is displayed") {
|
||||
onMainScreen { emptyTransactionBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block icon is displayed") {
|
||||
onMainScreen { emptyTransactionBlockIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block text is displayed") {
|
||||
onMainScreen { emptyTransactionBlockText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block 'Explore' button is displayed") {
|
||||
onMainScreen { emptyTransactionBlockExploreButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Organize tokens' button is not displayed") {
|
||||
onMainScreen { organizeTokensButtonWithoutLazySearch.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,9 +83,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val marketPriceBlock: KNode = child {
|
||||
hasTestTag(MarketPriceBlockTestTags.BLOCK)
|
||||
useUnmergedTree = true
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun marketPriceBlock(): LazyListItemNode {
|
||||
return lazyList.childWith<LazyListItemNode> {
|
||||
hasTestTag(MarketPriceBlockTestTags.BLOCK)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
val marketPriceText: KNode = child {
|
||||
|
|
@ -104,12 +107,10 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun transactionsExplorerText(): KNode {
|
||||
return child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_TEXT)
|
||||
hasText(getResourceString(R.string.common_explorer))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
val transactionsExplorerText: KNode = child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_TEXT)
|
||||
hasText(getResourceString(R.string.common_explorer))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val emptyTransactionBlock: KNode = child {
|
||||
|
|
@ -223,12 +224,10 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
fun organizeTokensButtonWithoutLazySearch(): KNode {
|
||||
return child {
|
||||
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
val organizeTokensButtonWithoutLazySearch: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||
|
|
|
|||
|
|
@ -87,12 +87,13 @@ class FeedbackTest : BaseTestCase() {
|
|||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Enter address") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
|
||||
onSendAddressScreen { addressTextField.performTextInput(recipientAddress) }
|
||||
}
|
||||
step("Click 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Send' button") {
|
||||
waitForIdle()
|
||||
onSendConfirmScreen {
|
||||
sendButton.assertIsEnabled()
|
||||
sendButton.performClick()
|
||||
|
|
@ -138,6 +139,7 @@ class FeedbackTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Check 'Scan warning' dialog") {
|
||||
waitForIdle()
|
||||
checkScanWarningDialog()
|
||||
}
|
||||
step("Click on 'Request support' button") {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
|
|
@ -42,6 +44,9 @@ class SendTest : BaseTestCase() {
|
|||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on token with name: $currencyName") {
|
||||
onMainScreen { tokenWithTitleAndAddress(currencyName).clickWithAssertion() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import com.tangem.common.annotations.ApiEnv
|
|||
import com.tangem.common.annotations.ApiEnvConfig
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.common.extensions.*
|
||||
import com.tangem.common.utils.*
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.screens.*
|
||||
|
|
@ -28,10 +30,12 @@ class SwapTokenTest : BaseTestCase() {
|
|||
@Test
|
||||
fun networkFeeTest() {
|
||||
val inputAmount = "100"
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
resetWireMockScenarios()
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
|
|
@ -71,7 +75,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Input swap amount = '$inputAmount'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onSwapTokenScreen {
|
||||
textInput.clickWithAssertion()
|
||||
textInput.performTextReplacement(inputAmount)
|
||||
|
|
@ -89,7 +93,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Network fee' block is displayed") {
|
||||
onSwapTokenScreen {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
networkFeeBlock.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +108,12 @@ class SwapTokenTest : BaseTestCase() {
|
|||
@DisplayName("Swap: network error test")
|
||||
@Test
|
||||
fun networkErrorSwapTest() {
|
||||
setupHooks().run {
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
enableWiFi()
|
||||
enableMobileData()
|
||||
}
|
||||
).run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
|
|
@ -120,6 +129,10 @@ class SwapTokenTest : BaseTestCase() {
|
|||
step("Click on token with name: '$tokenTitle'") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Turn off Wi-Fi and Mobile Data") {
|
||||
disableWiFi()
|
||||
disableMobileData()
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton.performClick() }
|
||||
}
|
||||
|
|
@ -189,7 +202,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Input swap amount = '$inputAmount'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onSwapTokenScreen {
|
||||
textInput.clickWithAssertion()
|
||||
textInput.performTextReplacement(inputAmount)
|
||||
|
|
@ -200,7 +213,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Click on 'Network fee' block") {
|
||||
onSwapTokenScreen {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
networkFeeBlock.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.tangem.tests
|
|||
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.extensions.launchApp
|
||||
import com.tangem.common.extensions.stopApp
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
|
|
@ -49,8 +49,9 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
@Test
|
||||
fun acceptTermsOfServiceAfterAppRestart() {
|
||||
val packageName = getTargetContext().packageName
|
||||
val tosUrl = "https://tangem.com/tangem_tos.html"
|
||||
|
||||
setupHooks().run {
|
||||
val tosUrl = "https://tangem.com/tangem_tos.html"
|
||||
step("Assert title of 'Disclaimer screen' is displayed") {
|
||||
onDisclaimerScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -65,14 +66,11 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
step("'Accept' button is displayed") {
|
||||
onDisclaimerScreen { acceptButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
step("Stop app") {
|
||||
stopApp(packageName)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
launchApp(packageName)
|
||||
}
|
||||
step("Assert title of 'Disclaimer screen' is displayed") {
|
||||
onDisclaimerScreen { title.assertIsDisplayed() }
|
||||
|
|
@ -86,16 +84,22 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
onDisclaimerScreen {
|
||||
waitForIdle()
|
||||
acceptButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
step("Stop app") {
|
||||
stopApp(packageName)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
launchApp(packageName)
|
||||
}
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
}
|
||||
step("Open 'Markets screen'") {
|
||||
swipeMarketsBlock(SwipeDirection.UP)
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
}
|
||||
step("Click on $tokenTitle token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -95,7 +95,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
onDialog { continueButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Go back to 'Markets: tokens list'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onMarketsScreen { topBarBackButton.clickWithAssertion() }
|
||||
}
|
||||
step("Close 'Markets screen'") {
|
||||
|
|
@ -151,7 +151,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
/**
|
||||
* Initialize components that need to be initialized before [super.onCreate] is called
|
||||
*/
|
||||
private fun preInit() {
|
||||
fun preInit() {
|
||||
tangemAppLoggerInitializer.initialize()
|
||||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue