diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/TangemPayScenarios.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/TangemPayScenarios.kt index 3e9542762c..1bd697787f 100644 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/TangemPayScenarios.kt +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/TangemPayScenarios.kt @@ -23,6 +23,31 @@ fun BaseTestCase.openTangemPay() { } } +/** Opens Tangem Pay and taps the card to reach the card management page. */ +fun BaseTestCase.openTangemPayCardPage() { + openTangemPay() + step("Click on 'Card' button") { + onTangemPayMainScreen { cardButton.clickWithAssertion() } + } + step("Assert card page 'More' button is displayed") { + awaitSuccess { onTangemPayCardPageScreen { moreButton.assertIsDisplayed() } } + } +} + +/** From the card page, opens the 'Replace card' reissue bottom sheet via the 'More' menu. */ +fun BaseTestCase.openReissueSheet() { + step("Click on 'More' button") { + onTangemPayCardPageScreen { moreButton.clickWithAssertion() } + } + step("Click on 'Replace card' menu item") { + awaitSuccess { onTangemPayCardPageScreen { replaceCardMenuItem.assertIsDisplayed() } } + onTangemPayCardPageScreen { replaceCardMenuItem.performClick() } + } + step("Assert reissue bottom sheet is displayed") { + awaitSuccess { onTangemPayReissueSheet { confirmButton.assertIsDisplayed() } } + } +} + // Compose Test gesture — UiAutomator swipe doesn't reach Material3 PullToRefreshBox's NestedScrollConnection. fun BaseTestCase.pullToRefreshTangemPay() { val balance = composeTestRule.onNode(hasTestTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE)) diff --git a/app/src/androidTest/kotlin/com/tangem/screens/TokenReceiveWarningBottomSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/TokenReceiveWarningBottomSheetPageObject.kt index 77173fb0af..5ef11f3286 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/TokenReceiveWarningBottomSheetPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/TokenReceiveWarningBottomSheetPageObject.kt @@ -19,6 +19,11 @@ class TokenReceiveWarningBottomSheetPageObject(semanticsProvider: SemanticsNodeI val gotItButton: KNode = child { hasText(getResourceString(R.string.common_got_it)) } + + fun networkName(name: String): KNode = child { + hasText(text = name, substring = true) + useUnmergedTree = true + } } internal fun BaseTestCase.onTokenReceiveWarningBottomSheet(function: TokenReceiveWarningBottomSheetPageObject.() -> Unit) = diff --git a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayAddFundsSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayAddFundsSheetPageObject.kt index ba66970bb8..2b9955eb31 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayAddFundsSheetPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayAddFundsSheetPageObject.kt @@ -17,7 +17,7 @@ class TangemPayAddFundsSheetPageObject(semanticsProvider: SemanticsNodeInteracti } val receiveOption: KNode = child { - hasText(getResourceString(CoreResR.string.common_receive)) + hasText(getResourceString(CoreResR.string.tangempay_topup_receive_title)) useUnmergedTree = true } diff --git a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayCardPagePageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayCardPagePageObject.kt index 5d43dec5e8..48a207d282 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayCardPagePageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayCardPagePageObject.kt @@ -2,14 +2,39 @@ package com.tangem.screens.tangempay import androidx.compose.ui.test.SemanticsNodeInteractionsProvider import com.tangem.common.BaseTestCase +import com.tangem.core.res.R as CoreResR import com.tangem.core.ui.test.TangemPayTestTags 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 class TangemPayCardPagePageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen(semanticsProvider = semanticsProvider) { + val moreButton: KNode = child { + hasTestTag(TangemPayTestTags.CARD_PAGE_MORE_BUTTON) + useUnmergedTree = true + } + + val replaceCardMenuItem: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_card_details_reissue_card)) + useUnmergedTree = true + } + + val cardNumberShort: KNode = child { + hasTestTag(TangemPayTestTags.CARD_NUMBER_SHORT) + useUnmergedTree = true + } + + val reissueInProgressBlock: KNode = child { + hasText( + text = getResourceString(CoreResR.string.tangempay_reissue_card_in_progress), + substring = true, + ) + useUnmergedTree = true + } + val changePinRow: KNode = child { hasTestTag(TangemPayTestTags.CHANGE_PIN_ROW) useUnmergedTree = true diff --git a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayMainPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayMainPageObject.kt index aad99a3d9e..951b01eb5c 100644 --- a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayMainPageObject.kt +++ b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayMainPageObject.kt @@ -61,6 +61,14 @@ class TangemPayMainPageObject(semanticsProvider: SemanticsNodeInteractionsProvid hasText(text) useUnmergedTree = true } + + val reissueInProgressBanner: KNode = child { + hasText( + text = getResourceString(CoreResR.string.tangempay_reissue_card_in_progress), + substring = true, + ) + useUnmergedTree = true + } } internal fun BaseTestCase.onTangemPayMainScreen(function: TangemPayMainPageObject.() -> Unit) = diff --git a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayReissueSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayReissueSheetPageObject.kt new file mode 100644 index 0000000000..2354a89618 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayReissueSheetPageObject.kt @@ -0,0 +1,62 @@ +package com.tangem.screens.tangempay + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.common.BaseTestCase +import com.tangem.core.res.R as CoreResR +import com.tangem.core.ui.test.TangemPayTestTags +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 + +class TangemPayReissueSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen(semanticsProvider = semanticsProvider) { + + val title: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_reissue_card_title)) + useUnmergedTree = true + } + + val description: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_reissue_card_description)) + useUnmergedTree = true + } + + val feeLabel: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_reissue_card_fee_label)) + useUnmergedTree = true + } + + val feeValue: KNode = child { + hasTestTag(TangemPayTestTags.REISSUE_SHEET_FEE_VALUE) + useUnmergedTree = true + } + + val confirmButton: KNode = child { + hasTestTag(TangemPayTestTags.REISSUE_SHEET_CONFIRM_BUTTON) + useUnmergedTree = true + } + + val feeErrorTitle: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_reissue_card_fee_unreachable_error_title)) + useUnmergedTree = true + } + + val refreshButton: KNode = child { + hasText(getResourceString(CoreResR.string.warning_button_refresh)) + useUnmergedTree = true + } + + val insufficientFundsTitle: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_reissue_card_insufficient_funds_title)) + useUnmergedTree = true + } + + val addFundsButton: KNode = child { + hasText(getResourceString(CoreResR.string.tangempay_card_details_add_funds)) + useUnmergedTree = true + } +} + +internal fun BaseTestCase.onTangemPayReissueSheet(function: TangemPayReissueSheetPageObject.() -> Unit) = + onComposeScreen(composeTestRule, function) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayTransactionDetailsSheetPageObject.kt b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayTransactionDetailsSheetPageObject.kt new file mode 100644 index 0000000000..e19a687a99 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/tangempay/TangemPayTransactionDetailsSheetPageObject.kt @@ -0,0 +1,33 @@ +package com.tangem.screens.tangempay + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.common.BaseTestCase +import com.tangem.core.res.R as CoreResR +import com.tangem.core.ui.test.TangemPayTestTags +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 + +class TangemPayTransactionDetailsSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen(semanticsProvider = semanticsProvider) { + + val feeTitle: KNode = child { + hasText(getResourceString(CoreResR.string.tangem_pay_fee_title)) + useUnmergedTree = true + } + + val serviceFeesCategory: KNode = child { + hasText(getResourceString(CoreResR.string.tangem_pay_fee_subtitle)) + useUnmergedTree = true + } + + val amount: KNode = child { + hasTestTag(TangemPayTestTags.TRANSACTION_DETAILS_AMOUNT) + useUnmergedTree = true + } +} + +internal fun BaseTestCase.onTangemPayTransactionDetailsSheet( + function: TangemPayTransactionDetailsSheetPageObject.() -> Unit, +) = onComposeScreen(composeTestRule, function) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/tangempay/TangemPayReissueTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/tangempay/TangemPayReissueTest.kt new file mode 100644 index 0000000000..160363678a --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/tests/tangempay/TangemPayReissueTest.kt @@ -0,0 +1,299 @@ +package com.tangem.tests.tangempay + +import com.tangem.common.BaseTestCase +import com.tangem.common.constants.TestConstants.TANGEM_PAY_ELIGIBILITY_SCENARIO +import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT +import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_VERY_LONG +import com.tangem.common.extensions.assertTextContainsSafe +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.common.extensions.extractText +import com.tangem.common.utils.resetWireMockScenarioState +import com.tangem.common.utils.resetWireMockScenarios +import com.tangem.common.utils.setWireMockScenarioState +import com.tangem.scenarios.* +import com.tangem.screens.onTokenReceiveWarningBottomSheet +import com.tangem.screens.tangempay.* +import dagger.hilt.android.testing.HiltAndroidTest +import io.qameta.allure.kotlin.AllureId +import io.qameta.allure.kotlin.junit4.DisplayName +import org.junit.Assert +import org.junit.Test + +@HiltAndroidTest +class TangemPayReissueTest : BaseTestCase() { + + private val eligibilityState = "PaeraCustomer" + private val balanceScenario = "tangem_pay_balance_update" + private val balanceInitialState = "InitialBalance" + private val cardReissueScenario = "tangem_pay_card_reissue" + private val cardReissueStartedState = "Started" + private val cardReissueFeeErrorState = "FeeError" + private val reissueOrderScenario = "tangem_pay_reissue_order" + private val reissueOrderStartedState = "Started" + private val reissueOrderCompletedState = "Completed" + private val reissueScenario = "tangem_pay_reissue" + private val reissueCompletedState = "Completed" + private val historyScenario = "tangem_pay_transaction_history" + private val historyInitialEmptyState = "InitialEmpty" + private val historyAfterReissueFeeState = "AfterReissueFee" + + @AllureId("9749") + @DisplayName("Tangem Pay: card reissue bottom sheet displays replace card details") + @Test + fun reissueBottomSheetDisplaysReplaceCardDetailsTest() { + setupHooks( + additionalBeforeSection = { + resetWireMockScenarios() + setWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO, eligibilityState) + setWireMockScenarioState(balanceScenario, balanceInitialState) + setWireMockScenarioState(cardReissueScenario, cardReissueStartedState) + }, + additionalAfterSection = { + resetWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO) + resetWireMockScenarioState(balanceScenario) + resetWireMockScenarioState(cardReissueScenario) + }, + ).run { + step("Open Tangem Pay card page") { openTangemPayCardPage() } + step("Open the 'Replace card' reissue bottom sheet") { openReissueSheet() } + step("Assert reissue sheet title, description and fee label are displayed") { + onTangemPayReissueSheet { + title.assertIsDisplayed() + description.assertIsDisplayed() + feeLabel.assertIsDisplayed() + } + } + step("Assert replacement fee value is displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { feeValue.assertTextContainsSafe("1.00", substring = true) } + } + } + } + } + + @AllureId("9833") + @DisplayName("Tangem Pay: error is shown when reissue cost is not fetched") + @Test + fun reissueFeeErrorShowsErrorWhenFeeRequestFailsTest() { + setupHooks( + additionalBeforeSection = { + resetWireMockScenarios() + setWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO, eligibilityState) + setWireMockScenarioState(cardReissueScenario, cardReissueFeeErrorState) + }, + additionalAfterSection = { + resetWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO) + resetWireMockScenarioState(cardReissueScenario) + }, + ).run { + step("Open Tangem Pay card page") { openTangemPayCardPage() } + step("Open the 'Replace card' reissue bottom sheet") { openReissueSheet() } + step("Assert fee unreachable error and 'Refresh' button are displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { + feeErrorTitle.assertIsDisplayed() + refreshButton.assertIsDisplayed() + } + } + } + } + } + + @AllureId("9752") + @DisplayName("Tangem Pay: reissue fee transaction appears in history and details") + @Test + fun reissueFeeTransactionAppearsInHistoryAndDetailsTest() { + val feeMerchantName = "Card replacement fee" + + setupHooks( + additionalBeforeSection = { + resetWireMockScenarios() + setWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO, eligibilityState) + setWireMockScenarioState(balanceScenario, balanceInitialState) + setWireMockScenarioState(cardReissueScenario, cardReissueStartedState) + setWireMockScenarioState(reissueOrderScenario, reissueOrderStartedState) + setWireMockScenarioState(historyScenario, historyInitialEmptyState) + }, + additionalAfterSection = { + resetWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO) + resetWireMockScenarioState(balanceScenario) + resetWireMockScenarioState(cardReissueScenario) + resetWireMockScenarioState(reissueOrderScenario) + resetWireMockScenarioState(historyScenario) + }, + ).run { + step("Open Tangem Pay card page") { openTangemPayCardPage() } + step("Open the 'Replace card' reissue bottom sheet") { openReissueSheet() } + step("Wait for replacement fee to load") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { feeValue.assertTextContainsSafe("1.00", substring = true) } + } + } + step("Click on 'Replace card' confirm button") { + onTangemPayReissueSheet { confirmButton.clickWithAssertion() } + } + step("Assert reissue started and the sheet is dismissed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayCardPageScreen { reissueInProgressBlock.assertIsDisplayed() } + } + } + step("Return to the payment account screen") { + device.uiDevice.pressBack() + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayMainScreen { balance.assertIsDisplayed() } + } + } + step("Switch WireMock scenario '$historyScenario' to '$historyAfterReissueFeeState'") { + setWireMockScenarioState(historyScenario, historyAfterReissueFeeState) + } + step("Pull to refresh Tangem Pay") { pullToRefreshTangemPay() } + step("Assert '$feeMerchantName' transaction is displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayMainScreen { transactionRowWithText(feeMerchantName).assertIsDisplayed() } + } + } + step("Click on '$feeMerchantName' transaction row") { + onTangemPayMainScreen { transactionRowWithText(feeMerchantName).performClick() } + } + step("Assert fee transaction details are displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayTransactionDetailsSheet { + feeTitle.assertIsDisplayed() + serviceFeesCategory.assertIsDisplayed() + amount.assertTextContainsSafe("1.00", substring = true) + } + } + } + } + } + + @AllureId("9743") + @DisplayName("Tangem Pay: card reissue end-to-end replaces card with new details") + @Test + fun reissueEndToEndReplacesCardWithNewDetailsTest() { + val reissuedCardLastDigits = "5353" + val balanceAfterWithdrawState = "AfterWithdraw" + + // AfterWithdraw funds the fee check without a customer/me stub, so reissued customer/me wins. + setupHooks( + additionalBeforeSection = { + resetWireMockScenarios() + setWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO, eligibilityState) + setWireMockScenarioState(balanceScenario, balanceAfterWithdrawState) + setWireMockScenarioState(cardReissueScenario, cardReissueStartedState) + setWireMockScenarioState(reissueOrderScenario, reissueOrderStartedState) + }, + additionalAfterSection = { + resetWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO) + resetWireMockScenarioState(balanceScenario) + resetWireMockScenarioState(cardReissueScenario) + resetWireMockScenarioState(reissueOrderScenario) + resetWireMockScenarioState(reissueScenario) + }, + ).run { + var oldCardNumber = "" + step("Open Tangem Pay card page") { openTangemPayCardPage() } + step("Read the current card number") { + onTangemPayCardPageScreen { cardNumberShort.assertIsDisplayed() } + onTangemPayCardPageScreen { oldCardNumber = cardNumberShort.extractText() } + } + step("Open the 'Replace card' reissue bottom sheet") { openReissueSheet() } + step("Wait for replacement fee to load") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { feeValue.assertTextContainsSafe("1.00", substring = true) } + } + } + step("Click on 'Replace card' confirm button") { + onTangemPayReissueSheet { confirmButton.clickWithAssertion() } + } + step("Assert reissue started (sheet dismissed, card is replacing)") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { confirmButton.assertDoesNotExist() } + onTangemPayCardPageScreen { reissueInProgressBlock.assertIsDisplayed() } + } + } + step("Switch WireMock scenario '$reissueOrderScenario' to '$reissueOrderCompletedState'") { + setWireMockScenarioState(reissueOrderScenario, reissueOrderCompletedState) + } + step("Switch WireMock scenario '$reissueScenario' to '$reissueCompletedState'") { + setWireMockScenarioState(reissueScenario, reissueCompletedState) + } + step("Return to the payment account screen") { + device.uiDevice.pressBack() + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayMainScreen { balance.assertIsDisplayed() } + } + } + step("Refresh until the card leaves the replacing state") { + pullToRefreshTangemPay() + flakySafely(WAIT_UNTIL_TIMEOUT_VERY_LONG) { + onTangemPayMainScreen { reissueInProgressBanner.assertDoesNotExist() } + } + } + step("Reopen the reissued card") { + onTangemPayMainScreen { cardButton.clickWithAssertion() } + } + var newCardNumber = "" + step("Read the new card number") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayCardPageScreen { + cardNumberShort.assertTextContainsSafe(reissuedCardLastDigits, substring = true) + } + } + onTangemPayCardPageScreen { newCardNumber = cardNumberShort.extractText() } + } + step("Assert the card number changed after reissue") { + Assert.assertNotEquals(oldCardNumber, newCardNumber) + } + } + } + + @AllureId("9746") + @DisplayName("Tangem Pay: top up via card reissue when unable to cover fee") + @Test + fun reissueTopUpUnableToCoverFeeAddFundsReceiveTest() { + val depositNetworkName = "Polygon" + + setupHooks( + additionalBeforeSection = { + resetWireMockScenarios() + setWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO, eligibilityState) + setWireMockScenarioState(cardReissueScenario, cardReissueStartedState) + }, + additionalAfterSection = { + resetWireMockScenarioState(TANGEM_PAY_ELIGIBILITY_SCENARIO) + resetWireMockScenarioState(cardReissueScenario) + }, + ).run { + step("Open Tangem Pay card page") { openTangemPayCardPage() } + step("Open the 'Replace card' reissue bottom sheet") { openReissueSheet() } + step("Assert 'Unable to cover fee' state is displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayReissueSheet { insufficientFundsTitle.assertIsDisplayed() } + } + } + step("Click on 'Add funds' button") { + onTangemPayReissueSheet { addFundsButton.clickWithAssertion() } + } + step("Assert 'Add funds' sheet shows Swap and Receive options") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTangemPayAddFundsSheet { + swapOption.assertIsDisplayed() + receiveOption.assertIsDisplayed() + } + } + } + step("Click on 'Receive' option") { + onTangemPayAddFundsSheet { receiveOption.clickWithAssertion() } + } + step("Assert deposit info for the '$depositNetworkName' network is displayed") { + flakySafely(WAIT_UNTIL_TIMEOUT) { + onTokenReceiveWarningBottomSheet { + bottomSheet.assertIsDisplayed() + networkName(depositNetworkName).assertIsDisplayed() + } + } + } + } + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/test/TangemPayTestTags.kt b/core/ui/src/main/java/com/tangem/core/ui/test/TangemPayTestTags.kt index 234e5f8236..bcd265fbb1 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/test/TangemPayTestTags.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/test/TangemPayTestTags.kt @@ -24,6 +24,19 @@ object TangemPayTestTags { const val FREEZE_CARD_ROW = "TANGEM_PAY_FREEZE_CARD_ROW" const val CARD_FROZEN_BADGE = "TANGEM_PAY_CARD_FROZEN_BADGE" + // Card page top bar more-actions menu (redesign) + const val CARD_PAGE_MORE_BUTTON = "TANGEM_PAY_CARD_PAGE_MORE_BUTTON" + + // Masked card number shown on the card face (e.g. "*4242") + const val CARD_NUMBER_SHORT = "TANGEM_PAY_CARD_NUMBER_SHORT" + + // Replace card (reissue) bottom sheet + const val REISSUE_SHEET_CONFIRM_BUTTON = "TANGEM_PAY_REISSUE_SHEET_CONFIRM_BUTTON" + const val REISSUE_SHEET_FEE_VALUE = "TANGEM_PAY_REISSUE_SHEET_FEE_VALUE" + + // Transaction details bottom sheet + const val TRANSACTION_DETAILS_AMOUNT = "TANGEM_PAY_TRANSACTION_DETAILS_AMOUNT" + // Freeze confirmation bottom sheet const val FREEZE_CONFIRMATION_SUBMIT_BUTTON = "TANGEM_PAY_FREEZE_CONFIRMATION_SUBMIT_BUTTON" diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt index 6b333d950a..e7ba2a0cd0 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardDetailsBlock.kt @@ -448,7 +448,8 @@ private fun ConstraintLayoutScope.CardNumberBlock( start.linkTo(parent.start) bottom.linkTo(parent.bottom) } - .padding(bottom = 8.dp), + .padding(bottom = 8.dp) + .testTag(TangemPayTestTags.CARD_NUMBER_SHORT), ) } else { Text( diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt index d8899867a7..9ea6c1f59e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayCardPageScreen.kt @@ -34,6 +34,7 @@ import com.tangem.core.ui.ds.topbar.TangemTopBar import com.tangem.core.ui.ds2.button.TangemButton import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.* +import com.tangem.core.ui.test.TangemPayTestTags import com.tangem.domain.models.pay.TangemPayCardFrozenState import com.tangem.domain.models.pay.TangemPayCardState import com.tangem.features.tangempay.details.impl.R @@ -355,6 +356,7 @@ private fun CardPageTopBar( endContent = { Box { TangemButton( + modifier = Modifier.testTag(TangemPayTestTags.CARD_PAGE_MORE_BUTTON), iconStart = TangemIconUM.Icon(iconRes = CoreUiR.drawable.ic_more_default_24), onClick = { isDropdownMenuShown = true }, size = TangemButton.Size.X11, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayReissueCardContentV2.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayReissueCardContentV2.kt index e2889fc5ff..eae125f2ac 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayReissueCardContentV2.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayReissueCardContentV2.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -39,6 +40,7 @@ import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.core.ui.res.generated.icons.Icons import com.tangem.core.ui.res.generated.icons.ic_arrow_refresh_32 import com.tangem.core.ui.res.generated.icons.ic_error_28 +import com.tangem.core.ui.test.TangemPayTestTags import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.TangemPayReissueCardError import com.tangem.features.tangempay.entity.TangemPayReissueCardUM @@ -155,6 +157,7 @@ private fun FeeBlock( titleRes = R.string.tangempay_reissue_card_fee_label, value = state.feeAmount, showDivider = appearance.shouldShowBalanceRow, + valueTestTag = TangemPayTestTags.REISSUE_SHEET_FEE_VALUE, ) if (appearance.shouldShowBalanceRow) { FeeInfoRow( @@ -166,7 +169,7 @@ private fun FeeBlock( } @Composable -private fun FeeInfoRow(titleRes: Int, value: String, showDivider: Boolean = false) { +private fun FeeInfoRow(titleRes: Int, value: String, showDivider: Boolean = false, valueTestTag: String? = null) { TangemRow( divider = showDivider, contentLead = TangemRowContentLead.Start, @@ -185,6 +188,7 @@ private fun FeeInfoRow(titleRes: Int, value: String, showDivider: Boolean = fals ) } else { TangemRowText( + modifier = if (valueTestTag != null) Modifier.testTag(valueTestTag) else Modifier, text = value, role = TangemRowTextRole.Value, ) @@ -213,7 +217,9 @@ private fun BottomButtonsBlock( text = resourceReference(R.string.common_cancel), ) TangemButton( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .testTag(TangemPayTestTags.REISSUE_SHEET_CONFIRM_BUTTON), size = TangemButton.Size.X12, onClick = appearance.primaryAction(state), isEnabled = !state.isFeeLoading && !state.isReissuingInProgress, diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUiV2.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUiV2.kt index 66fed29d1b..47021f2001 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUiV2.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangempayTxDetailsUiV2.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Devices @@ -40,6 +41,7 @@ import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.core.ui.res.generated.icons.Icons import com.tangem.core.ui.res.generated.icons.ic_arrow_down_24 import com.tangem.core.ui.res.generated.icons.ic_arrow_refresh_20 +import com.tangem.core.ui.test.TangemPayTestTags import com.tangem.features.tangempay.details.impl.R import com.tangem.features.tangempay.entity.* @@ -83,7 +85,9 @@ internal fun TangemPayTxHistoryDetailsContentV2(state: TangemPayTxHistoryDetails modifier = Modifier.padding(top = TangemTheme.dimens2.x12), ) Text( - modifier = Modifier.padding(top = TangemTheme.dimens2.x6), + modifier = Modifier + .padding(top = TangemTheme.dimens2.x6) + .testTag(TangemPayTestTags.TRANSACTION_DETAILS_AMOUNT), text = state.transactionAmount.orMaskWithStars(state.isBalanceHidden), style = TangemTheme.typography3.display.medium, color = TangemTheme.colors3.text.primary,