Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-24 12:44:09 +03:00
parent 8db160652c
commit 20682ca353
10 changed files with 393 additions and 47 deletions

View file

@ -0,0 +1,41 @@
package com.tangem.scenarios
import com.tangem.common.BaseTestCase
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.screens.onReceiveAssetsBottomSheet
import com.tangem.screens.onTokenReceiveQrCodeBottomSheet
import com.tangem.screens.onTokenReceiveWarningBottomSheet
import io.qameta.allure.kotlin.Allure.step
fun BaseTestCase.goToQrCodeBottomSheet() {
step("Assert 'Token receive warning' bottom sheet is displayed") {
onTokenReceiveWarningBottomSheet { bottomSheet.assertIsDisplayed() }
}
step("Click on 'Got it' button") {
onTokenReceiveWarningBottomSheet { gotItButton.performClick() }
}
step("Click on 'Show QR code' button") {
onReceiveAssetsBottomSheet { showQrCodeButton.clickWithAssertion() }
}
}
fun BaseTestCase.checkQrCodeBottomSheetScenario() {
step("Assert bottom sheet with QR code title is displayed") {
onTokenReceiveQrCodeBottomSheet { title.assertIsDisplayed() }
}
step("Assert QR code is displayed") {
onTokenReceiveQrCodeBottomSheet { qrCode.assertIsDisplayed() }
}
step("Assert address title is displayed") {
onTokenReceiveQrCodeBottomSheet { addressTitle.assertIsDisplayed() }
}
step("Assert address is displayed") {
onTokenReceiveQrCodeBottomSheet { address.assertIsDisplayed() }
}
step("Assert 'Copy' button is displayed") {
onTokenReceiveQrCodeBottomSheet { copyButton.assertIsDisplayed() }
}
step("Assert 'Share' button is displayed") {
onTokenReceiveQrCodeBottomSheet { shareButton.assertIsDisplayed() }
}
}

View file

@ -0,0 +1,30 @@
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.BaseButtonTestTags
import com.tangem.core.ui.test.BaseDialogTestTags
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 com.tangem.common.ui.R as CommonUIR
class OperationIsUnavailableDialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<OperationIsUnavailableDialogPageObject>(semanticsProvider = semanticsProvider) {
val text: KNode = child {
hasTestTag(BaseDialogTestTags.TEXT)
hasText(getResourceString(CommonUIR.string.token_button_unavailability_generic_description))
useUnmergedTree = true
}
val okButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.common_ok))
}
}
internal fun BaseTestCase.onOperationIsUnavailableDialog(function: OperationIsUnavailableDialogPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -0,0 +1,35 @@
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.BaseButtonTestTags
import com.tangem.core.ui.test.BaseDialogTestTags
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 com.tangem.common.ui.R as CommonUIR
class SwapIsNotSupportedDialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<SwapIsNotSupportedDialogPageObject>(semanticsProvider = semanticsProvider) {
fun text(currencyName: String): KNode = child {
hasTestTag(BaseDialogTestTags.TEXT)
hasText(
getResourceString(
CommonUIR.string.token_button_unavailability_reason_not_exchangeable,
currencyName
)
)
useUnmergedTree = true
}
val okButton: KNode = child {
hasTestTag(BaseButtonTestTags.BUTTON)
hasText(getResourceString(R.string.common_ok))
}
}
internal fun BaseTestCase.onSwapIsNotSupportedDialog(function: SwapIsNotSupportedDialogPageObject.() -> Unit) =
onComposeScreen(composeTestRule, function)

View file

@ -97,25 +97,31 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
)
@OptIn(ExperimentalTestApi::class)
val swapButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
fun receiveButton(): LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
hasText(getResourceString(R.string.common_receive))
}
@OptIn(ExperimentalTestApi::class)
fun swapButton(): LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
hasText(getResourceString(R.string.common_swap))
}
@OptIn(ExperimentalTestApi::class)
val sellButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
fun sellButton(): LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
hasText(getResourceString(R.string.common_sell))
}
@OptIn(ExperimentalTestApi::class)
val buyButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
fun buyButton(): LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
hasText(getResourceString(R.string.common_buy))
}
@OptIn(ExperimentalTestApi::class)
val sendButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
fun sendButton(): LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
hasText(getResourceString(R.string.common_send))
}

View file

