diff --git a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt index 8b307f4571..15e6bfcafc 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt @@ -186,6 +186,7 @@ abstract class BaseTestCase : TestCase( "VISA_ONBOARDING_ENABLED" to true, "AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING" to true, "AND_15310_ADD_FUNDS_STAGE1" to true, + "APP_REDESIGN_ENABLED" to true, ) ) } diff --git a/app/src/androidTest/kotlin/com/tangem/common/extensions/CustomAssertsExt.kt b/app/src/androidTest/kotlin/com/tangem/common/extensions/CustomAssertsExt.kt index 87db4a23e4..309b7c2fa0 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/extensions/CustomAssertsExt.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/extensions/CustomAssertsExt.kt @@ -115,5 +115,13 @@ private fun extractText(node: SemanticsNode): String? { private fun parseVolume(node: SemanticsNode): Double? { val text = extractText(node) ?: return null - return text.replace("[^0-9.]".toRegex(), "").toDoubleOrNull() + val multiplier = when { + text.contains('T', ignoreCase = true) -> 1_000_000_000_000.0 + text.contains('B', ignoreCase = true) -> 1_000_000_000.0 + text.contains('M', ignoreCase = true) -> 1_000_000.0 + text.contains('K', ignoreCase = true) -> 1_000.0 + else -> 1.0 + } + val number = text.replace("[^0-9.]".toRegex(), "").toDoubleOrNull() ?: return null + return number * multiplier } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt b/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt index 3e5c61cf6b..ee98f114ff 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt @@ -11,6 +11,11 @@ fun KNode.clickWithAssertion() { performClick() } +fun KNode.clickWhenEnabled() { + assertIsEnabled() + performClick() +} + fun KNode.assertTextContainsSafe( text: String, substring: Boolean = false, diff --git a/app/src/androidTest/kotlin/com/tangem/common/extensions/UiDeviceExt.kt b/app/src/androidTest/kotlin/com/tangem/common/extensions/UiDeviceExt.kt index 2ec823d1e8..b9121a87c6 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/extensions/UiDeviceExt.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/extensions/UiDeviceExt.kt @@ -4,8 +4,6 @@ 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 -import io.github.kakaocup.kakao.common.utilities.getResourceString fun BaseTestCase.swipeVertical( direction: SwipeDirection, @@ -31,21 +29,6 @@ fun BaseTestCase.pullToRefresh(steps: Int = 1000) { ) } -fun BaseTestCase.swipeMarketsBlock(direction: SwipeDirection) { - val searchBarText = device.uiDevice - .findObject(By.textContains(getResourceString(R.string.markets_search_header_title))) - val bounds = searchBarText.visibleBounds - - val centerX = bounds.centerX() - val startY = bounds.centerY() - val endY = when (direction) { - SwipeDirection.UP -> 50 - SwipeDirection.DOWN -> device.uiDevice.displayHeight - 100 - } - - device.uiDevice.swipe(centerX, startY, centerX, endY, 100) -} - fun BaseTestCase.openTheAppFromRecents() { device.uiDevice.waitForIdle() diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/CheckMainScreenScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/CheckMainScreenScenarios.kt index b8baf03580..cc456bd051 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/CheckMainScreenScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/CheckMainScreenScenarios.kt @@ -6,97 +6,33 @@ import com.tangem.common.extensions.swipeVertical import com.tangem.screens.onMainScreen import io.qameta.allure.kotlin.Allure.step -fun BaseTestCase.checkSingleCurrencyMainScreen( - cardBlockchain: String, - cardTitle: String, - withTransactions: Boolean = false, - withWalletImage: Boolean = true -) { +fun BaseTestCase.checkSingleCurrencyMainScreen(cardTitle: String) { step("Assert card title equal '$cardTitle'") { onMainScreen { walletNameText.assertTextEquals(cardTitle) } } - if (withWalletImage) { - step("Assert card image is displayed") { //TODO: create assertion method for checking images - onMainScreen { walletImage.assertIsDisplayed() } - } - } else { - step("Assert card image is not displayed") { - onMainScreen { walletImage.assertIsNotDisplayed() } - } - } - step("Assert 'Receive' button is displayed") { - onMainScreen { receiveButton.assertIsDisplayed() } - } step("Assert 'Buy' button is displayed") { onMainScreen { buyButton.assertIsDisplayed() } } - step("Assert 'Send' button is displayed") { - onMainScreen { sendButton.assertIsDisplayed() } - } step("Assert 'Sell' button is displayed") { onMainScreen { sellButton.assertIsDisplayed() } } step("Assert 'Swap' button is not displayed") { onMainScreen { swapButton.assertIsNotDisplayed() } } - step("Assert 'Market Price' on single card main screen is displayed") { - onMainScreen { marketPriceBlock().assertIsDisplayed() } - } - step("Assert 'Market Price' title equals $cardBlockchain Market Price") { - onMainScreen { marketPriceText.assertTextContains("$cardBlockchain Market Price") } - } step("Swipe up") { swipeVertical(SwipeDirection.UP) } - 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 'Add & Manage' button is not displayed") { onMainScreen { addAndManageButtonWithoutLazySearch.assertIsNotDisplayed() } } } fun BaseTestCase.checkMultiCurrencyMainScreen( - devicesCount: String, cardTitle: String, - withWalletImage: Boolean = true ) { step("Assert card title equal '$cardTitle'") { onMainScreen { walletNameText.assertTextEquals(cardTitle) } } - if (withWalletImage) { - step("Assert card image is displayed") { - onMainScreen { walletImage.assertIsDisplayed() } - } - } else { - step("Assert card image is not displayed") { - onMainScreen { walletImage.assertIsNotDisplayed() } - } - } - step("Assert devices count equal to '$devicesCount'") { - onMainScreen { walletDevicesCount.assertTextContains(devicesCount) } - } step("Assert 'Buy' button is displayed") { onMainScreen { buyButton.assertIsDisplayed() } } diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/MarketsScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/MarketsScenarios.kt index cda67fda49..ac596e4ede 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/MarketsScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/MarketsScenarios.kt @@ -1,28 +1,28 @@ package com.tangem.scenarios +import androidx.compose.ui.test.ExperimentalTestApi 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.screens.onMainScreen import com.tangem.screens.onMarketsExchangesScreen import com.tangem.screens.onMarketsScreen import com.tangem.screens.onMarketsTokenDetailsScreen import io.qameta.allure.kotlin.Allure.step -fun BaseTestCase.openMarketTokenDetailsScreen(blockchainName: String, tokenName: String) { +fun BaseTestCase.openTokenDetailsFromMarketsScreen(blockchainName: String, tokenName: String) { step("Open 'Markets' screen") { onMainScreen { searchThroughMarketPlaceholder.performClick() } waitForIdle() } - step("Click on 'Search' placeholder") { - onMarketsScreen { searchThroughMarketPlaceholder.performClick() } - } step("Click on $blockchainName blockchain") { waitForIdle() onMarketsScreen { tokenWithTitle(blockchainName).clickWithAssertion() } } - step("Click on $tokenName token") { + step("Click on 'In your portfolio' block") { + waitForIdle() + onMarketsTokenDetailsScreen { inYourPortfolioBlock.clickWithAssertion() } + } + step("Click on $tokenName token in 'Your portfolio' bottom sheet") { waitForIdle() onMarketsTokenDetailsScreen { tokenWithTitle(tokenName).clickWithAssertion() } } @@ -59,6 +59,7 @@ fun BaseTestCase.openMarketsScreen() { } } +@OptIn(ExperimentalTestApi::class) fun BaseTestCase.openMarketsExchangesScreen(tokenName: String, shouldClickSeeAllButton: Boolean = false) { openMarketsScreen() if (shouldClickSeeAllButton) @@ -69,9 +70,8 @@ fun BaseTestCase.openMarketsExchangesScreen(tokenName: String, shouldClickSeeAll onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() } waitForIdle() } - step("Scroll down") { - swipeVertical(SwipeDirection.UP) - swipeVertical(SwipeDirection.UP) + step("Scroll to 'Listed on exchanges' block") { + onMarketsScreen { scrollToListedOnBlock() } } step("Click on 'Listed on exchanges' block") { onMarketsScreen { listedOnBlockContainer.performClick() } diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt index 5277c76ba8..591528e289 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/SendScenarios.kt @@ -6,7 +6,6 @@ import com.tangem.common.constants.TestConstants.HOLD_DURATION_MS import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG -import com.tangem.common.extensions.assertIsDimmed import com.tangem.common.extensions.clickWithAssertion import com.tangem.common.utils.setWireMockScenarioState import com.tangem.screens.* @@ -34,8 +33,11 @@ fun BaseTestCase.openSendScreen( step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() } } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } } @@ -91,11 +93,11 @@ fun BaseTestCase.openSendAddressScreen( step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() } } - step("Assert 'Send' button is not dimmed") { - onTokenDetailsScreen { sendButton().assertIsDimmed(false) } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Type '$inputAmount' in input text field") { onSendScreen { @@ -109,6 +111,13 @@ fun BaseTestCase.openSendAddressScreen( step("Assert 'Send Address' container is displayed") { onSendAddressScreen { container.assertIsDisplayed() } } + step("Wait for recipient list to load") { + composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_LONG) { + runCatching { + onSendAddressScreen { addressesShimmer.assertIsNotDisplayed() } + }.isSuccess + } + } } fun BaseTestCase.checkScanQrScreen(emptyClipboard: Boolean = true) { @@ -244,8 +253,11 @@ fun BaseTestCase.selectTokenToSendViaSwap( networkName: String, networkType: String? = null, ) { - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Click on 'Swap to another token' button") { onSendScreen { swapToAnotherTokenButton.performClick() } diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/SwapScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/SwapScenarios.kt index d3933b0416..c036c80610 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/SwapScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/SwapScenarios.kt @@ -10,6 +10,7 @@ import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.HOLD_DURATION_MS import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG import com.tangem.common.extensions.assertVisibility +import com.tangem.common.extensions.clickWhenEnabled import com.tangem.common.extensions.clickWithAssertion import com.tangem.common.extensions.isDisplayedSafely import com.tangem.core.ui.R as CoreUiR @@ -43,8 +44,8 @@ fun BaseTestCase.openSwapScreen( } SwapEntryPoint.TokenDetails -> step("Click on 'Swap' button on 'Token details' screen") { - onTokenDetailsScreen { swapButton().performClick() } - } + onTokenDetailsScreen { swapButton.clickWhenEnabled() } + } SwapEntryPoint.MarketsTokenDetails -> step("Click on 'Swap' button on 'Markets' token details screen") { onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.performClick() } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/AddFundsBottomSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/AddFundsBottomSheetPageObject.kt new file mode 100644 index 0000000000..5586e86757 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/AddFundsBottomSheetPageObject.kt @@ -0,0 +1,41 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.common.BaseTestCase +import com.tangem.core.ui.R +import com.tangem.core.ui.test.BaseBottomSheetTestTags +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.hasText as withText + +class AddFundsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(BaseBottomSheetTestTags.CONTAINER) }, + ) { + + val buyButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_buy))) + useUnmergedTree = true + } + + val swapButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_swap))) + useUnmergedTree = true + } + + val receiveButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_receive))) + useUnmergedTree = true + } + + val closeButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_close))) + useUnmergedTree = true + } +} + +internal fun BaseTestCase.onAddFundsBottomSheet(function: AddFundsBottomSheetPageObject.() -> Unit) = + onComposeScreen(composeTestRule, function) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/AddTokenBottomSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/AddTokenBottomSheetPageObject.kt index fc864f40e2..e870bbb20e 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/AddTokenBottomSheetPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/AddTokenBottomSheetPageObject.kt @@ -11,7 +11,10 @@ import io.github.kakaocup.compose.node.element.KNode import io.github.kakaocup.kakao.common.utilities.getResourceString class AddTokenBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : - ComposeScreen(semanticsProvider = semanticsProvider) { + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(BaseBottomSheetTestTags.CONTAINER) }, + ) { val title: KNode = child { hasTestTag(BaseBottomSheetTestTags.TITLE) @@ -23,6 +26,12 @@ class AddTokenBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractions hasText(getResourceString(R.string.common_add)) useUnmergedTree = true } + + val laterButton: KNode = child { + hasTestTag(BaseButtonTestTags.TEXT) + hasText(getResourceString(R.string.common_later)) + useUnmergedTree = true + } } internal fun BaseTestCase.onAddTokenBottomSheet(function: AddTokenBottomSheetPageObject.() -> Unit) = diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MainScreenPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/MainScreenPageObject.kt index 82defdf7f0..ce7201883e 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/MainScreenPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/MainScreenPageObject.kt @@ -5,6 +5,7 @@ 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 androidx.compose.ui.test.swipeUp import com.tangem.common.BaseTestCase import com.tangem.common.extensions.getQuantityString import com.tangem.common.extensions.hasLazyListItemPosition @@ -49,27 +50,32 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) val buyButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_buy)) + hasAnyDescendant(withText(getResourceString(R.string.common_buy))) + useUnmergedTree = true } val sendButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_send)) + hasAnyDescendant(withText(getResourceString(R.string.common_send))) + useUnmergedTree = true } val receiveButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_receive)) + hasAnyDescendant(withText(getResourceString(R.string.common_receive))) + useUnmergedTree = true } val sellButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_sell)) + hasAnyDescendant(withText(getResourceString(R.string.common_sell))) + useUnmergedTree = true } val swapButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_swap)) + hasAnyDescendant(withText(getResourceString(R.string.common_swap))) + useUnmergedTree = true } val walletNameText: KNode = child { @@ -82,13 +88,21 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) useUnmergedTree = true } - val walletDevicesCount: KNode = child { - hasTestTag(MainScreenTestTags.DEVICES_COUNT) - useUnmergedTree = true + /** + * Collapses the collapsing header via a touch-based swipe so that items near the bottom + * of the lazy list fall within screen bounds before programmatic childWith scroll. + * Required because TangemCollapsingTopBar places the body at y=collapsingHeight, which + * pushes lower list items off-screen when the header is expanded. + */ + private fun collapseHeader() { + screenContainer { + performTouchInput { swipeUp(startY = visibleSize.height * 0.6f, endY = visibleSize.height * 0.1f) } + } } @OptIn(ExperimentalTestApi::class) fun marketPriceBlock(): LazyListItemNode { + collapseHeader() return lazyList.childWith { hasTestTag(MarketPriceBlockTestTags.BLOCK) useUnmergedTree = true @@ -231,6 +245,7 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) */ @OptIn(ExperimentalTestApi::class) fun accountWithName(name: String): LazyListItemNode { + collapseHeader() return lazyList.childWith { hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM) hasAnyDescendant(withText(name)) @@ -243,6 +258,7 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) */ @OptIn(ExperimentalTestApi::class) fun tokenWithTitleAndAddress(tokenTitle: String): KNode { + collapseHeader() return lazyList.childWith { hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM) hasText(tokenTitle) @@ -255,6 +271,7 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) @OptIn(ExperimentalTestApi::class) fun tokenWithCustomDerivationIcon(tokenTitle: String): KNode { + collapseHeader() return lazyList.childWith { hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM) hasText(tokenTitle) @@ -267,6 +284,7 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) @OptIn(ExperimentalTestApi::class) fun addAndManageButton(): KNode { + collapseHeader() return lazyList.childWith { hasTestTag(MainScreenTestTags.ADD_AND_MANAGE_BUTTON) }.child { @@ -282,11 +300,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) } val searchThroughMarketPlaceholder: KNode = child { - hasText(getResourceString(R.string.markets_search_header_title)) + hasText(getResourceString(R.string.markets_search_title_placeholder)) useUnmergedTree = true } fun tokenNetworkGroupTitle(tokenNetwork: String): KNode { + collapseHeader() return lazyList.child { hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM) hasAnyChild(withText(tokenNetwork)) @@ -296,6 +315,7 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) @OptIn(ExperimentalTestApi::class) fun tokenWithTitleAndPosition(tokenTitle: String, index: Int): KNode { + collapseHeader() return lazyList.childWith { hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM) hasText(tokenTitle) diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MarketsExchangesPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/MarketsExchangesPageObject.kt index 00d7f17067..2ae6458a3b 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/MarketsExchangesPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/MarketsExchangesPageObject.kt @@ -2,11 +2,9 @@ package com.tangem.screens import androidx.compose.ui.semantics.SemanticsNode import androidx.compose.ui.test.SemanticsNodeInteractionsProvider -import androidx.compose.ui.test.hasParent import androidx.compose.ui.test.hasTestTag import com.tangem.common.BaseTestCase import com.tangem.core.ui.test.TokenElementsTestTags -import com.tangem.core.ui.test.TopAppBarTestTags import com.tangem.features.onramp.impl.R import io.github.kakaocup.compose.node.element.ComposeScreen import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen @@ -23,16 +21,15 @@ class MarketsExchangesPageObject(private val provider: SemanticsNodeInteractions fun allExchangeTypeNodes(): List = provider - .onAllNodes(hasParent(hasParent(hasTestTag(TokenElementsTestTags.TOKEN_PRICE)))) + .onAllNodes(hasTestTag(TokenElementsTestTags.TOKEN_PRICE)) .fetchSemanticsNodes() fun allTrustScoreNodes(): List = provider - .onAllNodes(hasParent(hasTestTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT))) + .onAllNodes(hasTestTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT)) .fetchSemanticsNodes() val exchangesTitle: KNode = child { - hasTestTag(TopAppBarTestTags.TITLE) hasText(getResourceString(R.string.markets_token_details_exchanges_title)) useUnmergedTree = true } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MarketsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/MarketsPageObject.kt index 1eefd12486..dd24c4d3ca 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/MarketsPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/MarketsPageObject.kt @@ -1,6 +1,8 @@ package com.tangem.screens +import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import androidx.compose.ui.test.hasTestTag import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.MARKETS_MAIN_NETWORK_SUFFIX import com.tangem.core.ui.test.BaseButtonTestTags @@ -15,9 +17,9 @@ import io.github.kakaocup.kakao.common.utilities.getResourceString class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen(semanticsProvider = semanticsProvider) { - val addToPortfolioButton: KNode = child { + val addButton: KNode = child { hasTestTag(BaseButtonTestTags.TEXT) - hasText(getResourceString(R.string.common_add_to_portfolio)) + hasText(getResourceString(R.string.common_add)) useUnmergedTree = true } @@ -31,7 +33,12 @@ class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : } val searchThroughMarketPlaceholder: KNode = child { - hasText(getResourceString(R.string.markets_search_header_title)) + hasText(getResourceString(R.string.markets_search_title_placeholder)) + useUnmergedTree = true + } + + val tokenDetailsContent: KNode = child { + hasTestTag(MarketsTestTags.TOKEN_DETAILS_CONTENT) useUnmergedTree = true } @@ -41,7 +48,8 @@ class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : } val listedOnBlockContainer: KNode = child { - hasText(getResourceString(R.string.markets_token_details_listed_on), substring = true) + hasTestTag(MarketsTestTags.LISTED_ON_BLOCK) + useUnmergedTree = true } val listedOnEmptyText: KNode = child { @@ -60,6 +68,13 @@ class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : hasText(title) } } + + @ExperimentalTestApi + fun scrollToListedOnBlock() { + tokenDetailsContent { + performScrollToNode(hasTestTag(MarketsTestTags.LISTED_ON_BLOCK)) + } + } } internal fun BaseTestCase.onMarketsScreen(function: MarketsPageObject.() -> Unit) = diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MarketsTokenDetailsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/MarketsTokenDetailsPageObject.kt index 237a0f183b..cdd4f4843c 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/MarketsTokenDetailsPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/MarketsTokenDetailsPageObject.kt @@ -3,14 +3,13 @@ package com.tangem.screens import androidx.compose.ui.test.SemanticsNodeInteractionsProvider import com.tangem.common.BaseTestCase import com.tangem.core.ui.test.MarketTokenDetailsBottomSheetTestTags -import com.tangem.core.ui.test.TokenElementsTestTags import com.tangem.features.onramp.impl.R 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 +import com.tangem.core.ui.R as CoreUiR class MarketsTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen(semanticsProvider = semanticsProvider) { @@ -20,11 +19,14 @@ class MarketsTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractions hasText(getResourceString(R.string.common_swap), substring = true) } + val inYourPortfolioBlock: KNode = child { + hasText(getResourceString(CoreUiR.string.markets_portfolio_block_subtitle), substring = true) + useUnmergedTree = true + } + fun tokenWithTitle(title: String): KNode = child { - hasAnyAncestor(withTestTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_TOKEN_ITEM)) - hasTestTag(TokenElementsTestTags.TOKEN_TITLE) - hasAnySibling(withTestTag(TokenElementsTestTags.TOKEN_ICON)) hasAnyChild(withText(title)) + hasClickAction() useUnmergedTree = true } } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/OrganizeTokensPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/OrganizeTokensPageObject.kt index 1d5bd3418b..2ea02089e6 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/OrganizeTokensPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/OrganizeTokensPageObject.kt @@ -28,23 +28,18 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi useUnmergedTree = true } - private val topBarGroupButton: KNode = child { - hasTestTag(OrganizeTokensScreenTestTags.GROUP_BUTTON) + val organizeMenuButton: KNode = child { + hasTestTag(OrganizeTokensScreenTestTags.MENU_BUTTON) useUnmergedTree = true } - val groupButton: KNode = topBarGroupButton.child { + val groupButton: KNode = child { hasText(getResourceString(R.string.organize_tokens_group)) useUnmergedTree = true } - val ungroupButton: KNode = topBarGroupButton.child { - hasText(getResourceString(R.string.organize_tokens_ungroup)) - useUnmergedTree = true - } - val sortByBalanceButton: KNode = child { - hasTestTag(OrganizeTokensScreenTestTags.SORT_BY_BALANCE_BUTTON) + hasText(getResourceString(R.string.organize_tokens_sort_by_balance)) useUnmergedTree = true } // endregion TopBar @@ -84,7 +79,7 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi fun tokenNetworkGroupTitle(tokenNetwork: String): KNode { return lazyList.child { hasTestTag(OrganizeTokensScreenTestTags.GROUP_TITLE_ITEM) - hasAnyChild(withText(tokenNetwork)) + hasAnyDescendant(withText(tokenNetwork)) useUnmergedTree = true } } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt index 85d6640b23..be240a7c5a 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/SendAddressPageObject.kt @@ -97,7 +97,7 @@ class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider ): KNode = child { hasTestTag(SendAddressScreenTestTags.RECENT_ADDRESS_ITEM) hasAnyChild(withTestTag(SendAddressScreenTestTags.RECENT_ADDRESS_ICON)) - hasAnyDescendant(withText(recipientAddress)) + hasAnyDescendant(withText(recipientAddress, substring = true)) hasAnyDescendant(withTestTag(SendAddressScreenTestTags.RECENT_ADDRESS_TEXT)) useUnmergedTree = true if (description != null) { diff --git a/app/src/androidTest/kotlin/com/tangem/screens/TokenDetailsPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/TokenDetailsPageObject.kt index 4996f7db80..9f4b705579 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/TokenDetailsPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/TokenDetailsPageObject.kt @@ -1,20 +1,15 @@ package com.tangem.screens -import androidx.compose.ui.test.ExperimentalTestApi -import androidx.compose.ui.test.SemanticsMatcher import androidx.compose.ui.test.SemanticsNodeInteractionsProvider import com.tangem.common.BaseTestCase -import com.tangem.common.utils.LazyListItemNode import com.tangem.core.ui.test.BaseActionButtonsBlockTestTags import com.tangem.core.ui.test.BaseButtonTestTags import com.tangem.core.ui.test.NotificationTestTags import com.tangem.core.ui.test.TokenDetailsScreenTestTags -import com.tangem.core.ui.utils.LazyListItemPositionSemantics import com.tangem.features.tokendetails.impl.R 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.compose.node.element.lazylist.KLazyListNode import io.github.kakaocup.kakao.common.utilities.getResourceString import androidx.compose.ui.test.hasTestTag as withTestTag import androidx.compose.ui.test.hasText as withText @@ -36,18 +31,8 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide useUnmergedTree = true } - val availableStakingBlockTitle: KNode = child { - hasTestTag(TokenDetailsScreenTestTags.STAKING_SERVICE_TITLE) - useUnmergedTree = true - } - - val availableStakingBlockText: KNode = child { - hasTestTag(TokenDetailsScreenTestTags.STAKING_SERVICE_TEXT) - useUnmergedTree = true - } - - val availableStakingBlockCurrencyIcon: KNode = child { - hasTestTag(TokenDetailsScreenTestTags.STAKING_CURRENCY_ICON) + fun availableStakingBlockText(apy: String): KNode = child { + hasText(getResourceString(R.string.token_details_earn_staking_subtitle, apy)) useUnmergedTree = true } @@ -62,69 +47,39 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide useUnmergedTree = true } - val stakingDot: KNode = child { - hasTestTag(TokenDetailsScreenTestTags.STAKING_DOT) - useUnmergedTree = true - } - val stakingTokenAmount: KNode = child { hasTestTag(TokenDetailsScreenTestTags.STAKING_TOKEN_AMOUNT) useUnmergedTree = true } - val stakingChevronIcon: KNode = child { - hasTestTag(TokenDetailsScreenTestTags.STAKING_CHEVRON_ICON) - useUnmergedTree = true + val stakingTitle: KNode = child { + hasText(getResourceString(R.string.common_staking)) } - val stakingTitle: KNode = child { - hasText(getResourceString(R.string.staking_native)) + val stakingEnabledTitle: KNode = child { + hasText(getResourceString(R.string.staking_enabled)) } val title: KNode = child { hasTestTag(TokenDetailsScreenTestTags.TOKEN_TITLE) } - private val horizontalActionChips = KLazyListNode( - semanticsProvider = semanticsProvider, - viewBuilderAction = { hasTestTag(BaseActionButtonsBlockTestTags.HORIZONTAL_ACTION_CHIPS) }, - itemTypeBuilder = { itemType(::LazyListItemNode) }, - positionMatcher = { position -> - SemanticsMatcher.expectValue( - LazyListItemPositionSemantics, - position - ) - } - ) - - @OptIn(ExperimentalTestApi::class) - fun receiveButton(): LazyListItemNode = horizontalActionChips.childWith { + val addFundsButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_receive)) + hasAnyDescendant(withText(getResourceString(R.string.tangempay_card_details_add_funds))) + useUnmergedTree = true } - @OptIn(ExperimentalTestApi::class) - fun swapButton(): LazyListItemNode = horizontalActionChips.childWith { + val swapButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_swap)) + hasAnyDescendant(withText(getResourceString(R.string.common_swap))) + useUnmergedTree = true } - @OptIn(ExperimentalTestApi::class) - fun sellButton(): LazyListItemNode = horizontalActionChips.childWith { + val transferButton: KNode = child { hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_sell)) - } - - @OptIn(ExperimentalTestApi::class) - fun buyButton(): LazyListItemNode = horizontalActionChips.childWith { - hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_buy)) - } - - @OptIn(ExperimentalTestApi::class) - fun sendButton(): LazyListItemNode = horizontalActionChips.childWith { - hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) - hasText(getResourceString(R.string.common_send)) + hasAnyDescendant(withText(getResourceString(R.string.common_transfer))) + useUnmergedTree = true } fun networkFeeNotificationIcon(feeCurrencyName: String): KNode = child { @@ -204,7 +159,6 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide hasAnyDescendant(withTestTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_SWAP_ICON)) hasAnyDescendant(withTestTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_TO_ICON)) hasAnyDescendant(withTestTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_TO_AMOUNT)) - hasAnyDescendant(withTestTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_CHEVRON_ICON)) useUnmergedTree = true } } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/TransferBottomSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/TransferBottomSheetPageObject.kt new file mode 100644 index 0000000000..f8dd42807f --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/TransferBottomSheetPageObject.kt @@ -0,0 +1,41 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.common.BaseTestCase +import com.tangem.core.ui.R +import com.tangem.core.ui.test.BaseBottomSheetTestTags +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.hasText as withText + +class TransferBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(BaseBottomSheetTestTags.CONTAINER) }, + ) { + + val sendButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_send))) + useUnmergedTree = true + } + + val swapButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_swap))) + useUnmergedTree = true + } + + val sellButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_sell))) + useUnmergedTree = true + } + + val closeButton: KNode = child { + hasAnyChild(withText(getResourceString(R.string.common_close))) + useUnmergedTree = true + } +} + +internal fun BaseTestCase.onTransferBottomSheet(function: TransferBottomSheetPageObject.() -> Unit) = + onComposeScreen(composeTestRule, function) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt index b7fa3d9c5b..821cf2ca7b 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt @@ -27,6 +27,7 @@ import com.tangem.screens.onSendScreen import com.tangem.screens.onStoriesScreen import com.tangem.screens.onTokenDetailsScreen import com.tangem.screens.onMainScreenTopBar +import com.tangem.screens.onTransferBottomSheet import com.tangem.tap.domain.sdk.mocks.MockProvider import dagger.hilt.android.testing.HiltAndroidTest import io.qameta.allure.kotlin.AllureId @@ -94,8 +95,11 @@ class FeedbackTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() } } - step("Click 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Type '$sendAmount' in input text field") { onSendScreen { diff --git a/app/src/androidTest/kotlin/com/tangem/tests/OrganizeTokensTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/OrganizeTokensTest.kt index 81fe762f61..23ae843dbc 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/OrganizeTokensTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/OrganizeTokensTest.kt @@ -22,7 +22,8 @@ class OrganizeTokensTest : BaseTestCase() { fun groupTokensTest() { setupHooks().run { val tokenTitle = "Ethereum" - val tokenNetwork = "Ethereum network" + val networkTitleOrganize = "Ethereum" + val networkTitleMain = "Ethereum network" step("Open 'Main Screen'") { openMainScreen() @@ -39,17 +40,20 @@ class OrganizeTokensTest : BaseTestCase() { tokenWithTitle(tokenTitle).assertIsDisplayed() } } + step("Open organize menu") { + onOrganizeTokensScreen { organizeMenuButton.clickWithAssertion() } + } step("Click 'Group' button") { onOrganizeTokensScreen { groupButton.clickWithAssertion() } } step("Assert tokens were grouped on 'Organize tokens' screen") { - onOrganizeTokensScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsDisplayed() } + onOrganizeTokensScreen { tokenNetworkGroupTitle(networkTitleOrganize).assertIsDisplayed() } } step("Click 'Apply' button") { onOrganizeTokensScreen { applyButton.clickWithAssertion() } } step("Assert tokens were grouped on 'Main screen'") { - onMainScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsDisplayed() } + onMainScreen { tokenNetworkGroupTitle(networkTitleMain).assertIsDisplayed() } } step("Open 'Organize tokens' screen") { openOrganizeTokensScreen() @@ -60,17 +64,20 @@ class OrganizeTokensTest : BaseTestCase() { tokenWithTitle(tokenTitle).assertIsDisplayed() } } - step("Click 'Ungroup' button") { - onOrganizeTokensScreen { ungroupButton.clickWithAssertion() } + step("Open organize menu") { + onOrganizeTokensScreen { organizeMenuButton.clickWithAssertion() } + } + step("Click 'Group' checkbox again to ungroup") { + onOrganizeTokensScreen { groupButton.clickWithAssertion() } } step("Assert tokens were ungrouped on 'Organize tokens' screen") { - onOrganizeTokensScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsNotDisplayed() } + onOrganizeTokensScreen { tokenNetworkGroupTitle(networkTitleOrganize).assertIsNotDisplayed() } } step("Click 'Apply' button") { onOrganizeTokensScreen { applyButton.clickWithAssertion() } } step("Assert tokens were ungrouped on 'Main screen'") { - onMainScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsNotDisplayed() } + onMainScreen { tokenNetworkGroupTitle(networkTitleMain).assertIsNotDisplayed() } } } } @@ -185,6 +192,9 @@ class OrganizeTokensTest : BaseTestCase() { tokenWithTitleAndPosition(polExMaticTitle, 3).assertIsDisplayed() } } + step("Open organize menu") { + onOrganizeTokensScreen { organizeMenuButton.clickWithAssertion() } + } step("Click 'By Balance' button") { onOrganizeTokensScreen { sortByBalanceButton.clickWithAssertion() diff --git a/app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt index 1b83533fcb..d3511f52da 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt @@ -35,11 +35,7 @@ class ScanCardTest : BaseTestCase() { openMainScreen(cardType) } step("Check 'Main' screen for '${cardType.name}' $cardBlockchain card") { - checkSingleCurrencyMainScreen( - cardBlockchain = cardBlockchain, - cardTitle = cardType.name, - withTransactions = true - ) + checkSingleCurrencyMainScreen(cardTitle = cardType.name) } } } @@ -57,7 +53,7 @@ class ScanCardTest : BaseTestCase() { openMainScreen(mockContent = cardType, isTwinsCard = true) } step("Check 'Main' screen for '$cardName' $cardBlockchain card") { - checkSingleCurrencyMainScreen(cardBlockchain = cardBlockchain, cardTitle = cardName) + checkSingleCurrencyMainScreen(cardTitle = cardName) } } } @@ -66,7 +62,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: Card with Secp256k1 curve") @Test fun secpk1CurveCardScanTest() { - val devicesCount = "1 device" val cardType: MockContent = Secpk1CurveMockContent val cardName = "Wallet" val card = "card with Secp256k1 curve" @@ -75,12 +70,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on $card") { openMainScreen(mockContent = cardType) } - step("Check 'Main' screen for $card curve with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen( - devicesCount = devicesCount, - cardTitle = cardName, - withWalletImage = false - ) + step("Check 'Main' screen for $card curve") { + checkMultiCurrencyMainScreen(cardTitle = cardName) } } } @@ -99,11 +90,7 @@ class ScanCardTest : BaseTestCase() { openMainScreen(mockContent = cardType) } step("Check 'Main' screen for $card with blockchain: '$cardBlockchain'") { - checkSingleCurrencyMainScreen( - cardBlockchain = cardBlockchain, - cardTitle = cardName, - withWalletImage = false - ) + checkSingleCurrencyMainScreen(cardTitle = cardName) } } } @@ -112,7 +99,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: 'Shiba' card") @Test fun shibaCardScanTest() { - val devicesCount = "2 devices" val cardType: MockContent = ShibaMockContent val cardName = "Wallet" val card = "Shiba" @@ -121,8 +107,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on '$card' card") { openMainScreen(mockContent = cardType) } - step("Check 'Main' screen for '$card' card with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen(devicesCount, cardName) + step("Check 'Main' screen for '$card' card") { + checkMultiCurrencyMainScreen(cardName) } } } @@ -131,7 +117,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: 'Ring'") @Test fun ringScanTest() { - val devicesCount = "3 devices" val cardType: ProductType = ProductType.Ring val cardName = "Wallet" val ring = "Ring" @@ -140,8 +125,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on '$ring'") { openMainScreen(productType = cardType) } - step("Check 'Main' screen for '$ring' with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen(devicesCount, cardName) + step("Check 'Main' screen for '$ring'") { + checkMultiCurrencyMainScreen(cardName) } } } @@ -150,7 +135,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: 'Wallet' card") @Test fun walletCardScanTest() { - val devicesCount = "1 device" val cardType: ProductType = ProductType.Wallet val cardName = "Wallet" @@ -158,8 +142,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on '$cardName' card") { openMainScreen(productType = cardType) } - step("Check 'Main' screen for '$cardName' card with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen(devicesCount, cardName) + step("Check 'Main' screen for '$cardName' card") { + checkMultiCurrencyMainScreen(cardName) } } } @@ -168,7 +152,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: 'Wallet 2' card") @Test fun wallet2ScanTest() { - val devicesCount = "2 devices" val cardType: MockContent = Wallet2MockContent val cardName = "Wallet" val card = "Wallet 2" @@ -177,8 +160,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on '$card' card") { openMainScreen(mockContent = cardType) } - step("Check 'Main' screen for '$card' card with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen(devicesCount, cardName) + step("Check 'Main' screen for '$card' card") { + checkMultiCurrencyMainScreen(cardName) } } } @@ -187,7 +170,6 @@ class ScanCardTest : BaseTestCase() { @DisplayName("Scan: Card with 4.12 firmware") @Test fun firmware412CardScanTest() { - val devicesCount = "1 device" val cardType: MockContent = Firmware412MockContent val cardName = "Tangem card" val card = "card with 4.12 firmware" @@ -196,8 +178,8 @@ class ScanCardTest : BaseTestCase() { step("Open 'Main Screen' on '$card'") { openMainScreen(mockContent = cardType) } - step("Check 'Main' screen for '$card' with devices count = '$devicesCount'") { - checkMultiCurrencyMainScreen(devicesCount, cardName) + step("Check 'Main' screen for '$card'") { + checkMultiCurrencyMainScreen(cardName) } } } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/StakingTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/StakingTest.kt index d02ce135ee..013753f460 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/StakingTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/StakingTest.kt @@ -56,20 +56,14 @@ class StakingTest : BaseTestCase() { onTokenDetailsScreen { stakingBlock.assertIsDisplayed() } } step("Assert 'Staking title' is displayed") { - onTokenDetailsScreen { stakingTitle.assertIsDisplayed() } + onTokenDetailsScreen { stakingEnabledTitle.assertIsDisplayed() } } step("Assert 'Staking fiat amount' is displayed") { onTokenDetailsScreen { stakingFiatAmount.assertIsDisplayed() } } - step("Assert 'Staking dot' is displayed") { - onTokenDetailsScreen { stakingDot.assertIsDisplayed() } - } step("Assert 'Staking token amount' is displayed") { onTokenDetailsScreen { stakingTokenAmount.assertIsDisplayed() } } - step("Assert 'Staking block chevron icon' is displayed") { - onTokenDetailsScreen { stakingChevronIcon.assertIsDisplayed() } - } } } @@ -139,6 +133,7 @@ class StakingTest : BaseTestCase() { val scenarioName = "staking_eth_pol_balances_android" val scenarioState = "Started" val stakingAmount = "1" + val stakingApy = "2.84%" setupHooks( additionalAfterSection = { @@ -172,13 +167,10 @@ class StakingTest : BaseTestCase() { onTokenDetailsScreen { availableStakingBlock.assertIsDisplayed() } } step("Assert 'Available staking block' title is displayed") { - onTokenDetailsScreen { availableStakingBlockTitle.assertIsDisplayed() } + onTokenDetailsScreen { stakingTitle.assertIsDisplayed() } } step("Assert 'Available staking block' text is displayed") { - onTokenDetailsScreen { availableStakingBlockText.assertIsDisplayed() } - } - step("Assert 'Available staking block' currency icon is displayed") { - onTokenDetailsScreen { availableStakingBlockCurrencyIcon.assertIsDisplayed() } + onTokenDetailsScreen { availableStakingBlockText(stakingApy).assertIsDisplayed() } } step("Click on 'Stake' button") { onTokenDetailsScreen { stakeButton.clickWithAssertion() } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt index 51bc278976..e3c3937047 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt @@ -1,14 +1,10 @@ package com.tangem.tests 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.screens.onMainScreen import com.tangem.tap.domain.sdk.mocks.content.DevWalletMockContent -import com.tangem.tap.domain.sdk.mocks.content.Wallet2WithSeedPhraseMockContent import dagger.hilt.android.testing.HiltAndroidTest -import io.qameta.allure.kotlin.Allure.step import io.qameta.allure.kotlin.AllureId import io.qameta.allure.kotlin.junit4.DisplayName import org.junit.Test diff --git a/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/MainScreenActionButtonsTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/MainScreenActionButtonsTest.kt index 1f795cadce..418774cd8e 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/MainScreenActionButtonsTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/MainScreenActionButtonsTest.kt @@ -389,6 +389,9 @@ class MainScreenActionButtonsTest : BaseTestCase() { step("Click on 'Buy' button") { onMainScreen { buyButton.performClick() } } + step("Click on token: '$tokenTitle'") { + onBuyTokenScreen { tokenWithTitleAndFiatAmount(tokenTitle).performClick() } + } step("Click on 'Confirm' button in 'Dialog'") { waitForIdle() onDialog { confirmButton.clickWithAssertion() } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/TokenDetailsScreenActionButtonsTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/TokenDetailsScreenActionButtonsTest.kt index f634fe21c0..99e629f6e9 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/TokenDetailsScreenActionButtonsTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/actionButtons/TokenDetailsScreenActionButtonsTest.kt @@ -2,16 +2,17 @@ package com.tangem.tests.actionButtons import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT -import com.tangem.common.extensions.assertIsDimmed import com.tangem.common.extensions.clickWithAssertion import com.tangem.scenarios.checkQrCodeBottomSheetScenario import com.tangem.scenarios.goToQrCodeBottomSheet import com.tangem.scenarios.openMainScreen import com.tangem.scenarios.synchronizeAddresses +import com.tangem.screens.onAddFundsBottomSheet import com.tangem.screens.onMainScreen import com.tangem.screens.onSwapStoriesScreen import com.tangem.screens.onSwapTokenScreen import com.tangem.screens.onTokenDetailsScreen +import com.tangem.screens.onTransferBottomSheet import dagger.hilt.android.testing.HiltAndroidTest import io.qameta.allure.kotlin.AllureId import io.qameta.allure.kotlin.junit4.DisplayName @@ -37,20 +38,41 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() { waitForIdle() onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() } } - step("Assert 'Receive' button is displayed") { - onTokenDetailsScreen { receiveButton().assertIsDisplayed() } - } - step("Assert 'Buy' button is displayed") { - onTokenDetailsScreen { buyButton().assertIsDisplayed() } - } - step("Assert 'Send' button is displayed") { - onTokenDetailsScreen { sendButton().assertIsDisplayed() } + step("Assert 'Add funds' button is displayed") { + onTokenDetailsScreen { addFundsButton.assertIsDisplayed() } } step("Assert 'Swap' button is displayed") { - onTokenDetailsScreen { swapButton().assertIsDisplayed() } + onTokenDetailsScreen { swapButton.assertIsDisplayed() } } - step("Assert 'Sell' button is displayed") { - onTokenDetailsScreen { sellButton().assertIsDisplayed() } + step("Assert 'Transfer' button is displayed") { + onTokenDetailsScreen { transferButton.assertIsDisplayed() } + } + step("Click on 'Add funds' button") { + onTokenDetailsScreen { addFundsButton.clickWithAssertion() } + } + step("Assert 'Buy' button in bottom sheet is displayed") { + onAddFundsBottomSheet { buyButton.assertIsDisplayed() } + } + step("Assert 'Swap' button in bottom sheet is displayed") { + onAddFundsBottomSheet { swapButton.assertIsDisplayed() } + } + step("Assert 'Receive' button in bottom sheet is displayed") { + onAddFundsBottomSheet { receiveButton.assertIsDisplayed() } + } + step("Click on 'Close' button in bottom sheet") { + onAddFundsBottomSheet { closeButton.clickWithAssertion() } + } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Assert 'Send' button in bottom sheet is displayed") { + onTransferBottomSheet { sendButton.assertIsDisplayed() } + } + step("Assert 'Swap' button in bottom sheet is displayed") { + onTransferBottomSheet { swapButton.assertIsDisplayed() } + } + step("Assert 'Sell' button in bottom sheet is displayed") { + onTransferBottomSheet { sellButton.assertIsDisplayed() } } } } @@ -72,20 +94,41 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() { waitForIdle() onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() } } - step("Assert 'Receive' button is not dimmed") { - onTokenDetailsScreen { receiveButton().assertIsDimmed(false) } + step("Assert 'Add funds' button is enabled") { + onTokenDetailsScreen { addFundsButton.assertIsEnabled() } } - step("Assert 'Buy' button is not dimmed") { - onTokenDetailsScreen { buyButton().assertIsDimmed(false) } + step("Assert 'Swap' button is disabled") { + onTokenDetailsScreen { swapButton.assertIsNotEnabled() } } - step("Assert 'Send' button is not dimmed") { - onTokenDetailsScreen { sendButton().assertIsDimmed(false) } + step("Assert 'Transfer' button is enabled") { + onTokenDetailsScreen { transferButton.assertIsEnabled() } } - step("Assert 'Swap' button is dimmed") { - onTokenDetailsScreen { swapButton().assertIsDimmed() } + step("Click on 'Add funds' button") { + onTokenDetailsScreen { addFundsButton.clickWithAssertion() } } - step("Assert 'Sell' button is dimmed") { - onTokenDetailsScreen { sellButton().assertIsDimmed() } + step("Assert 'Buy' button in bottom sheet is enabled") { + onAddFundsBottomSheet { buyButton.assertIsEnabled() } + } + step("Assert 'Swap' button in bottom sheet is disabled") { + onAddFundsBottomSheet { swapButton.assertIsNotEnabled() } + } + step("Assert 'Receive' button in bottom sheet is enabled") { + onAddFundsBottomSheet { receiveButton.assertIsEnabled() } + } + step("Click on 'Close' button in bottom sheet") { + onAddFundsBottomSheet { closeButton.clickWithAssertion() } + } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Assert 'Send' button in bottom sheet is enabled") { + onTransferBottomSheet { sendButton.assertIsEnabled() } + } + step("Assert 'Swap' button in bottom sheet is disabled") { + onTransferBottomSheet { swapButton.assertIsNotEnabled() } + } + step("Assert 'Sell' button in bottom sheet is disabled") { + onTransferBottomSheet { sellButton.assertIsNotEnabled() } } } } @@ -109,7 +152,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() { onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() } } step("Click on 'Swap' button") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Close 'Stories' screen") { onSwapStoriesScreen { closeButton.clickWithAssertion() } @@ -140,8 +183,11 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() { waitForIdle() onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() } } - step("Click on 'Receive' button") { - onTokenDetailsScreen { receiveButton().performClick() } + step("Click on 'Add funds' button") { + onTokenDetailsScreen { addFundsButton.clickWithAssertion() } + } + step("Click on 'Receive' button in bottom sheet") { + onAddFundsBottomSheet { receiveButton.clickWithAssertion() } } step("Go to QR code bottom sheet") { flakySafely(WAIT_UNTIL_TIMEOUT) { diff --git a/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceLongTapTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceLongTapTest.kt deleted file mode 100644 index bae6abd799..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceLongTapTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.tangem.tests.balance - -import androidx.compose.ui.test.longClick -import com.tangem.common.BaseTestCase -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() - } - step("Long tap on total balance block") { - onMainScreen { - totalBalanceContainer.performTouchInput { - longClick() - } - } - } - step("Assert 'Rename' button is displayed") { - onMainScreen { totalBalanceMenuRenameWallet.assertIsDisplayed() } - } - step("Assert 'Delete' button is not displayed") { - onMainScreen { totalBalanceMenuDeleteWallet.assertIsNotDisplayed() } - } - } - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceUpdateTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceUpdateTest.kt index b8a7826147..61318f6706 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceUpdateTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/balance/TotalBalanceUpdateTest.kt @@ -3,6 +3,7 @@ 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.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT import com.tangem.common.extensions.* import com.tangem.common.utils.resetWireMockScenarioState import com.tangem.common.utils.setWireMockScenarioState @@ -82,28 +83,27 @@ class TotalBalanceUpdateTest : BaseTestCase() { step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") { setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState) } - step("Click on 'Add to portfolio' button") { - onMarketsScreen { addToPortfolioButton.clickWithAssertion() } + step("Click on 'Add' button in 'Markets' bottom sheet") { + onMarketsScreen { addButton.clickWithAssertion() } } - step("Click on main network") { - onMarketsScreen { mainNetworkSuffix.performClick() } - } - step("Click on 'Add' button") { - onDialog { addButton.clickWithAssertion() } - } - step("Assert 'Continue' is not displayed") { - onDialog { addButton.assertIsNotDisplayed() } + step("Click on 'Add' button in 'Add token' bottom sheet") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onAddTokenBottomSheet { + addButton.performClick() + } + onAddTokenBottomSheet { laterButton.assertIsDisplayed() } + } } step("Click on 'Later' button") { - onDialog { laterButton.clickWithAssertion() } + onAddTokenBottomSheet { laterButton.performClick() } } - step("Go back to 'Markets: tokens list'") { + step("Press 'Back' button") { waitForIdle() - onMarketsScreen { topBarBackButton.clickWithAssertion() } + device.uiDevice.pressBack() } - step("Close 'Markets screen'") { - onSearchBar { searchField.assertIsDisplayed() } - swipeMarketsBlock(SwipeDirection.DOWN) + step("Press 'Back' button") { + waitForIdle() + device.uiDevice.pressBack() } step("Assert $updatedBalance is displayed in total balance") { onMainScreen { totalBalanceText.assertTextContains(updatedBalance) } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/main/MainScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/main/MainScreenTest.kt index ac99d2e42e..0822905804 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/main/MainScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/main/MainScreenTest.kt @@ -2,6 +2,8 @@ package com.tangem.tests.main import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO +import com.tangem.common.extensions.SwipeDirection +import com.tangem.common.extensions.swipeVertical import com.tangem.common.utils.resetWireMockScenarioState import com.tangem.common.utils.setWireMockScenarioState import com.tangem.scenarios.openMainScreen @@ -35,7 +37,7 @@ class MainScreenTest : BaseTestCase() { } @AllureId("8748") - @DisplayName("Main: check 'Organize tokens' button with single token no accounts") + @DisplayName("Main: check 'Add & Manage' button with single token no accounts") @Test fun checkOrganizeTokensButtonWithSingleTokenNoAccountsTest() { val scenarioState = "Cardano" @@ -56,14 +58,14 @@ class MainScreenTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses() } - step("Assert 'Add & Manage' button is not displayed") { - onMainScreen { addAndManageButtonNode.assertIsNotDisplayed()} + step("Assert 'Add & Manage' button is displayed") { + onMainScreen { addAndManageButtonNode.assertIsDisplayed() } } } } @AllureId("8749") - @DisplayName("Main: check 'Organize tokens' button with single token two accounts") + @DisplayName("Main: check 'Add & Manage' button with single token two accounts") @Test fun checkOrganizeTokensButtonWithSingleTokenMultiAccountsTest() { val scenarioState = "TwoAccountsSingleTokenEach" @@ -81,14 +83,14 @@ class MainScreenTest : BaseTestCase() { step("Open 'Main Screen'") { openMainScreen() } - step("Assert 'Add & Manage' button is not displayed") { - onMainScreen { addAndManageButtonNode.assertIsNotDisplayed()} + step("Assert 'Add & Manage' button is displayed") { + onMainScreen { addAndManageButtonNode.assertIsDisplayed() } } } } @AllureId("8750") - @DisplayName("Main: check 'Organize tokens' button with multiple tokens two accounts") + @DisplayName("Main: check 'Add & Manage' button with multiple tokens two accounts") @Test fun checkOrganizeTokensButtonWithMultipleTokensMultiAccountsTest() { val scenarioState = "TwoAccountsMixed" @@ -106,8 +108,11 @@ class MainScreenTest : BaseTestCase() { step("Open 'Main Screen'") { openMainScreen() } + step("Swipe up") { + swipeVertical(SwipeDirection.UP, startHeightRatio = 0.6f, endHeightRatio = 0.1f) + } step("Assert 'Add & Manage' button is displayed") { - onMainScreen { addAndManageButtonNode.assertIsDisplayed()} + onMainScreen { addAndManageButtonNode.assertIsDisplayed() } } } } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/main/WarningsTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/main/WarningsTest.kt index 689da371e0..8510d1e1c6 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/main/WarningsTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/main/WarningsTest.kt @@ -16,7 +16,7 @@ import org.junit.Test class WarningsTest : BaseTestCase() { @AllureId("184") - @DisplayName("Token list: hide token by long tap") + @DisplayName("Warnings: missing address warning") @Test fun checkUnavailableNetworksWarningTest() { val scenarioState = "MissingDerivation" @@ -38,9 +38,6 @@ class WarningsTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses(isBalanceAvailable = false) } - step("Assert 'Missing addresses' notification icon is displayed") { - onMainScreen { missingAddressNotificationIcon.assertIsDisplayed() } - } step("Assert 'Missing addresses' notification title is displayed") { onMainScreen { missingAddressNotificationTitle.assertIsDisplayed() } } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/markets/MarketsExchangesTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/markets/MarketsExchangesTest.kt index fc17e54653..cef6601e65 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/markets/MarketsExchangesTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/markets/MarketsExchangesTest.kt @@ -1,5 +1,6 @@ package com.tangem.tests.markets +import androidx.compose.ui.test.ExperimentalTestApi import com.tangem.common.BaseTestCase import com.tangem.common.annotations.ApiEnv import com.tangem.common.annotations.ApiEnvConfig @@ -39,6 +40,7 @@ class MarketsExchangesTest : BaseTestCase() { } } + @OptIn(ExperimentalTestApi::class) @Test @AllureId("56") @ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD)) @@ -60,9 +62,8 @@ class MarketsExchangesTest : BaseTestCase() { onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() } waitForIdle() } - step("Scroll down") { - swipeVertical(SwipeDirection.UP) - swipeVertical(SwipeDirection.UP) + step("Scroll to 'Listed on exchanges' block") { + onMarketsScreen { scrollToListedOnBlock() } } step("Assert 'Listed on exchanges' block has title") { onMarketsScreen { listedOnBlockContainer.assertIsDisplayed() } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/RecentBlockTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/RecentBlockTest.kt index 37950eb1a3..ff84ea465b 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/RecentBlockTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/RecentBlockTest.kt @@ -227,7 +227,7 @@ class RecentBlockTest : BaseTestCase() { val sendAmount = "1" val txHistoryScenarioState = "11OutgoingTransactions" val recipientAddressBase = "DJ2TaZ5vvp3mBLugUpKjVM3pRBLi4uYaq" - val shortenedRecipientAddress = "DJ2TaZ5vvp3mBLugU...Li4uYaq123456789b" + val longRecipientAddress = recipientAddressBase + "123456789b" setupHooks( additionalAfterSection = { @@ -261,7 +261,7 @@ class RecentBlockTest : BaseTestCase() { checkRecentAddressItem(address = DOGECOIN_ADDRESS, description = recentTransactionAmount1) } step("Check recent address item №2") { - checkRecentAddressItem(address = shortenedRecipientAddress, description = recentTransactionAmount2) + checkRecentAddressItem(address = longRecipientAddress, description = recentTransactionAmount2) } step("Check recent address item №3") { checkRecentAddressItem(address = recipientAddressBase + "k", description = recentTransactionAmount2) diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt index 6f0000086b..49d9682e4e 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/addressScreen/SendAddressScreenTest.kt @@ -246,8 +246,11 @@ class SendAddressScreenTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() } } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") { setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState) diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/confirmScreen/SendConfirmScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/confirmScreen/SendConfirmScreenTest.kt index a9746ca3c1..4a8f00b331 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/confirmScreen/SendConfirmScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/confirmScreen/SendConfirmScreenTest.kt @@ -46,8 +46,11 @@ class SendConfirmScreenTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() } } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Type '$inputAmount' in input text field") { onSendScreen { @@ -123,8 +126,11 @@ class SendConfirmScreenTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() } } - step("Click on 'Send' button") { - onTokenDetailsScreen { sendButton().performClick() } + step("Click on 'Transfer' button") { + onTokenDetailsScreen { transferButton.clickWithAssertion() } + } + step("Click on 'Send' button in bottom sheet") { + onTransferBottomSheet { sendButton.clickWithAssertion() } } step("Type '$inputAmount' in input text field") { onSendScreen { diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/feeScreen/SendFeeScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/feeScreen/SendFeeScreenTest.kt index b9f6635d09..d67314ba1c 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/feeScreen/SendFeeScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/feeScreen/SendFeeScreenTest.kt @@ -281,13 +281,13 @@ class SendFeeScreenTest : BaseTestCase() { fun checkNetworkFeeBottomSheetForBitcoinTest() { val tokenName = "Bitcoin" val tokenAmount = "0.00000001" - val feeAmount = "$2.86" + val feeAmount = "$0.48" val fiatFeeAmount = "$0.24" val marketSelectorItem = getResourceString(R.string.common_fee_selector_option_market) val fastSelectorItem = getResourceString(R.string.common_fee_selector_option_fast) val slowSelectorItem = getResourceString(R.string.common_fee_selector_option_slow) val feeUpTo = getResourceString(R.string.send_max_fee) - val feeUpToValue = "0.0000264 BTC" + val feeUpToValue = "0.0000044 BTC" val newFeeUpToValue = "0.0000022 BTC" val satoshi = getResourceString(R.string.send_satoshi_per_byte_title) val satoshiValue = "2" diff --git a/app/src/androidTest/kotlin/com/tangem/tests/send/warnings/KaspaWarningsTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/send/warnings/KaspaWarningsTest.kt index 98b623c535..18d4af9a0a 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/send/warnings/KaspaWarningsTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/send/warnings/KaspaWarningsTest.kt @@ -4,10 +4,12 @@ import com.tangem.common.BaseTestCase import com.tangem.common.constants.TestConstants.KASPA_RECIPIENT_ADDRESS import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO +import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG import com.tangem.common.extensions.clickWithAssertion import com.tangem.common.utils.resetWireMockScenarioState import com.tangem.common.utils.setWireMockScenarioState import com.tangem.scenarios.checkSendWarning +import com.tangem.scenarios.openSendConfirmScreenViaNextButton import com.tangem.scenarios.openSendScreen import com.tangem.screens.onSendAddressScreen import com.tangem.screens.onSendScreen @@ -145,8 +147,10 @@ class KaspaWarningsTest : BaseTestCase() { step("Type address in input text field") { onSendAddressScreen { addressTextField.performTextReplacement(KASPA_RECIPIENT_ADDRESS) } } - step("Click on 'Next' button") { - onSendAddressScreen { nextButton.clickWithAssertion() } + step("Click 'Next' button until 'Send Confirm' screen opens") { + composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_LONG) { + runCatching { openSendConfirmScreenViaNextButton() }.isSuccess + } } step("Assert 'UTXO limit warning' is displayed") { checkSendWarning( diff --git a/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapStoriesTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapStoriesTest.kt index 13bc7aba06..e5f34ef64d 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapStoriesTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapStoriesTest.kt @@ -3,8 +3,6 @@ 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 import com.tangem.common.utils.setWireMockScenarioState @@ -18,101 +16,6 @@ import org.junit.Test @HiltAndroidTest class SwapStoriesTest : BaseTestCase() { - @AllureId("5453") - @DisplayName("Check 'Swap' button badge on 'Main' screen") - @Test - fun checkMainScreenSwapButtonBadgeTest() { - - setupHooks().run { - - step("Open 'Main Screen'") { - openMainScreen() - } - step("Synchronize addresses") { - synchronizeAddresses() - } - step("Assert 'Swap' button has badge") { - onMainScreen { swapButton.assertHasBadge() } - } - step("Open 'Swap' screen") { - openSwapScreen(from = SwapEntryPoint.MainScreen) - } - step("Click on 'Close' button") { - onSwapTokenScreen { closeButton.performClick() } - } - step("Assert 'Swap' button has not badge") { - onMainScreen { swapButton.assertHasBadge(false) } - } - } - } - - @AllureId("5454") - @DisplayName("Check 'Swap' button badge on token details screen") - @Test - fun checkTokenDetailsScreenSwapButtonTest() { - val tokenName = "Ethereum" - - setupHooks().run { - - step("Open 'Main Screen'") { - openMainScreen() - } - step("Synchronize addresses") { - synchronizeAddresses() - } - step("Click on token with name: '$tokenName'") { - onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() } - } - step("Assert 'Swap' button has badge") { - onTokenDetailsScreen { swapButton().assertHasBadge() } - } - step("Open 'Swap' screen") { - openSwapScreen(from = SwapEntryPoint.TokenDetails) - } - step("Click on 'Close' button") { - onSwapTokenScreen { closeButton.performClick() } - } - step("Assert 'Swap' button has not badge") { - onTokenDetailsScreen { swapButton().assertHasBadge(false) } - } - } - } - - @AllureId("5455") - @DisplayName("Check 'Swap' button badge on token details in 'Market' screen") - @Test - fun checkMarketTokenDetailsScreenSwapButtonTest() { - val tokenName = "Ethereum" - val badgeShown = "Badge shown" - val badgeHidden = "Badge hidden" - - setupHooks().run { - - step("Open 'Main Screen'") { - openMainScreen() - } - step("Synchronize addresses") { - synchronizeAddresses() - } - step("Open 'Markets' token details screen for token '$tokenName'") { - openMarketTokenDetailsScreen(blockchainName = tokenName, tokenName = tokenName) - } - step("Assert 'Swap' button has badge") { - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertIsDisplayed() } - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeShown) } - } - step("Open 'Swap' screen") { - openSwapScreen(from = SwapEntryPoint.MarketsTokenDetails) - } - step("Click on 'Close' button") { - onSwapTokenScreen { closeButton.performClick() } - } - step("Assert 'Swap' button has not badge") { - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeHidden) } - } - } - } - @AllureId("5469") @DisplayName("Check unavailable swap stories on 'Main' screen") @Test @@ -136,9 +39,6 @@ class SwapStoriesTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses() } - step("Assert 'Swap' button has not badge") { - onMainScreen { swapButton.assertHasBadge(false) } - } step("Open 'Swap' screen") { openSwapScreen(from = SwapEntryPoint.MainScreen, storiesExist = false) } @@ -155,9 +55,6 @@ class SwapStoriesTest : BaseTestCase() { waitForIdle() onMainScreen { swapButton.assertIsDisplayed() } } - step("Assert 'Swap' button has badge") { - onMainScreen { swapButton.assertHasBadge() } - } step("Open 'Swap' screen") { openSwapScreen(from = SwapEntryPoint.MainScreen, storiesExist = true) } @@ -192,9 +89,6 @@ class SwapStoriesTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() } } - step("Assert 'Swap' button has not badge") { - onTokenDetailsScreen { swapButton().assertHasBadge(false) } - } step("Open 'Swap' screen") { openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = false) } @@ -207,13 +101,6 @@ class SwapStoriesTest : BaseTestCase() { step("Restart app") { restartApp(packageName) } - step("Assert 'Swap' button has badge") { - waitForIdle() - flakySafely(WAIT_UNTIL_TIMEOUT) { - composeTestRule.mainClock.advanceTimeBy(500) - onMainScreen { swapButton.assertHasBadge() } - } - } step("Open 'Swap' screen") { openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = true) } @@ -228,8 +115,6 @@ class SwapStoriesTest : BaseTestCase() { val scenarioErrorState = "Error" val packageName = getTargetContext().packageName val tokenName = "Ethereum" - val badgeShown = "Badge shown" - val badgeHidden = "Badge hidden" setupHooks( additionalBeforeAppLaunchSection = { @@ -246,16 +131,15 @@ class SwapStoriesTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses() } - step("Open 'Markets' token details screen for token '$tokenName'") { - openMarketTokenDetailsScreen(blockchainName = tokenName, tokenName = tokenName) + step("Open 'Token details' from 'Markets' screen for token '$tokenName'") { + openTokenDetailsFromMarketsScreen(blockchainName = tokenName, tokenName = tokenName) } - step("Assert 'Swap' button has not badge") { + step("Assert 'Swap' button is displayed") { waitForIdle() - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertIsDisplayed() } - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeHidden) } + onTokenDetailsScreen { swapButton.assertIsDisplayed() } } step("Open 'Swap' screen") { - openSwapScreen(from = SwapEntryPoint.MarketsTokenDetails, storiesExist = false) + openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = false) } step("Click on 'Close' button") { onSwapTokenScreen { closeButton.performClick() } @@ -266,16 +150,12 @@ class SwapStoriesTest : BaseTestCase() { step("Restart app") { restartApp(packageName) } - step("Open 'Markets' token details screen for token '$tokenName'") { - openMarketTokenDetailsScreen(blockchainName = tokenName, tokenName = tokenName) - } - step("Assert 'Swap' button has badge") { + step("Assert 'Swap' button is displayed") { waitForIdle() - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertIsDisplayed() } - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeShown) } + onTokenDetailsScreen { swapButton.assertIsDisplayed() } } step("Open 'Swap' screen") { - openSwapScreen(from = SwapEntryPoint.MarketsTokenDetails, storiesExist = true) + openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = true) } } } @@ -331,11 +211,8 @@ class SwapStoriesTest : BaseTestCase() { step("Click on token with name: '$tokenName'") { onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() } } - step("Assert 'Swap' button has badge") { - onTokenDetailsScreen { swapButton().assertHasBadge() } - } step("Click on 'Swap' button on 'Token details' screen") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Check stories changes") { checkStoriesChanges() @@ -369,11 +246,11 @@ class SwapStoriesTest : BaseTestCase() { step("Synchronize addresses") { synchronizeAddresses() } - step("Open 'Markets' token details screen for token '$tokenName'") { - openMarketTokenDetailsScreen(blockchainName = tokenName, tokenName = tokenName) + step("Open 'Token details' from 'Markets' screen for token '$tokenName'") { + openTokenDetailsFromMarketsScreen(blockchainName = tokenName, tokenName = tokenName) } step("Click on 'Swap' button on 'Markets' token details screen") { - onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Check stories changes") { checkStoriesChanges() @@ -388,7 +265,7 @@ class SwapStoriesTest : BaseTestCase() { onSwapTokenScreen { closeButton.performClick() } } step("Open 'Swap' screen without stories") { - openSwapScreen(from = SwapEntryPoint.MarketsTokenDetails, storiesExist = false) + openSwapScreen(from = SwapEntryPoint.TokenDetails, storiesExist = false) } } } @@ -433,6 +310,17 @@ class SwapStoriesTest : BaseTestCase() { step("Click on 'Close' button") { onSwapTokenScreen { closeButton.performClick() } } + step("Long click on token with name: '$tokenName' again to reopen actions menu") { + waitForIdle() + onMainScreen { + tokenWithTitleAndAddress(tokenName).performTouchInput { + longClick( + position = center, + durationMillis = 1000L, + ) + } + } + } step("Open 'Swap' screen without stories") { openSwapScreen(from = SwapEntryPoint.TokenActionsBottomSheet, storiesExist = false) } diff --git a/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapTokenScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapTokenScreenTest.kt index 94092b1e2f..7137918e72 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapTokenScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/swap/SwapTokenScreenTest.kt @@ -50,7 +50,7 @@ class SwapTokenScreenTest : BaseTestCase() { onTokenDetailsScreen { title.assertIsDisplayed() } } step("Click on 'Swap' button") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Close 'Stories' screen") { onSwapStoriesScreen { closeButton.clickWithAssertion() } @@ -147,7 +147,7 @@ class SwapTokenScreenTest : BaseTestCase() { disableMobileData() } step("Click on 'Swap' button") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Close 'Stories' screen") { onSwapStoriesScreen { closeButton.clickWithAssertion() } @@ -201,7 +201,7 @@ class SwapTokenScreenTest : BaseTestCase() { onTokenDetailsScreen { title.assertIsDisplayed() } } step("Click on 'Swap' button") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Close 'Stories' screen") { onSwapStoriesScreen { closeButton.clickWithAssertion() } @@ -304,7 +304,7 @@ class SwapTokenScreenTest : BaseTestCase() { onTokenDetailsScreen { title.assertIsDisplayed() } } step("Click on 'Swap' button") { - onTokenDetailsScreen { swapButton().performClick() } + onTokenDetailsScreen { swapButton.performClick() } } step("Close 'Stories' screen") { onSwapStoriesScreen { closeButton.clickWithAssertion() } @@ -510,7 +510,7 @@ class SwapTokenScreenTest : BaseTestCase() { onMainScreen { tokenWithTitleAndAddress(polygon).clickWithAssertion() } } step("Assert 'Swap' button is not dimmed. Swap available") { - onTokenDetailsScreen { swapButton().assertIsDimmed(false) } + onTokenDetailsScreen { swapButton.assertIsEnabled() } } step("Press 'Back' button") { device.uiDevice.pressBack() @@ -519,7 +519,7 @@ class SwapTokenScreenTest : BaseTestCase() { onMainScreen { tokenWithTitleAndAddress(bitcoin).clickWithAssertion() } } step("Assert 'Swap' button is dimmed") { - onTokenDetailsScreen { swapButton().assertIsDimmed(true) } + onTokenDetailsScreen { swapButton.assertIsNotEnabled() } } step("Press 'Back' button") { device.uiDevice.pressBack() @@ -528,7 +528,7 @@ class SwapTokenScreenTest : BaseTestCase() { onMainScreen { tokenWithTitleAndAddress(salam).clickWithAssertion() } } step("Assert 'Swap' button is dimmed") { - onTokenDetailsScreen { swapButton().assertIsDimmed(true) } + onTokenDetailsScreen { swapButton.assertIsNotEnabled() } } } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/earn/EarnBlock.kt b/common/ui/src/main/java/com/tangem/common/ui/earn/EarnBlock.kt index da370bebe6..fbd260125a 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/earn/EarnBlock.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/earn/EarnBlock.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.draw.BlurredEdgeTreatment import androidx.compose.ui.draw.blur import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.innerShadow +import androidx.compose.ui.platform.testTag import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.shadow.Shadow @@ -38,6 +39,7 @@ import com.tangem.core.ui.ds.row.TangemRowLayoutId import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign +import com.tangem.core.ui.test.TokenDetailsScreenTestTags import com.tangem.core.res.R as CoreResR private const val TINTED_BACKGROUND_ALPHA = 0.1f @@ -179,17 +181,23 @@ private fun EarnBlockTrailing(type: Type, trailingUM: EarnBlockUM.TrailingUM?, o } is EarnBlockUM.TrailingUM.Balance -> { if (!trailingUM.isBalanceHidden) { + val fiatModifier = Modifier.layoutId(TangemRowLayoutId.END_TOP).let { + if (type == Type.Staking) it.testTag(TokenDetailsScreenTestTags.STAKING_FIAT_AMOUNT) else it + } + val cryptoModifier = Modifier.layoutId(TangemRowLayoutId.END_BOTTOM).let { + if (type == Type.Staking) it.testTag(TokenDetailsScreenTestTags.STAKING_TOKEN_AMOUNT) else it + } Text( text = trailingUM.fiatValue.resolveAnnotatedReference(), style = TangemTheme.typography2.bodySemibold16, color = TangemTheme.colors2.text.neutral.primary, - modifier = Modifier.layoutId(TangemRowLayoutId.END_TOP), + modifier = fiatModifier, ) Text( text = trailingUM.cryptoValue.resolveReference(), style = TangemTheme.typography2.captionMedium12, color = TangemTheme.colors2.text.neutral.secondary, - modifier = Modifier.layoutId(TangemRowLayoutId.END_BOTTOM), + modifier = cryptoModifier, ) } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt index 368bf293c7..875515992a 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/expressStatus/ExpressStatusItems.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import com.tangem.common.ui.R @@ -35,6 +36,7 @@ import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign +import com.tangem.core.ui.test.TokenDetailsScreenTestTags import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -78,7 +80,8 @@ private fun ExpressTransactionItem( .clip(TangemTheme.shapes.roundedCornersXMedium) .background(TangemTheme.colors2.surface.level3) .clickable(onClick = info.onClick) - .padding(TangemTheme.dimens2.x4), + .padding(TangemTheme.dimens2.x4) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM), ) { TitleRow( title = info.title.resolveReference(), @@ -104,7 +107,9 @@ private fun TitleRow(title: String, infoIconRes: Int?, infoIconTint: Color?) { text = title, style = TangemTheme.typography2.bodyMedium16, color = TangemTheme.colors3.text.primary, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_TITLE), ) if (infoIconRes != null && infoIconTint != null) { Icon( @@ -126,32 +131,42 @@ private fun AmountsRow(info: ExpressTransactionStateInfoUM) { CurrencyIcon( state = info.fromCurrencyIcon, shouldDisplayNetwork = false, - modifier = Modifier.size(TangemTheme.dimens.size18), + modifier = Modifier + .size(TangemTheme.dimens.size18) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_FROM_ICON), ) EllipsisText( text = info.fromAmount.resolveReference(), style = TangemTheme.typography2.bodyMedium16, color = TangemTheme.colors3.text.primary, ellipsis = TextEllipsis.OffsetEnd(info.fromAmountSymbol.length), - modifier = Modifier.weight(weight = 1f, fill = false), + modifier = Modifier + .weight(weight = 1f, fill = false) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_FROM_AMOUNT), ) Icon( painter = painterResource(R.drawable.ic_forward_24), contentDescription = null, tint = TangemTheme.colors3.icon.tertiary, - modifier = Modifier.size(TangemTheme.dimens.size18), + modifier = Modifier + .size(TangemTheme.dimens.size18) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_SWAP_ICON), ) CurrencyIcon( state = info.toCurrencyIcon, shouldDisplayNetwork = false, - modifier = Modifier.size(TangemTheme.dimens.size18), + modifier = Modifier + .size(TangemTheme.dimens.size18) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_TO_ICON), ) EllipsisText( text = info.toAmount.resolveReference(), style = TangemTheme.typography2.bodyMedium16, color = TangemTheme.colors3.text.primary, ellipsis = TextEllipsis.OffsetEnd(info.toAmountSymbol.length), - modifier = Modifier.weight(weight = 1f, fill = false), + modifier = Modifier + .weight(weight = 1f, fill = false) + .testTag(TokenDetailsScreenTestTags.EXPRESS_STATUS_ITEM_TO_AMOUNT), ) } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt b/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt index ebfad19e9c..9941a44e01 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokenaction/TokenActionRow.kt @@ -19,6 +19,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.layoutId import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.semantics.disabled +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.tangem.core.ui.R import com.tangem.core.ui.ds.row.TangemRowContainer @@ -68,7 +70,8 @@ fun TokenActionRow( onClick = onClick, onLongClick = onLongClick, hapticManager = hapticManager, - ), + ) + .semantics { if (!isEnabled) disabled() }, ) { LeadingIcon(iconRes = iconRes, accentColor = accentColor) Text( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt index a286a52db4..b597df325e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/TangemBottomSheet.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -39,6 +40,7 @@ import com.tangem.core.ui.res.LocalBottomSheetAlwaysVisible import com.tangem.core.ui.res.LocalWindowSize import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign +import com.tangem.core.ui.test.BaseBottomSheetTestTags import com.tangem.core.ui.utils.WindowInsetsZero /** @@ -253,7 +255,8 @@ inline fun BasicBottomSheet( Column( modifier = contentModifier .background(containerColor) - .heightIn(max = maxHeight), + .heightIn(max = maxHeight) + .testTag(BaseBottomSheetTestTags.CONTAINER), ) { Box(modifier = Modifier.fillMaxWidth()) { title(model) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt index 23b9f3979b..988177e57c 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/bottomsheets/modal/TangemModalBottomSheet.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -40,6 +41,7 @@ import com.tangem.core.ui.components.sheetscaffold.TangemSheetState import com.tangem.core.ui.components.sheetscaffold.TangemSheetValue import com.tangem.core.ui.components.sheetscaffold.rememberSheetState import com.tangem.core.ui.res.* +import com.tangem.core.ui.test.BaseBottomSheetTestTags import com.tangem.core.ui.utils.WindowInsetsZero const val MODAL_SHEET_MAX_HEIGHT = 0.8f @@ -205,7 +207,8 @@ inline fun BsContent( .background(containerColor) .heightIn(max = maxHeight.dp) .fillMaxWidth() - .nestedScroll(nestedScrollConnection), + .nestedScroll(nestedScrollConnection) + .testTag(BaseBottomSheetTestTags.CONTAINER), ) { Box(modifier = Modifier.fillMaxWidth()) { title(model) diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/button/action/ActionButtons.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/button/action/ActionButtons.kt index fc7c6c2af8..94c0d8aaa8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/button/action/ActionButtons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/button/action/ActionButtons.kt @@ -10,6 +10,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.key import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.disabled +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -25,6 +28,7 @@ import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign +import com.tangem.core.ui.test.BaseActionButtonsBlockTestTags import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -51,7 +55,10 @@ fun ActionButtons(buttons: ImmutableList, modifier: Modifier = M TangemTheme.colors2.text.status.disabled } Column( - modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x2_5), + modifier = Modifier + .padding(horizontal = TangemTheme.dimens2.x2_5) + .testTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON) + .semantics { if (!button.isEnabled) disabled() }, verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2), horizontalAlignment = Alignment.CenterHorizontally, ) { diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt index 8495036ca7..282be7cef8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessage.kt @@ -19,9 +19,11 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import com.tangem.core.ui.R +import com.tangem.core.ui.test.NotificationTestTags import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsState import com.tangem.core.ui.ds.button.* @@ -66,7 +68,8 @@ fun TangemMessage( Alignment.Top }, ) - .size(messageUM.iconSize), + .size(messageUM.iconSize) + .testTag(NotificationTestTags.ICON), ) } }, @@ -115,14 +118,14 @@ fun TangemMessage( Image( painter = painterResource(config.iconResId), contentDescription = null, - modifier = Modifier.size(config.iconSize), + modifier = Modifier.size(config.iconSize).testTag(NotificationTestTags.ICON), ) } else { Icon( imageVector = ImageVector.vectorResource(config.iconResId), contentDescription = null, tint = iconTint, - modifier = Modifier.size(config.iconSize), + modifier = Modifier.size(config.iconSize).testTag(NotificationTestTags.ICON), ) } }, @@ -166,7 +169,7 @@ fun TangemMessage( } else { Alignment.Start } - Box(modifier = modifier) { + Box(modifier = modifier.testTag(NotificationTestTags.CONTAINER)) { Box( modifier = Modifier .matchParentSize() @@ -244,6 +247,7 @@ private fun TangemMessageContent( color = TangemTheme.colors2.text.neutral.primary, maxLines = 1, textAlign = textAlign, + modifier = Modifier.testTag(NotificationTestTags.TITLE), ) } if (subtitle != null) { @@ -252,6 +256,7 @@ private fun TangemMessageContent( text = subtitle.resolveAnnotatedReference(), style = TangemTheme.typography2.captionSemibold12, color = TangemTheme.colors2.text.neutral.secondary, + modifier = Modifier.testTag(NotificationTestTags.MESSAGE), ) } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/BaseBottomSheetTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/BaseBottomSheetTestTags.kt index ccf4a1033e..f1cdb64dcb 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/test/BaseBottomSheetTestTags.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/test/BaseBottomSheetTestTags.kt @@ -1,6 +1,7 @@ package com.tangem.core.ui.test object BaseBottomSheetTestTags { + const val CONTAINER = "BASE_BOTTOM_SHEET_CONTAINER" const val ACTION_BUTTON = "BASE_BOTTOM_SHEET_ACTION_BUTTON" const val ACTION_ICON = "BASE_BOTTOM_SHEET_ACTION_ICON" const val TITLE = "BASE_BOTTOM_SHEET_TITLE" diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/MarketsTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/MarketsTestTags.kt index 9569e50d89..49829a1eda 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/test/MarketsTestTags.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/test/MarketsTestTags.kt @@ -4,4 +4,6 @@ object MarketsTestTags { const val TOKENS_LIST = "MARKETS_TOKENS_LIST" const val TOKENS_LIST_ITEM = "MARKETS_TOKENS_LIST_ITEM" const val LISTED_ON_EXCHANGES_COUNT = "MARKETS_LISTED_ON_EXCHANGES_COUNT" + const val LISTED_ON_BLOCK = "MARKETS_LISTED_ON_BLOCK" + const val TOKEN_DETAILS_CONTENT = "MARKETS_TOKEN_DETAILS_CONTENT" } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/OrganizeTokensScreenTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/OrganizeTokensScreenTestTags.kt index 1bcf552c56..e351290af8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/test/OrganizeTokensScreenTestTags.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/test/OrganizeTokensScreenTestTags.kt @@ -2,6 +2,7 @@ package com.tangem.core.ui.test object OrganizeTokensScreenTestTags { // region OrganizeTokensTopBar + const val MENU_BUTTON = "ORGANIZE_TOKENS_MENU_BUTTON" const val GROUP_BUTTON = "ORGANIZE_TOKENS_GROUP_BUTTON" const val SORT_BY_BALANCE_BUTTON = "SORT_BY_BALANCE_BUTTON" // endregion OrganizeTokensTopBar diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt index d9dd9222f6..09ac1d2352 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/MarketsTokenDetailsContent.kt @@ -17,6 +17,8 @@ import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag +import com.tangem.core.ui.test.MarketsTestTags import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -116,6 +118,7 @@ private fun Content( LazyColumn( state = lazyListState, contentPadding = PaddingValues(bottom = bottomBarHeight, top = contentPadding.calculateTopPadding()), + modifier = Modifier.testTag(MarketsTestTags.TOKEN_DETAILS_CONTENT), ) { item("header") { Header(state = state) diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ExchangesBottomSheet.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ExchangesBottomSheet.kt index d613f5e228..e41fb40418 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ExchangesBottomSheet.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ExchangesBottomSheet.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -48,6 +49,7 @@ import com.tangem.core.ui.ds.topbar.TangemTopBar import com.tangem.core.ui.ds.topbar.TangemTopBarType import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.LocalRedesignEnabled +import com.tangem.core.ui.test.TokenElementsTestTags import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.core.ui.res.TangemThemePreviewRedesign @@ -314,13 +316,15 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif tangemIconUM = exchangeItemUM.icon, modifier = Modifier .layoutId(layoutId = TangemRowLayoutId.HEAD) - .size(TangemTheme.dimens2.x10), + .size(TangemTheme.dimens2.x10) + .testTag(TokenElementsTestTags.TOKEN_ICON), ) Text( modifier = Modifier .padding(start = TangemTheme.dimens2.x2) - .layoutId(TangemRowLayoutId.START_TOP), + .layoutId(TangemRowLayoutId.START_TOP) + .testTag(TokenElementsTestTags.TOKEN_TITLE), text = exchangeItemUM.title.resolveReference(), style = TangemTheme.typography2.bodySemibold16, color = TangemTheme.colors2.text.neutral.primary, @@ -329,7 +333,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif Text( modifier = Modifier .padding(start = TangemTheme.dimens2.x2) - .layoutId(TangemRowLayoutId.START_BOTTOM), + .layoutId(TangemRowLayoutId.START_BOTTOM) + .testTag(TokenElementsTestTags.TOKEN_PRICE), text = exchangeItemUM.subTitle.resolveReference(), style = TangemTheme.typography2.captionSemibold12, color = TangemTheme.colors2.text.neutral.secondary, @@ -338,7 +343,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif Text( modifier = Modifier .padding(start = TangemTheme.dimens2.x2) - .layoutId(TangemRowLayoutId.END_TOP), + .layoutId(TangemRowLayoutId.END_TOP) + .testTag(TokenElementsTestTags.TOKEN_FIAT_AMOUNT_TEXT), text = exchangeItemUM.volumeInUsd.resolveReference(), style = TangemTheme.typography2.bodySemibold16, color = TangemTheme.colors2.text.neutral.primary, @@ -351,7 +357,8 @@ private fun ExchangeItemRowContent(exchangeItemUM: ExchangeItemUM.Content, modif shape = CircleShape, ) .padding(vertical = 2.dp, horizontal = 6.dp) - .layoutId(TangemRowLayoutId.END_BOTTOM), + .layoutId(TangemRowLayoutId.END_BOTTOM) + .testTag(TokenElementsTestTags.TOKEN_CRYPTO_AMOUNT), text = exchangeItemUM.auditLabel.text.resolveReference(), style = TangemTheme.typography2.captionSemibold11, color = getColorByTrustValue(exchangeItemUM.auditLabel.type), diff --git a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ListedOnBlock.kt b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ListedOnBlock.kt index a8f1472bd7..5691e27dcb 100644 --- a/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ListedOnBlock.kt +++ b/features/feed/impl/src/main/kotlin/com/tangem/features/feed/ui/market/detailed/components/ListedOnBlock.kt @@ -10,10 +10,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTag import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -65,7 +64,8 @@ private fun ListedOnBlockV1(state: ListedOnUM, modifier: Modifier = Modifier) { .clip(shape = TangemTheme.shapes.roundedCornersXMedium) .clickable(enabled = state is ListedOnUM.Content) { (state as? ListedOnUM.Content)?.onClick?.invoke() - }, + } + .testTag(MarketsTestTags.LISTED_ON_BLOCK), ) { Description( state = state, @@ -89,9 +89,11 @@ private fun ListedOnBlockV1(state: ListedOnUM, modifier: Modifier = Modifier) { @Composable private fun ListedOnBlockV2(state: ListedOnUM, modifier: Modifier = Modifier) { TokenMarketInformationBlock( - modifier = modifier.clickable(enabled = state is ListedOnUM.Content) { - (state as? ListedOnUM.Content)?.onClick?.invoke() - }, + modifier = modifier + .clickable(enabled = state is ListedOnUM.Content) { + (state as? ListedOnUM.Content)?.onClick?.invoke() + } + .testTag(MarketsTestTags.LISTED_ON_BLOCK), title = { Row(verticalAlignment = Alignment.CenterVertically) { Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x1)) { @@ -103,6 +105,7 @@ private fun ListedOnBlockV2(state: ListedOnUM, modifier: Modifier = Modifier) { overflow = TextOverflow.Ellipsis, ) Text( + modifier = Modifier.testTag(MarketsTestTags.LISTED_ON_EXCHANGES_COUNT), text = state.description.resolveReference(), style = TangemTheme.typography2.headingSemibold20, color = TangemTheme.colors2.text.neutral.primary, @@ -178,7 +181,7 @@ internal fun ListedOnBlockPlaceholderV2(modifier: Modifier = Modifier) { private fun Description(state: ListedOnUM, modifier: Modifier = Modifier) { Text( text = state.description.resolveReference(), - modifier = modifier.semantics { testTag = MarketsTestTags.LISTED_ON_EXCHANGES_COUNT }, + modifier = modifier.testTag(MarketsTestTags.LISTED_ON_EXCHANGES_COUNT), color = TangemTheme.colors.text.tertiary, overflow = TextOverflow.Ellipsis, maxLines = 1, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt index ba581e7537..31eaefbf5e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsScreen.kt @@ -13,12 +13,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.common.ui.account.AccountIconUM import com.tangem.common.ui.earn.EarnBlock +import com.tangem.common.ui.earn.EarnBlockUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.common.ui.expressStatus.state.ExpressTransactionsBlockState import com.tangem.common.ui.notifications.notifications @@ -35,6 +37,7 @@ import com.tangem.core.ui.ds.button.TangemButtonUM import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.themedColor import com.tangem.core.ui.res.LocalHazeState +import com.tangem.core.ui.test.TokenDetailsScreenTestTags import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.domain.models.account.CryptoPortfolioIcon @@ -140,7 +143,7 @@ private fun BoxScope.TokenDetailsMarketBlockOverlay( ) } -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LongMethod") @Composable private fun TokenDetailsBody( tokenDetailsUM: TokenDetailsUM, @@ -165,6 +168,7 @@ private fun TokenDetailsBody( LazyColumn( modifier = modifier + .testTag(TokenDetailsScreenTestTags.SCREEN_CONTAINER) .hazeSourceTangem(state = LocalHazeState.current) .topFade( height = topContentPadding, @@ -190,9 +194,18 @@ private fun TokenDetailsBody( ) tokenDetailsUM.earnBlockState?.let { earnBlock -> item(key = "staking_block") { + val stakingTag = when { + earnBlock is EarnBlockUM.Content && + earnBlock.type == EarnBlockUM.Type.Staking && + earnBlock.trailingUM is EarnBlockUM.TrailingUM.Button -> + TokenDetailsScreenTestTags.STAKING_AVAILABLE_BLOCK + else -> TokenDetailsScreenTestTags.STAKING_BLOCK + } EarnBlock( state = earnBlock, - modifier = itemModifier.padding(vertical = TangemTheme.dimens2.x3), + modifier = itemModifier + .padding(vertical = TangemTheme.dimens2.x3) + .testTag(stakingTag), ) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsTopBar.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsTopBar.kt index a25b282c16..a79ceb5399 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsTopBar.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/TokenDetailsTopBar.kt @@ -16,9 +16,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.text.* +import androidx.compose.ui.platform.testTag +import com.tangem.core.ui.test.TokenDetailsScreenTestTags +import com.tangem.core.ui.test.TokenDetailsTopBarTestTags +import androidx.compose.ui.text.Placeholder +import androidx.compose.ui.text.PlaceholderVerticalAlign +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -58,7 +67,9 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier: .clip(CircleShape) .hazeEffectTangem { blurRadius = ACTION_BLUR_RADIUS } TangemTopBar( - modifier = modifier.statusBarsPadding(), + modifier = modifier + .statusBarsPadding() + .testTag(TokenDetailsTopBarTestTags.BACK_BUTTON), startContent = { TangemTopBarActionContent( modifier = actionModifier, @@ -73,7 +84,7 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier: var isDropdownMenuShown by rememberSaveable { mutableStateOf(false) } Box { TangemTopBarActionContent( - modifier = actionModifier, + modifier = actionModifier.testTag(TokenDetailsTopBarTestTags.MORE_BUTTON), actionUM = TangemTopBarActionUM( iconRes = CoreUiR.drawable.ic_more_default_24, onClick = { isDropdownMenuShown = true }, @@ -105,7 +116,9 @@ internal fun TokenDetailsTopBar(topAppBarUM: TokenDetailsTopAppBarUM, modifier: horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x0_5), ) { - TokenDetailsTitle(titleState = topAppBarUM.titleState) + Box(modifier = Modifier.testTag(TokenDetailsScreenTestTags.TOKEN_TITLE)) { + TokenDetailsTitle(titleState = topAppBarUM.titleState) + } Text( text = topAppBarUM.subtitle.resolveAnnotatedReference(), color = TangemTheme.colors2.text.neutral.tertiary, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/ui/OrganizeTokensContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/ui/OrganizeTokensContent.kt index f1c3b50e57..0c08233a68 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/ui/OrganizeTokensContent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/organizetokens/ui/OrganizeTokensContent.kt @@ -96,6 +96,7 @@ internal fun OrganizeTokensContent( onClick = { isShowDropdownMenu = true }, ghostModeProgress = 0f, ), + modifier = Modifier.testTag(OrganizeTokensScreenTestTags.MENU_BUTTON), type = TangemTopBarType.BottomSheet, ) OrganizeDropDownMenu( @@ -161,8 +162,7 @@ private fun TokenList( modifier = Modifier .align(Alignment.TopCenter) .reorderable(reorderableListState) - .testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST) - .hazeSourceTangem(zIndex = 1f), + .testTag(OrganizeTokensScreenTestTags.TOKENS_LAZY_LIST), state = reorderableListState.listState, contentPadding = listContentPadding, ) { @@ -221,7 +221,7 @@ private fun LazyItemScope.DraggableItem( when (item) { is OrganizeRowItemUM.Network -> TangemHeaderRow( - modifier = modifierWithBackground, + modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.GROUP_TITLE_ITEM), reorderableState = reorderableState, headerRowUM = item.headerRowUM, ) @@ -231,7 +231,7 @@ private fun LazyItemScope.DraggableItem( isBalanceHidden = isBalanceHidden, ) is OrganizeRowItemUM.Token -> OrganizeTokenRow( - modifier = modifierWithBackground, + modifier = modifierWithBackground.testTag(OrganizeTokensScreenTestTags.TOKEN_LIST_ITEM), tokenRowUM = item.tokenRowUM, reorderableState = reorderableState, isBalanceHidden = isBalanceHidden, @@ -262,11 +262,15 @@ private fun BoxScope.BottomButtons(organizeTokensUM: OrganizeTokensUM) { ) { TangemButton( buttonUM = organizeTokensUM.cancelButton, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag(OrganizeTokensScreenTestTags.CANCEL_BUTTON), ) TangemButton( buttonUM = organizeTokensUM.applyButton, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .testTag(OrganizeTokensScreenTestTags.APPLY_BUTTON), ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/tokenActions/TokenActionContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/tokenActions/TokenActionContent.kt index aebf8404a9..449d0a9eb0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/tokenActions/TokenActionContent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/tokenActions/TokenActionContent.kt @@ -14,6 +14,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.testTag +import com.tangem.core.ui.test.BaseBottomSheetTestTags import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpOffset @@ -101,6 +103,7 @@ private fun TokenActionContextMenuContent(actions: ImmutableList - TangemTopBarActionContent(action) + TangemTopBarActionContent( + action, + modifier = Modifier.testTag(MainScreenTestTags.MORE_BUTTON), + ) } } },