@ -55,7 +55,7 @@ class BlockchainTest : BaseTestCase() {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click on 'Send' button") {
onTokenDetailsScreen { sendButton.performClick() }
onTokenDetailsScreen { sendButton().performClick() }
}
step("Type '$errorSendAmount' in input text field") {
onSendScreen {

View file

@ -73,7 +73,7 @@ class FeedbackTest : BaseTestCase() {
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
}
step("Click 'Send' button") {
onTokenDetailsScreen { sendButton.performClick() }
onTokenDetailsScreen { sendButton().performClick() }
}
step("Type '$sendAmount' in input text field") {
onSendScreen {

View file

@ -47,7 +47,7 @@ class SwapTokenTest : BaseTestCase() {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton.performClick() }
onTokenDetailsScreen { swapButton().performClick() }
}
step("Close 'Stories' screen") {
onSwapStoriesScreen { closeButton.clickWithAssertion() }
@ -131,7 +131,7 @@ class SwapTokenTest : BaseTestCase() {
disableMobileData()
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton.performClick() }
onTokenDetailsScreen { swapButton().performClick() }
}
step("Close 'Stories' screen") {
onSwapStoriesScreen { closeButton.clickWithAssertion() }
@ -175,7 +175,7 @@ class SwapTokenTest : BaseTestCase() {
onTokenDetailsScreen { title.assertIsDisplayed() }
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton.performClick() }
onTokenDetailsScreen { swapButton().performClick() }
}
step("Close 'Stories' screen") {
onSwapStoriesScreen { closeButton.clickWithAssertion() }

View file

@ -6,14 +6,8 @@ import com.tangem.common.constants.TestConstants.BITCOIN_ADDRESS
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.*
import com.tangem.common.utils.assertClipboardTextEquals
import com.tangem.common.utils.clearClipboard
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.scenarios.assertActionButtonsForMultiCurrencyWallet
import com.tangem.scenarios.checkActionIsUnavailableDialog
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.common.utils.*
import com.tangem.scenarios.*
import com.tangem.screens.*
import com.tangem.tap.domain.sdk.mocks.MockContent
import com.tangem.tap.domain.sdk.mocks.content.TwinsMockContent
@ -288,37 +282,13 @@ class MainScreenActionButtonsTest : BaseTestCase() {
step("Click on 'Receive' button") {
onTokenActionsBottomSheet { receiveButton.performClick() }
}
step("Assert 'Token receive warning' bottom sheet is displayed") {
waitForIdle()
step("Go to QR code bottom sheet") {
flakySafely(WAIT_UNTIL_TIMEOUT) {
onTokenReceiveWarningBottomSheet {
bottomSheet.assertIsDisplayed()
}
goToQrCodeBottomSheet()
}
}
step("Click on 'Got it' button") {
onTokenReceiveWarningBottomSheet { gotItButton.performClick() }
}
step("Click on 'Show QR code' button") {
onReceiveAssetsBottomSheet { showQrCodeButton.clickWithAssertion() }
}
step("Assert bottom sheet with QR code title is displayed") {
onTokenReceiveQrCodeBottomSheet { title.assertIsDisplayed() }
}
step("Assert QR code is displayed") {
onTokenReceiveQrCodeBottomSheet { qrCode.assertIsDisplayed() }
}
step("Assert address title is displayed") {
onTokenReceiveQrCodeBottomSheet { addressTitle.assertIsDisplayed() }
}
step("Assert address is displayed") {
onTokenReceiveQrCodeBottomSheet { address.assertIsDisplayed() }
}
step("Assert 'Copy' button is displayed") {
onTokenReceiveQrCodeBottomSheet { copyButton.assertIsDisplayed() }
}
step("Assert 'Share' button is displayed") {
onTokenReceiveQrCodeBottomSheet { shareButton.assertIsDisplayed() }
step("Check QR code bottom sheet") {
checkQrCodeBottomSheetScenario()
}
}
}
@ -349,10 +319,10 @@ class MainScreenActionButtonsTest : BaseTestCase() {
}
}
}
step("Assert 'Receive' button is displayed") {
step("Assert 'Sell' button is displayed") {
onTokenActionsBottomSheet { sellButton.assertIsDisplayed() }
}
step("Click on 'Receive' button") {
step("Click on 'Sell' button") {
onTokenActionsBottomSheet { sellButton.performClick() }
}
step("Assert Chrome Browser is opened") {

View file

@ -0,0 +1,255 @@
package com.tangem.tests.actionButtons
import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
import com.tangem.common.extensions.SwipeDirection
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.swipeVertical
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.scenarios.checkQrCodeBottomSheetScenario
import com.tangem.scenarios.goToQrCodeBottomSheet
import com.tangem.scenarios.openMainScreen
import com.tangem.scenarios.synchronizeAddresses
import com.tangem.screens.*
import com.tangem.screens.onMainScreen
import com.tangem.screens.onSwapStoriesScreen
import com.tangem.screens.onSwapTokenScreen
import com.tangem.screens.onTokenDetailsScreen
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 TokenDetailsScreenActionButtonsTest : BaseTestCase() {
@AllureId("594")
@DisplayName("Action buttons (token details screen): validate UI")
@Test
fun actionButtonsValidateUiTest() {
val tokenTitle = "Bitcoin"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
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 'Swap' button is displayed") {
onTokenDetailsScreen { swapButton().assertIsDisplayed() }
}
step("Assert 'Sell' button is displayed") {
onTokenDetailsScreen { sellButton().assertIsDisplayed() }
}
}
}
@AllureId("593")
@DisplayName("Action buttons (token details screen): check buttons state")
@Test
fun checkActionButtonsStateTest() {
val tokenTitle = "Bitcoin"
val actionButtonIsNotDimmed = "Action button is not dimmed"
val actionButtonIsDimmed = "Action button is dimmed"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
waitForIdle()
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
}
step("Assert 'Receive' button is not dimmed") {
onTokenDetailsScreen { receiveButton().assertContentDescriptionEquals(actionButtonIsNotDimmed) }
}
step("Assert 'Buy' button is not dimmed") {
onTokenDetailsScreen { buyButton().assertContentDescriptionEquals(actionButtonIsNotDimmed) }
}
step("Assert 'Send' button is dimmed") {
onTokenDetailsScreen { sendButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
step("Assert 'Swap' button is dimmed") {
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
step("Assert 'Sell' button is dimmed") {
onTokenDetailsScreen { sellButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
}
}
@AllureId("4459")
@DisplayName("Action buttons (token details screen): check 'Swap' button (success)")
@Test
fun checkSwapButtonSuccessTest() {
val tokenTitle = "Ethereum"
val tokenSymbol = "ETH"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
waitForIdle()
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton().performClick() }
}
step("Close 'Stories' screen") {
onSwapStoriesScreen { closeButton.clickWithAssertion() }
}
step("Assert 'Swap' screen title is displayed") {
onSwapTokenScreen { title.assertIsDisplayed() }
}
step("Assert token symbol: '$tokenSymbol' is displayed") {
onSwapTokenScreen { tokenSymbol(tokenSymbol).assertIsDisplayed() }
}
}
}
@AllureId("4460")
@DisplayName("Action buttons (token details screen): check 'Swap' button (provider error)")
@Test
fun checkSwapButtonProviderErrorTest() {
val tokenTitle = "POL (ex-MATIC)"
val actionButtonIsDimmed = "Action button is dimmed"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Swipe up") {
swipeVertical(SwipeDirection.UP)
}
step("Click on token with name: '$tokenTitle'") {
waitForIdle()
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
}
step("Assert 'Swap' button is dimmed") {
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton().performClick() }
}
step("Assert swapping $tokenTitle is not supported dialog text is displayed") {
onSwapIsNotSupportedDialog { text(tokenTitle).assertIsDisplayed() }
}
step("Assert 'Ok' button is displayed") {
onSwapIsNotSupportedDialog { okButton.assertIsDisplayed() }
}
step("Click on 'Ok' button") {
onSwapIsNotSupportedDialog { okButton.performClick() }
}
step("Assert 'Swap' button is dimmed") {
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
}
}
@AllureId("4461")
@DisplayName("Action buttons (token details screen): check 'Swap' button (Express error)")
@Test
fun checkSwapButtonExpressErrorTest() {
val tokenTitle = "Polygon"
val actionButtonIsDimmed = "Action button is dimmed"
val scenarioName = "express_api_assets"
val scenarioState = "Error"
setupHooks(
additionalAfterSection = {
resetWireMockScenarioState(scenarioName)
}
).run {
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
setWireMockScenarioState(scenarioName, scenarioState)
}
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Swipe up") {
swipeVertical(SwipeDirection.UP)
}
step("Click on token with name: '$tokenTitle'") {
waitForIdle()
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
}
step("Assert 'Swap' button is dimmed") {
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
step("Click on 'Swap' button") {
onTokenDetailsScreen { swapButton().performClick() }
}
step("Assert operation is unavailable dialog text is displayed") {
onOperationIsUnavailableDialog { text.assertIsDisplayed() }
}
step("Assert 'Ok' button is displayed") {
onOperationIsUnavailableDialog { okButton.assertIsDisplayed() }
}
step("Click on 'Ok' button") {
onOperationIsUnavailableDialog { okButton.performClick() }
}
step("Assert 'Swap' button is dimmed") {
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
}
}
}
@AllureId("3590")
@DisplayName("Action buttons (token details screen): validate UI")
@Test
fun checkReceiveButtonTest() {
val tokenTitle = "Bitcoin"
setupHooks().run {
step("Open 'Main Screen'") {
openMainScreen()
}
step("Synchronize addresses") {
synchronizeAddresses()
}
step("Click on token with name: '$tokenTitle'") {
waitForIdle()
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
}
step("Assert 'Receive' button is displayed") {
onTokenDetailsScreen { receiveButton().performClick() }
}
step("Go to QR code bottom sheet") {
flakySafely(WAIT_UNTIL_TIMEOUT) {
goToQrCodeBottomSheet()
}
}
step("Check QR code bottom sheet") {
checkQrCodeBottomSheetScenario()
}
}
}
}