From 8676fe11e2d77e98681f33e91d4ece95850248b9 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 18:49:55 +0100 Subject: [PATCH 01/89] Add PaymentController test: `given collect payment shown, when RETRY message received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt new file mode 100644 index 00000000000..00d6cdc0293 --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -0,0 +1,170 @@ +package com.woocommerce.android.ui.payments.cardreader.payment.controller + +import com.woocommerce.android.AppPrefs +import com.woocommerce.android.R +import com.woocommerce.android.cardreader.CardReaderManager +import com.woocommerce.android.cardreader.connection.CardReaderStatus +import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages +import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment +import com.woocommerce.android.model.Address +import com.woocommerce.android.model.Order +import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.orders.details.OrderDetailRepository +import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType +import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundErrorMapper +import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundableChecker +import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker +import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper +import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState +import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper +import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare +import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper +import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker +import com.woocommerce.android.util.CurrencyFormatter +import com.woocommerce.android.viewmodel.BaseUnitTest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.WooCommerceStore +import java.math.BigDecimal +import kotlin.reflect.KMutableProperty0 + +@OptIn(ExperimentalCoroutinesApi::class) +class CardReaderPaymentControllerTest : BaseUnitTest() { + private lateinit var controller: CardReaderPaymentController + + private val cardReaderManager: CardReaderManager = mock() + private val orderRepository: OrderDetailRepository = mock() + private val selectedSite: SelectedSite = mock() + private val paymentCollectibilityChecker: CardReaderPaymentCollectibilityChecker = mock() + private val tracker: PaymentsFlowTracker = mock() + private val trackCanceledFlow = CardReaderTrackCanceledFlow(tracker) + private val appPrefs: AppPrefs = mock() + private val currencyFormatter: CurrencyFormatter = mock() + private val wooStore: WooCommerceStore = mock() + private val errorMapper: CardReaderPaymentErrorMapper = mock() + private val cardReaderTrackingInfoKeeper: CardReaderTrackingInfoKeeper = mock() + private val interacRefundErrorMapper: CardReaderInteracRefundErrorMapper = mock() + private val interacRefundableChecker: CardReaderInteracRefundableChecker = mock() + private val paymentStateProvider = CardReaderPaymentStateProvider() + private val cardReaderPaymentOrderHelper: CardReaderPaymentOrderHelper = mock() + private val paymentReceiptHelper: PaymentReceiptHelper = mock() + private val cardReaderOnboardingChecker: CardReaderOnboardingChecker = mock() + private val cardReaderConfigProvider: CardReaderCountryConfigProvider = mock() + private val paymentReceiptShare: PaymentReceiptShare = mock() + + private var isTTPinProgress = false + private val isTTPinProgressProp: KMutableProperty0 = ::isTTPinProgress + + private val paymentParam = CardReaderFlowParam.PaymentOrRefund.Payment(ORDER_ID, ORDER) + + private val mockedOrder = mock() + private val mockedAddress = mock
() + + @OptIn(InternalCoroutinesApi::class) + @Before + fun setUp() = testBlocking { + createController() + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connected(mock()))) + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) + + whenever(mockedOrder.total).thenReturn(DUMMY_TOTAL) + whenever(mockedOrder.currency).thenReturn("GBP") + whenever(mockedOrder.billingAddress).thenReturn(mockedAddress) + whenever(mockedAddress.email).thenReturn("") + whenever(mockedAddress.firstName).thenReturn("Tester") + whenever(mockedAddress.lastName).thenReturn("Test") + whenever(mockedOrder.orderKey).thenReturn("wc_order_j0LMK3bFhalEL") + whenever(mockedOrder.id).thenReturn(ORDER_ID) + + whenever(paymentCollectibilityChecker.isCollectable(any())).thenReturn(true) + whenever(selectedSite.get()).thenReturn(siteModel) + whenever(wooStore.getStoreCountryCode(any())).thenReturn("US") + whenever(appPrefs.getCardReaderStatementDescriptor(anyOrNull(), anyOrNull(), anyOrNull())) + .thenReturn("test statement descriptor") + whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) + + whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) + whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn("test description") + whenever(cardReaderPaymentOrderHelper.getAmountLabel(mockedOrder)) + .thenReturn("${DUMMY_CURRENCY_SYMBOL}${DUMMY_TOTAL}") + whenever(cardReaderManager.batteryStatus).thenAnswer { flow { emit(CardReaderBatteryStatus.Unknown) } } + } + + @OptIn(ExperimentalCoroutinesApi::class) + private suspend fun createController() { + controller = CardReaderPaymentController( + scope = TestScope(coroutinesTestRule.testDispatcher), + cardReaderManager = cardReaderManager, + orderRepository = orderRepository, + selectedSite = selectedSite, + appPrefs = appPrefs, + paymentCollectibilityChecker = paymentCollectibilityChecker, + interacRefundableChecker = interacRefundableChecker, + tracker = tracker, + trackCancelledFlow = trackCanceledFlow, + currencyFormatter = currencyFormatter, + errorMapper = errorMapper, + interacRefundErrorMapper = interacRefundErrorMapper, + wooStore = wooStore, + dispatchers = coroutinesTestRule.testDispatchers, + cardReaderTrackingInfoKeeper = cardReaderTrackingInfoKeeper, + paymentStateProvider = paymentStateProvider, + cardReaderPaymentOrderHelper = cardReaderPaymentOrderHelper, + paymentReceiptHelper = paymentReceiptHelper, + cardReaderOnboardingChecker = cardReaderOnboardingChecker, + cardReaderConfigProvider = cardReaderConfigProvider, + paymentReceiptShare = paymentReceiptShare, + paymentOrRefund = paymentParam, + cardReaderType = CardReaderType.EXTERNAL, + isTTPPaymentInProgress = isTTPinProgressProp, + ) + } + + @Test + fun `given collect payment shown, when RETRY message received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it's run after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(AdditionalInfoType.RETRY_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_retry_card_prompt) + } + + companion object { + private const val ORDER_ID = 1L + private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } + private val DUMMY_TOTAL = BigDecimal(10.72) + private const val DUMMY_CURRENCY_SYMBOL = "£" + } +} From 662b0f25fba7c38b10c6191729c5a92e25833a47 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 18:56:01 +0100 Subject: [PATCH 02/89] Add PaymentController test: `given collect payment shown, when INSERT_CARD received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 00d6cdc0293..c2e3fad8585 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -22,6 +23,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -111,7 +113,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } @OptIn(ExperimentalCoroutinesApi::class) - private suspend fun createController() { + private fun createController() { controller = CardReaderPaymentController( scope = TestScope(coroutinesTestRule.testDispatcher), cardReaderManager = cardReaderManager, @@ -161,6 +163,25 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_retry_card_prompt) } + @Test + fun `given collect payment shown, when INSERT_CARD received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_collect_payment_hint) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From d5c80960a86c1748e6cc43be0d577a1567bbd1fb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:00:42 +0100 Subject: [PATCH 03/89] Add PaymentController test: `given collect payment shown, when SWIPE_CARD received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index c2e3fad8585..98ec3c00299 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -8,6 +8,8 @@ import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMe import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -182,6 +184,44 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_collect_payment_hint) } + @Test + fun `given collect payment shown, when INSERT_OR_SWIPE_CARD received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_OR_SWIPE_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_collect_payment_hint) + } + + @Test + fun `given collect payment shown, when SWIPE_CARD received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(SWIPE_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_collect_payment_hint) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From e78c02eeb134204a59608bb1e53fb49fd0ea36ba Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:18:56 +0100 Subject: [PATCH 04/89] Add PaymentController test: `given collect payment shown, when REMOVE_CARD received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 98ec3c00299..8f38bfa62ff 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -9,6 +9,7 @@ import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStat import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address @@ -222,6 +223,27 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_collect_payment_hint) } + @Test + fun `given collect payment shown, when REMOVE_CARD received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it's run after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(REMOVE_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_remove_card_prompt) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 9086eba6dcb5081069bb148c49f6e78718e4f390 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:20:00 +0100 Subject: [PATCH 05/89] Add PaymentController test: `given collect payment shown, when TRY_OTHER_CARD message received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 8f38bfa62ff..6894b2e1bac 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -11,6 +11,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -244,6 +245,27 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_remove_card_prompt) } + @Test + fun `given collect payment shown, when TRY_OTHER_CARD message received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it's run after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_CARD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_try_another_card_prompt) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 4a52038fb669327b2986644b276562ffbe6e39fe Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:23:11 +0100 Subject: [PATCH 06/89] Add PaymentController test: `given collect payment shown, when CARD_REMOVED_TOO_EARLY message received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 6894b2e1bac..856518023ce 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CARD_REMOVED_TOO_EARLY import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD @@ -266,6 +267,27 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_try_another_card_prompt) } + @Test + fun `given collect payment shown, when CARD_REMOVED_TOO_EARLY message received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it runs after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(CARD_REMOVED_TOO_EARLY)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_card_removed_too_early) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 96d03b9f9bbd5368cbb9f0a239ae4b225f24319a Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:24:07 +0100 Subject: [PATCH 07/89] Add PaymentController test: `given collect payment shown, when TRY_OTHER_READ message received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 856518023ce..5e67c1ae4c6 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -13,6 +13,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -288,6 +289,27 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_card_removed_too_early) } + @Test + fun `given collect payment shown, when TRY_OTHER_READ message received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it's run after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_READ_METHOD)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_try_another_read_method_prompt) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 647f459589b675c0ca81a09fff6ce690bbe273c0 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:25:40 +0100 Subject: [PATCH 08/89] Add PaymentController test: `given collect payment shown, when MULTIPLE_CARDS_DETECTED received, then collect payment hint updated` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 5e67c1ae4c6..298f78aedac 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -10,6 +10,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CARD_REMOVED_TOO_EARLY import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.MULTIPLE_CONTACTLESS_CARDS_DETECTED import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD @@ -310,6 +311,27 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_try_another_read_method_prompt) } + @Test + fun `given collect payment shown, when MULTIPLE_CARDS_DETECTED received, then collect payment hint updated`() = + testBlocking { + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + delay(1) // make sure it's run after collecting payment starts + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(MULTIPLE_CONTACTLESS_CARDS_DETECTED)) + } + } + + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + advanceUntilIdle() + + assertThat((controller.paymentState.value as CardReaderPaymentState.CollectingPayment).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_multiple_contactless_cards_detected_prompt) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 4aa8c79f7656368ef4fb202898278e3676615afe Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:28:02 +0100 Subject: [PATCH 09/89] Add PaymentController test: `given fetching order fails, when payment screen shown, then ExternalReaderFailedPayment state is shown` --- .../controller/CardReaderPaymentControllerTest.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 298f78aedac..8e94ae37f11 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -21,6 +21,7 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -31,6 +32,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentC import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -332,6 +334,17 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_multiple_contactless_cards_detected_prompt) } + @Test + fun `given fetching order fails, when payment screen shown, then ExternalReaderFailedPayment state is shown`() = + testBlocking { + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 063f8519eace7cb9e406f0fd04362e954585557f Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:37:38 +0100 Subject: [PATCH 10/89] Add PaymentController test: `given fetching order fails and tpp, when payment screen shown, then BuiltInReaderFailedPayment state is shown` --- .../CardReaderPaymentControllerTest.kt | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 8e94ae37f11..ffe3ec34dd7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -21,18 +21,16 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.BUILT_IN import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundableChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -122,7 +120,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } @OptIn(ExperimentalCoroutinesApi::class) - private fun createController() { + private fun createController(cardReaderType: CardReaderType = CardReaderType.EXTERNAL) { controller = CardReaderPaymentController( scope = TestScope(coroutinesTestRule.testDispatcher), cardReaderManager = cardReaderManager, @@ -146,7 +144,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { cardReaderConfigProvider = cardReaderConfigProvider, paymentReceiptShare = paymentReceiptShare, paymentOrRefund = paymentParam, - cardReaderType = CardReaderType.EXTERNAL, + cardReaderType = cardReaderType, isTTPPaymentInProgress = isTTPinProgressProp, ) } @@ -345,6 +343,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) } + @Test + fun `given fetching order fails and tpp, when payment screen shown, then BuiltInReaderFailedPayment state is shown`() = + testBlocking { + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + + createController(cardReaderType = BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 178902e0bf58d5dc401ba5064bac59dfa8dcaddc Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:38:25 +0100 Subject: [PATCH 11/89] Add PaymentController test: `when fetching order fails, then event tracked` --- .../controller/CardReaderPaymentControllerTest.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ffe3ec34dd7..32f847b0585 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -21,6 +21,7 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -51,6 +52,7 @@ import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore @@ -356,6 +358,16 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment::class.java) } + @Test + fun `when fetching order fails, then event tracked`() = + testBlocking { + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + + controller.start() + + verify(tracker).trackPaymentFailed(anyOrNull(), anyOrNull()) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From d919366879ef0323b8fb90b090d10da1d90cabb0 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:42:26 +0100 Subject: [PATCH 12/89] Move test from VM to PaymentController : `given fetching order succeeds, when payment screen shown, then order currency stored ` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 8 -------- .../controller/CardReaderPaymentControllerTest.kt | 10 ++++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index e0b223c531a..ab1d5d2f24f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -507,14 +507,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(UiStringRes(R.string.order_error_fetch_generic)) } - @Test - fun `given fetching order succeeds, when payment screen shown, then order currency stored `() = - testBlocking { - viewModel.start() - - verify(cardReaderTrackingInfoKeeper).setCurrency(("GBP")) - } - @Test fun `when payment screen shown, then loading data state is shown`() { viewModel.start() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 32f847b0585..5e62e4ed167 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -18,6 +18,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order +import com.woocommerce.android.model.UiString.UiStringRes import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider @@ -32,6 +33,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -368,6 +370,14 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPaymentFailed(anyOrNull(), anyOrNull()) } + @Test + fun `given fetching order succeeds, when payment screen shown, then order currency stored `() = + testBlocking { + controller.start() + + verify(cardReaderTrackingInfoKeeper).setCurrency(("GBP")) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 6ad2c558b57245d248bc5d2957c61a06efe5882a Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:44:53 +0100 Subject: [PATCH 13/89] Add test PaymentController: `when payment screen shown, then loading data state is emitted` --- .../payment/controller/CardReaderPaymentControllerTest.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 5e62e4ed167..5feda8d3fa5 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -34,6 +34,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentC import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -378,6 +379,13 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderTrackingInfoKeeper).setCurrency(("GBP")) } + @Test + fun `when payment screen shown, then loading data state is emitted`() { + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.LoadingData::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 7cfd2758517629f8654047bf0d3b52b0db67913c Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:51:18 +0100 Subject: [PATCH 14/89] Add test PaymentController: `when payment not collectable, then error event emitted and flow terminated` --- .../CardReaderPaymentControllerTest.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 5feda8d3fa5..f80a51c6845 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -35,6 +35,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentE import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare @@ -42,11 +43,15 @@ import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.viewmodel.BaseUnitTest +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat @@ -386,6 +391,28 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.LoadingData::class.java) } + @Test + fun `when payment not collectable, then error event emitted and flow terminated`() = + testBlocking { + whenever(paymentCollectibilityChecker.isCollectable(any())).thenReturn(false) + val events = mutableListOf() + val job = launch { + controller.event.collect { + events.add(it) + } + } + + controller.start() + + assertThat( + (events[0] as ShowErrorMessage).message + ).isEqualTo( + R.string.card_reader_payment_order_paid_payment_cancelled + ) + assertThat(events[1]).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + job.cancel() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From f623f5a630ac536f821fa66fab7779e41f425cdb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:53:13 +0100 Subject: [PATCH 15/89] Move test from VM PaymentController: `when flow started, then correct payment description is propagated to CardReaderManager` --- .../CardReaderPaymentViewModelTest.kt | 22 ----------------- .../CardReaderPaymentControllerTest.kt | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index ab1d5d2f24f..0f0c4e04d47 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -533,28 +533,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(events[1]).isInstanceOf(Exit::class.java) } - @Test - fun `when flow started, then correct payment description is propagated to CardReaderManager`() = - testBlocking { - val siteName = "testName" - val siteId = 12345L - val expectedResult = "hooray" - whenever(selectedSite.get()).thenReturn( - SiteModel().apply { - name = siteName - url = "" - this.siteId = siteId - } - ) - whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn(expectedResult) - val captor = argumentCaptor() - - viewModel.start() - - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.paymentDescription).isEqualTo(expectedResult) - } - @Test fun `when flow started, then correct statement descriptor is propagated to CardReaderManager`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index f80a51c6845..3d08821d22c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -16,6 +16,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment +import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order import com.woocommerce.android.model.UiString.UiStringRes @@ -59,6 +60,7 @@ import org.junit.Before import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -413,6 +415,28 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { job.cancel() } + @Test + fun `when flow started, then correct payment description is propagated to CardReaderManager`() = + testBlocking { + val siteName = "testName" + val siteId = 12345L + val expectedResult = "hooray" + whenever(selectedSite.get()).thenReturn( + SiteModel().apply { + name = siteName + url = "" + this.siteId = siteId + } + ) + whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn(expectedResult) + val captor = argumentCaptor() + + controller.start() + + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.paymentDescription).isEqualTo(expectedResult) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 9e3791f093e0b6ce85348f0ea78614261fd8f25a Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:54:49 +0100 Subject: [PATCH 16/89] Move test from VM PaymentController: `when flow started, then correct statement descriptor is propagated to CardReaderManager` --- .../CardReaderPaymentViewModelTest.kt | 14 ------------- .../CardReaderPaymentControllerTest.kt | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 0f0c4e04d47..e0953c6def2 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -533,20 +533,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(events[1]).isInstanceOf(Exit::class.java) } - @Test - fun `when flow started, then correct statement descriptor is propagated to CardReaderManager`() = - testBlocking { - val expectedResult = "hooray" - whenever(appPrefs.getCardReaderStatementDescriptor(anyOrNull(), anyOrNull(), anyOrNull())) - .thenReturn(expectedResult) - val captor = argumentCaptor() - - viewModel.start() - - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.statementDescriptor.value).isEqualTo(expectedResult) - } - @Test fun `when initializing payment, then ui updated to initializing payment state `() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 3d08821d22c..da96765c870 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -19,11 +19,9 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingP import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order -import com.woocommerce.android.model.UiString.UiStringRes import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -34,8 +32,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -44,9 +40,6 @@ import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.viewmodel.BaseUnitTest -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -437,6 +430,20 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(captor.firstValue.paymentDescription).isEqualTo(expectedResult) } + @Test + fun `when flow started, then correct statement descriptor is propagated to CardReaderManager`() = + testBlocking { + val expectedResult = "hooray" + whenever(appPrefs.getCardReaderStatementDescriptor(anyOrNull(), anyOrNull(), anyOrNull())) + .thenReturn(expectedResult) + val captor = argumentCaptor() + + controller.start() + + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.statementDescriptor.value).isEqualTo(expectedResult) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 7ab0235f6fe8aec394a2b6ba2b955564e13b5161 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:56:12 +0100 Subject: [PATCH 17/89] Add test to PaymentController: `when initializing payment, then Loading state emitted` --- .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index da96765c870..3a54fd8cbf4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -16,6 +16,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -32,6 +33,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -444,6 +446,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(captor.firstValue.statementDescriptor.value).isEqualTo(expectedResult) } + @Test + fun `when initializing payment, then Loading state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(InitializingPayment) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.LoadingData::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 96daeae47d4bb73491b9e46fbd016329d955bb79 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:57:27 +0100 Subject: [PATCH 18/89] Add test to PaymentController: `when collecting payment, then CollectingPayment state emitted` --- .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 3a54fd8cbf4..a84e0439187 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -33,6 +33,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -458,6 +459,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.LoadingData::class.java) } + @Test + fun `when collecting payment, then CollectingPayment state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 24ad94dd9368a39f196092e01e1b42d7f8b5401d Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 19:58:34 +0100 Subject: [PATCH 19/89] Add test to PaymentController: `given built in reader,when collecting payment, then ui CollectingPayment state emitted` --- .../controller/CardReaderPaymentControllerTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index a84e0439187..fd4a4ef2172 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -33,6 +33,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderCollectPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -472,6 +473,20 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState::class.java) } + @Test + fun `given built in reader,when collecting payment, then ui CollectingPayment state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + createController(BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.CollectingPayment.BuiltInReaderCollectPaymentState::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From faad942c95a03734811bf41d7db0d3c270fe12ef Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 20:00:31 +0100 Subject: [PATCH 20/89] Add test to PaymentController: `when processing payment, then ProcessingPayment state emitted` --- .../CardReaderPaymentControllerTest.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index fd4a4ef2172..c6ba3b37c00 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -17,6 +17,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -33,9 +34,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderCollectPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -474,7 +472,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } @Test - fun `given built in reader,when collecting payment, then ui CollectingPayment state emitted`() = + fun `given built in reader,when collecting payment, then CollectingPayment state emitted`() = testBlocking { whenever(cardReaderManager.collectPayment(any())).thenAnswer { flow { emit(CollectingPayment) } @@ -487,6 +485,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.CollectingPayment.BuiltInReaderCollectPaymentState::class.java) } + @Test + fun `when processing payment, then ProcessingPayment state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c7094f0c408844682e839d8d49f926d1f4aac596 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 20:01:44 +0100 Subject: [PATCH 21/89] Add test to PaymentController: `given built in reader, when processing payment, then ProcessingPayment state emitted` --- .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index c6ba3b37c00..0da4a1cd17c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -498,6 +498,20 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) } + @Test + fun `given built in reader, when processing payment, then ProcessingPayment state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + createController(BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.ProcessingPayment.BuiltInReaderProcessingPayment::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 27e2524d9780914c0d195be1f15ab376eb9fa9a0 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 18 Nov 2024 20:03:03 +0100 Subject: [PATCH 22/89] Move test from VM to PaymentController: `when processing payment completed with card present, then tracking keeper stores payment type` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 12 ------------ .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index e0953c6def2..9e33db3eb20 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -595,18 +595,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - @Test - fun `when processing payment completed with card present, then tracking keeper stores payment type`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.CARD_PRESENT)) } - } - - viewModel.start() - - verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card") - } - @Test fun `when processing payment completed with interac present, then tracking keeper stores payment type`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 0da4a1cd17c..ab0d762960d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -17,7 +17,9 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -512,6 +514,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.ProcessingPayment.BuiltInReaderProcessingPayment::class.java) } + @Test + fun `when processing payment completed with card present, then tracking keeper stores payment type`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.CARD_PRESENT)) } + } + + controller.start() + + verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card") + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From f01dde9c45f96abbeb45e272b44ebb83eb893405 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:23:43 +0100 Subject: [PATCH 23/89] Move test from VM to PaymentController: `when processing payment completed with interac present, then tracking keeper stores payment type` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 12 ------------ .../controller/CardReaderPaymentControllerTest.kt | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 9e33db3eb20..3711e78b0a4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -595,18 +595,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - @Test - fun `when processing payment completed with interac present, then tracking keeper stores payment type`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.INTERAC_PRESENT)) } - } - - viewModel.start() - - verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card_interac") - } - @Test fun `when processing payment completed with interac present, then track interac success`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ab0d762960d..ff9f3365ce4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -526,6 +526,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card") } + @Test + fun `when processing payment completed with interac present, then tracking keeper stores payment type`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.INTERAC_PRESENT)) } + } + + controller.start() + + verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card_interac") + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 541f79a058fd328fdba501787b04c9f3e62b90b3 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:24:37 +0100 Subject: [PATCH 24/89] Move test from VM to PaymentController: `when processing payment completed with interac present, then track interac success` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 11 ----------- .../controller/CardReaderPaymentControllerTest.kt | 12 ++++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 3711e78b0a4..0f61b053b94 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -595,17 +595,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - @Test - fun `when processing payment completed with interac present, then track interac success`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.INTERAC_PRESENT)) } - } - - viewModel.start() - - verify(tracker).trackInteracPaymentSucceeded() - } @Test fun `when processing payment completed with card present, then do not track interac success`() = diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ff9f3365ce4..269d5df19e5 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -538,6 +538,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("card_interac") } + @Test + fun `when processing payment completed with interac present, then track interac success`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.INTERAC_PRESENT)) } + } + + controller.start() + + verify(tracker).trackInteracPaymentSucceeded() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 6381858650c7d86e793ec7c69041eaa1f20ea7c8 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:25:25 +0100 Subject: [PATCH 25/89] Move test from VM to PaymentController: `when processing payment completed with card present, then do not track interac success` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 13 ------------- .../controller/CardReaderPaymentControllerTest.kt | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 0f61b053b94..af71b766463 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -595,19 +595,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - - @Test - fun `when processing payment completed with card present, then do not track interac success`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.CARD_PRESENT)) } - } - - viewModel.start() - - verify(tracker, never()).trackInteracPaymentSucceeded() - } - @Test fun `when processing payment completed with unknown type, then do not track interac success`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 269d5df19e5..1a24092422e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -59,6 +59,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel @@ -550,6 +551,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackInteracPaymentSucceeded() } + @Test + fun `when processing payment completed with card present, then do not track interac success`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.CARD_PRESENT)) } + } + + controller.start() + + verify(tracker, never()).trackInteracPaymentSucceeded() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c6f76bbfb11e78ada58b4385e2299d6baada8309 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:26:10 +0100 Subject: [PATCH 26/89] Move test from VM to PaymentController: `when processing payment completed with unknown type, then do not track interac success` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 12 ------------ .../controller/CardReaderPaymentControllerTest.kt | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index af71b766463..cf9ee4269ca 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -595,18 +595,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - @Test - fun `when processing payment completed with unknown type, then do not track interac success`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.UNKNOWN)) } - } - - viewModel.start() - - verify(tracker, never()).trackInteracPaymentSucceeded() - } - @Test fun `when processing payment completed with unknown, then tracking keeper stores payment type`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 1a24092422e..cd3637db0e1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -563,6 +563,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker, never()).trackInteracPaymentSucceeded() } + @Test + fun `when processing payment completed with unknown type, then do not track interac success`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.UNKNOWN)) } + } + + controller.start() + + verify(tracker, never()).trackInteracPaymentSucceeded() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From bd7ad118555c3e03c974304ac52008bbdc8fb415 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:27:00 +0100 Subject: [PATCH 27/89] Move test from VM to PaymentController: `when processing payment completed with unknown, then tracking keeper stores payment type` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 14 -------------- .../controller/CardReaderPaymentControllerTest.kt | 12 ++++++++++++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index cf9ee4269ca..eb6d91b3953 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -33,9 +33,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingP import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentCompleted import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentFailed -import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment -import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted import com.woocommerce.android.cardreader.payments.PaymentData import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.cardreader.payments.RefundParams @@ -595,18 +593,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderProcessingPaymentState::class.java) } - @Test - fun `when processing payment completed with unknown, then tracking keeper stores payment type`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPaymentCompleted(PaymentMethodType.UNKNOWN)) } - } - - viewModel.start() - - verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("unknown") - } - @Test fun `when capturing payment, then ui updated to capturing payment state`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index cd3637db0e1..62253a23d2e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -575,6 +575,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker, never()).trackInteracPaymentSucceeded() } + @Test + fun `when processing payment completed with unknown, then tracking keeper stores payment type`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPaymentCompleted(PaymentMethodType.UNKNOWN)) } + } + + controller.start() + + verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("unknown") + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 78d8ec28965259f860fb7fca54ebc14f8f39dd01 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:29:30 +0100 Subject: [PATCH 28/89] Add PaymentController test: `when capturing payment, then capturing payment state emitted` --- .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 62253a23d2e..940679bae71 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -15,6 +15,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CapturingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType @@ -36,6 +37,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCapturingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -587,6 +589,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderTrackingInfoKeeper).setPaymentMethodType("unknown") } + @Test + fun `when capturing payment, then capturing payment state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CapturingPayment) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentCapturing::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From e382e685f7356738402369874451fe954b80a1a6 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 13:31:13 +0100 Subject: [PATCH 29/89] Add PaymentController test: `given built in reader, when capturing payment, then ui updated to capturing payment state` --- .../CardReaderPaymentControllerTest.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 940679bae71..d2e8e7fa395 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -37,6 +37,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderCapturingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCapturingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -598,7 +599,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentCapturing::class.java) + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentCapturing.ExternalReaderPaymentCapturing::class.java) + } + + @Test + fun `given built in reader, when capturing payment, then ui updated to capturing payment state`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CapturingPayment) } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentCapturing.BuiltInReaderPaymentCapturing::class.java) } companion object { From 46ae7cf29a74b7749c3613a34b9749194b0c34de Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 14:49:03 +0100 Subject: [PATCH 30/89] Add PaymentController test: `given billing email empty, when external payment completed, then payment successful state emitted` --- .../CardReaderPaymentViewModelTest.kt | 2 +- .../CardReaderPaymentControllerTest.kt | 43 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index eb6d91b3953..3a49b39e5e7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -617,7 +617,7 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderCapturingPaymentState::class.java) } - +/// @Test fun `given billing email empty, when external payment completed, then ui updated to external payment successful state`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d2e8e7fa395..6951b8aade8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -6,6 +6,7 @@ import com.woocommerce.android.cardreader.CardReaderManager import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus +import com.woocommerce.android.cardreader.payments.CardPaymentStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CARD_REMOVED_TOO_EARLY import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD @@ -18,6 +19,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CapturingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentCompleted import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted @@ -27,6 +29,7 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -39,6 +42,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentE import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderCapturingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCapturingPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -108,6 +112,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController() whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connected(mock()))) whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) + whenever(orderRepository.getOrderById(any())).thenReturn(mockedOrder) whenever(mockedOrder.total).thenReturn(DUMMY_TOTAL) whenever(mockedOrder.currency).thenReturn("GBP") @@ -125,11 +130,30 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .thenReturn("test statement descriptor") whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) - whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) - whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn("test description") whenever(cardReaderPaymentOrderHelper.getAmountLabel(mockedOrder)) .thenReturn("${DUMMY_CURRENCY_SYMBOL}${DUMMY_TOTAL}") whenever(cardReaderManager.batteryStatus).thenAnswer { flow { emit(CardReaderBatteryStatus.Unknown) } } + whenever(currencyFormatter.formatAmountWithCurrency(DUMMY_TOTAL.toDouble(), "GBP")) + .thenReturn("${DUMMY_CURRENCY_SYMBOL}${DUMMY_TOTAL}") + whenever(mockedOrder.billingAddress).thenReturn(mockedAddress) + whenever(mockedAddress.email).thenReturn("") + whenever(mockedAddress.firstName).thenReturn("Tester") + whenever(mockedAddress.lastName).thenReturn("Test") + whenever(mockedOrder.orderKey).thenReturn("wc_order_j0LMK3bFhalEL") + whenever(mockedOrder.chargeId).thenReturn("chargeId") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { } + } + whenever(cardReaderManager.retryCollectPayment(any(), any())).thenAnswer { + flow { } + } + whenever(interacRefundableChecker.isRefundable(any())).thenReturn(true) + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow {} + } + whenever(paymentReceiptHelper.getReceiptUrl(ORDER_ID)).thenReturn(Result.success("test url")) + whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn("test description") + whenever(cardReaderPaymentOrderHelper.getReceiptDocumentName(mockedOrder.id)).thenReturn("receipt-order-1") } @OptIn(ExperimentalCoroutinesApi::class) @@ -604,7 +628,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } @Test - fun `given built in reader, when capturing payment, then ui updated to capturing payment state`() = + fun `given built in reader, when capturing payment, then capturing payment state emitted`() = testBlocking { whenever(cardReaderManager.collectPayment(any())).thenAnswer { flow { emit(CapturingPayment) } @@ -617,6 +641,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentCapturing.BuiltInReaderPaymentCapturing::class.java) } + @Test + fun `given billing email empty, when external payment completed, then payment successful state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 541095399e3a53d1c75cd39c899df24ca8f444fb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Tue, 19 Nov 2024 16:03:18 +0100 Subject: [PATCH 31/89] Add PaymentController test: `given billing not empty, when external payment completed, then payment successful receipt sent state emitted` --- .../CardReaderPaymentControllerTest.kt | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 6951b8aade8..7f2329a346d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -29,7 +29,6 @@ import com.woocommerce.android.model.Order import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -40,9 +39,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderCapturingPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCapturingPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -654,6 +650,35 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) } + @Test + fun `given billing email empty, when built in payment completed, then payment successful state emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) + } + + @Test + fun `given billing not empty, when external payment completed, then payment successful receipt sent state emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf( + CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java + ) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 4c66beaa67daefb75d7d8a395b5ccea5f2c24e06 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 13:32:22 +0100 Subject: [PATCH 32/89] Add `CardReaderPaymentController` test: `given billing not empty, when built in payment completed, then built in payment successful receipt sent state emitted` --- .../CardReaderPaymentViewModelTest.kt | 2 +- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 3a49b39e5e7..eb6d91b3953 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -617,7 +617,7 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderCapturingPaymentState::class.java) } -/// + @Test fun `given billing email empty, when external payment completed, then ui updated to external payment successful state`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 7f2329a346d..63e6fdb41c0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -39,6 +39,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -679,6 +680,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `given billing not empty, when built in payment completed, then built in payment successful receipt sent state emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + createController(BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf( + CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java + ) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 11a2aa45d3966397a885ab776c59482010e358ec Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 13:49:29 +0100 Subject: [PATCH 33/89] Add `CardReaderPaymentController` test: `when payment completed, then success sound is played` --- .../CardReaderPaymentControllerTest.kt | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 63e6fdb41c0..fc425d26386 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -39,7 +39,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -696,6 +696,24 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `when payment completed, then success sound is played`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + val events = mutableListOf() + val job = launch { + controller.event.collect { + events.add(it) + } + } + controller.start() + + assertThat(events[0]).isInstanceOf(PlaySuccessfulPaymentSound::class.java) + job.cancel() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From b1c344b4d281c2f142689324593183bacda30f7f Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 13:52:25 +0100 Subject: [PATCH 34/89] Move test from VM to `CardReaderPaymentController`: `when payment completed, then event tracked` --- .../CardReaderPaymentViewModelTest.kt | 12 ------------ .../CardReaderPaymentControllerTest.kt | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index eb6d91b3953..436b78a7d05 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -689,18 +689,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(events[0]).isInstanceOf(PlayChaChing::class.java) } - @Test - fun `when payment completed, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - viewModel.start() - - verify(tracker).trackPaymentSucceeded() - } - @Test fun `given external reader, when payment fails, then ui updated to external failed state`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index fc425d26386..fe2272ab966 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -3,6 +3,8 @@ package com.woocommerce.android.ui.payments.cardreader.payment.controller import com.woocommerce.android.AppPrefs import com.woocommerce.android.R import com.woocommerce.android.cardreader.CardReaderManager +import com.woocommerce.android.cardreader.config.CardReaderConfigForSupportedCountry +import com.woocommerce.android.cardreader.config.CardReaderConfigForUSA import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus @@ -17,9 +19,11 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CapturingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.Generic import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentCompleted +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentFailed import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted @@ -103,6 +107,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { private val mockedOrder = mock() private val mockedAddress = mock
() + private val cardReaderConfig: CardReaderConfigForSupportedCountry = CardReaderConfigForUSA + private val paymentFailedWithEmptyDataForRetry = PaymentFailed(Generic, null, "dummy msg") + @OptIn(InternalCoroutinesApi::class) @Before fun setUp() = testBlocking { @@ -714,6 +721,18 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { job.cancel() } + @Test + fun `when payment completed, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + controller.start() + + verify(tracker).trackPaymentSucceeded() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c110229cc812053153fff20390cb220551db548f Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:07:12 +0100 Subject: [PATCH 35/89] Add `CardReaderPaymentController` test: `given external reader, when payment fails, then failed state emitted` --- .../CardReaderPaymentControllerTest.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index fe2272ab966..c3332833f49 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -19,7 +19,10 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalI import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CapturingPayment +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.DeclinedByBackendError import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.Generic +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.NoNetwork +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CardPaymentStatusErrorType.Server import com.woocommerce.android.cardreader.payments.CardPaymentStatus.CollectingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.InitializingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentCompleted @@ -43,6 +46,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -109,11 +113,23 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { private val cardReaderConfig: CardReaderConfigForSupportedCountry = CardReaderConfigForUSA private val paymentFailedWithEmptyDataForRetry = PaymentFailed(Generic, null, "dummy msg") + private val paymentFailedWithValidDataForRetry = PaymentFailed(Generic, mock(), "dummy msg") + private val paymentFailedWithNoNetwork = PaymentFailed(NoNetwork, mock(), "dummy msg") + private val paymentFailedWithPaymentDeclined = PaymentFailed(DeclinedByBackendError.Unknown, mock(), "dummy msg") + private val paymentFailedWithCardReadTimeOut = PaymentFailed(Generic, mock(), "dummy msg") + private val paymentFailedWithServerError = PaymentFailed(Server(""), mock(), "dummy msg") + private val paymentFailedWithAmountTooSmall = PaymentFailed( + DeclinedByBackendError.AmountTooSmall, + mock(), + "dummy msg" + ) @OptIn(InternalCoroutinesApi::class) @Before fun setUp() = testBlocking { createController() + whenever(cardReaderConfigProvider.provideCountryConfigFor("US")) + .thenReturn(CardReaderConfigForUSA) whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connected(mock()))) whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) whenever(orderRepository.getOrderById(any())).thenReturn(mockedOrder) @@ -733,6 +749,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPaymentSucceeded() } + @Test + fun `given external reader, when payment fails, then failed state emitted`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 204c773ed793a807435646caf5024fb77e0ddd61 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:30:50 +0100 Subject: [PATCH 36/89] Add `CardReaderPaymentController` test: `given built in reader fails with Unknown error, when view model starts, then CTA with contact support button is provided` `given built in reader fails with Unknown error, when view model starts, then CTA with contact support button is provided` --- .../CardReaderPaymentControllerTest.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index c3332833f49..4ebbb814282 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -47,6 +47,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentC import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError +import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -764,6 +765,40 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) } + @Test + fun `given external reader fails with Unknown error, when flow starts, then CTA with contact support button is provided`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(Unknown) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + val externalReaderFailedPaymentState = + controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment + assertThat(externalReaderFailedPaymentState.cta).isNotNull + assertThat(externalReaderFailedPaymentState.cta!!.label).isEqualTo(R.string.support_contact) + } + + @Test + fun `given built in reader fails with Unknown error, when view model starts, then CTA with contact support button is provided`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(Unknown) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + createController(BUILT_IN) + + controller.start() + + val state = controller.paymentState.value as CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment + assertThat(state.cta).isNotNull + assertThat(state.cta!!.label).isEqualTo(R.string.support_contact) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 36e6a17f3b757a6f53a3cd16480fe6e3a0b3b337 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:41:29 +0100 Subject: [PATCH 37/89] Add `CardReaderPaymentController` test: `given external reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled` --- .../CardReaderPaymentViewModelTest.kt | 19 ------------------ .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 436b78a7d05..71f9f8a9fd3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -736,25 +736,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(state.secondaryActionLabel).isEqualTo(R.string.cancel) } - @Test - fun `given external reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled`() = - testBlocking { - whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.Declined.Generic) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(paymentFailedWithEmptyDataForRetry) } - } - - viewModel.start() - - val events = viewModel.event.captureValues() - - (viewModel.viewStateData.value as ExternalReaderFailedPaymentState).onPrimaryActionClicked.invoke() - - assertThat(events[0]).isInstanceOf(Exit::class.java) - assertThat(events[1]).isInstanceOf(ContactSupport::class.java) - } - @Test fun `when contact support clicked, then contact support event tracked`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 4ebbb814282..ac4fcb87119 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -56,6 +56,7 @@ import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter +import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi @@ -799,6 +800,25 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(state.cta!!.label).isEqualTo(R.string.support_contact) } + @Test + fun `given external reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Declined.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + val events: List = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment).cta!!.onCallToActionTapped.invoke() + } + + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + assertThat(events[1]).isInstanceOf(CardReaderPaymentEvent.ContactSupportTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 93abe093c90201671f947ad23cbd15c1d4a711d7 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:45:57 +0100 Subject: [PATCH 38/89] Add `CardReaderPaymentController` test: `given built in reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled` --- .../CardReaderPaymentViewModelTest.kt | 16 ------ .../CardReaderPaymentControllerTest.kt | 49 ++++++++++++++++--- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 71f9f8a9fd3..5a379949a69 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -736,22 +736,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(state.secondaryActionLabel).isEqualTo(R.string.cancel) } - @Test - fun `when contact support clicked, then contact support event tracked`() = - testBlocking { - whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.Declined.Generic) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(paymentFailedWithEmptyDataForRetry) } - } - - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderFailedPaymentState).onPrimaryActionClicked.invoke() - - verify(tracker).trackPaymentFailedContactSupportTapped() - } - @Test fun `given built in reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ac4fcb87119..d7a7fa32cc8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.U import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentFailed.* import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper @@ -399,7 +400,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) + .isInstanceOf(ExternalReaderFailedPayment::class.java) } @Test @@ -412,7 +413,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment::class.java) + .isInstanceOf(BuiltInReaderFailedPayment::class.java) } @Test @@ -763,7 +764,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment::class.java) + .isInstanceOf(ExternalReaderFailedPayment::class.java) } @Test @@ -778,7 +779,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val externalReaderFailedPaymentState = - controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment + controller.paymentState.value as ExternalReaderFailedPayment assertThat(externalReaderFailedPaymentState.cta).isNotNull assertThat(externalReaderFailedPaymentState.cta!!.label).isEqualTo(R.string.support_contact) } @@ -795,7 +796,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - val state = controller.paymentState.value as CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment + val state = controller.paymentState.value as BuiltInReaderFailedPayment assertThat(state.cta).isNotNull assertThat(state.cta!!.label).isEqualTo(R.string.support_contact) } @@ -812,7 +813,43 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events: List = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment).cta!!.onCallToActionTapped.invoke() + (controller.paymentState.value as ExternalReaderFailedPayment).cta!!.onCallToActionTapped() + } + + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + assertThat(events[1]).isInstanceOf(CardReaderPaymentEvent.ContactSupportTapped::class.java) + } + + @Test + fun `when contact support clicked, then contact support event tracked`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Declined.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).cta!!.onCallToActionTapped() + + verify(tracker).trackPaymentFailedContactSupportTapped() + } + + @Test + fun `given built in reader fails with generic error, when contact support clicked, then contact support emitted and flow canceled`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Declined.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + createController(BUILT_IN) + + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).cta!!.onCallToActionTapped() } assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) From 67333605f3fd845154bbc1982267f0a781e66ad3 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:52:22 +0100 Subject: [PATCH 39/89] Add `CardReaderPaymentController` test: `when payment fails, then event tracked` --- .../CardReaderPaymentViewModelTest.kt | 26 ----------- .../CardReaderPaymentControllerTest.kt | 45 +++++++++++++++++++ 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 5a379949a69..7b7b467d420 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -771,20 +771,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderFailedPaymentState::class.java) } - @Test - fun `when payment fails, then invalidate onboarding cache`() = - testBlocking { - whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.Generic) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(paymentFailedWithEmptyDataForRetry) } - } - - viewModel.start() - - verify(cardReaderOnboardingChecker).invalidateCache() - } - @Test fun `given external reader, when payment fails because of NoNetwork, then error is mapped correctly`() = testBlocking { @@ -890,18 +876,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { ) } - @Test - fun `when payment fails, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(paymentFailedWithEmptyDataForRetry) } - } - - viewModel.start() - - verify(tracker).trackPaymentFailed(anyOrNull(), anyOrNull()) - } - @Test fun `given external reader, when payment fails because of NO_NETWORK, then error is mapped correctly`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d7a7fa32cc8..177dbfa5b6e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -48,6 +48,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentE import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -81,6 +82,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal import kotlin.reflect.KMutableProperty0 +import kotlin.test.assertEquals @OptIn(ExperimentalCoroutinesApi::class) class CardReaderPaymentControllerTest : BaseUnitTest() { @@ -856,6 +858,49 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events[1]).isInstanceOf(CardReaderPaymentEvent.ContactSupportTapped::class.java) } + @Test + fun `given built in reader, when payment fails, then ui updated to built in failed state`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + createController(BUILT_IN) + + controller.start() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment::class.java) + } + + @Test + fun `when payment fails, then invalidate onboarding cache`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + verify(cardReaderOnboardingChecker).invalidateCache() + } + + @Test + fun `when payment fails, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + + verify(tracker).trackPaymentFailed(anyOrNull(), anyOrNull()) + } + + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c2b00f943e6022c9bb5148d1f89a8e8756603404 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:57:25 +0100 Subject: [PATCH 40/89] Add `CardReaderPaymentController` test: `given external reader, when payment fails because of AMOUNT_TOO_SMALL, then failed state is not retryable` --- .../CardReaderPaymentControllerTest.kt | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 177dbfa5b6e..f775c1d838e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -33,6 +33,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingP import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order +import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider @@ -47,8 +48,8 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentC import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError +import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -82,7 +83,8 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal import kotlin.reflect.KMutableProperty0 -import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull @OptIn(ExperimentalCoroutinesApi::class) class CardReaderPaymentControllerTest : BaseUnitTest() { @@ -900,6 +902,31 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPaymentFailed(anyOrNull(), anyOrNull()) } + @Test + fun `given external reader, when payment fails because of AMOUNT_TOO_SMALL, then failed state is not retryable`() = + testBlocking { + val error = AmountTooSmall(UiStringText("Amount must be at least US$0.50")) + whenever( + errorMapper.mapPaymentErrorToUiError( + DeclinedByBackendError.AmountTooSmall, + cardReaderConfig, + false + ) + ).thenReturn(error) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithAmountTooSmall) } + } + + controller.start() + + assertNull( + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry + ) + assertNotNull( + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onCancel + ) + } + companion object { private const val ORDER_ID = 1L From 7e19d9d74252c75465ce0b7feb9b8139d99a0521 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 14:59:01 +0100 Subject: [PATCH 41/89] Add `CardReaderPaymentController` test: `given external reader, when payment fails not because of AMOUNT_TOO_SMALL, then failed state is retryable` --- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index f775c1d838e..d9e76659997 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -50,6 +50,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -83,6 +84,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import java.math.BigDecimal import kotlin.reflect.KMutableProperty0 +import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -927,6 +929,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `given external reader, when payment fails not because of AMOUNT_TOO_SMALL, then failed state is retryable`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Server(""), cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Server) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithServerError) } + } + + controller.start() + + assertNotNull( + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry, + ) + } companion object { private const val ORDER_ID = 1L From 4a272841e4ffaef7ed12d1a52a749e578c8ee3cb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 15:02:03 +0100 Subject: [PATCH 42/89] Add `CardReaderPaymentController` test: `given built in reader, when payment fails not because of AMOUNT_TOO_SMALL, then failed state has Try again button` `given built in reader, when payment fails PIN_REQUIRED, then failed state has purchase card reader cta` --- .../CardReaderPaymentControllerTest.kt | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d9e76659997..ad78a024f9b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -50,7 +50,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -945,6 +944,46 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `given built in reader, when payment fails not because of AMOUNT_TOO_SMALL, then failed state has Try again button`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Server(""), cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Server) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithServerError) } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + + assertNotNull( + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry, + ) + } + + @Test + fun `given built in reader, when payment fails PIN_REQUIRED, then failed state has purchase card reader cta`() = + testBlocking { + whenever( + errorMapper.mapPaymentErrorToUiError( + DeclinedByBackendError.CardDeclined.PinRequired, + cardReaderConfig, + true + ) + ).thenReturn(PaymentFlowError.BuiltInReader.PinRequired) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(DeclinedByBackendError.CardDeclined.PinRequired, mock(), "dummy msg")) } + } + createController(BUILT_IN) + + controller.start() + + assertEquals( + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).cta!!.label, + R.string.card_reader_payment_payment_failed_purchase_hardware_reader + ) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From a84693129317a7fb5db52c9721fac3031e867957 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 15:05:46 +0100 Subject: [PATCH 43/89] Add `CardReaderPaymentController` test: `given built in reader, when purchase button clicked, then purchase even emmited` --- .../CardReaderPaymentControllerTest.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ad78a024f9b..4693bdc81ff 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -37,6 +37,7 @@ import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -50,6 +51,8 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.PurchaseCardReader +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -984,6 +987,32 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `given built in reader, when purchase button clicked, then purchase even emmited`() = + testBlocking { + whenever( + errorMapper.mapPaymentErrorToUiError( + DeclinedByBackendError.CardDeclined.PinRequired, + cardReaderConfig, + true + ) + ).thenReturn(PaymentFlowError.BuiltInReader.PinRequired) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(DeclinedByBackendError.CardDeclined.PinRequired, mock(), "dummy msg")) } + } + whenever(wooStore.getStoreCountryCode(siteModel)).thenReturn("US") + createController(cardReaderType = BUILT_IN) + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).cta!!.onCallToActionTapped() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PurchaseCardReaderTapped::class.java) + assertThat((events.last() as CardReaderPaymentEvent.PurchaseCardReaderTapped).url).isEqualTo( + "https://woocommerce.com/products/hardware/US" + ) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c2df5dd6e8a4d11766bd1cb325a1143ca6705acd Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 15:12:27 +0100 Subject: [PATCH 44/89] Add `CardReaderPaymentController` test: `given built in reader, when payment fails because of AMOUNT_TOO_SMALL, then clicking on ok button triggers exit event` --- .../CardReaderPaymentControllerTest.kt | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 4693bdc81ff..10395ba9a46 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -37,7 +37,6 @@ import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -51,8 +50,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.PurchaseCardReader -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1013,6 +1010,52 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { ) } + @Test + fun `given external reader, when payment fails because of AMOUNT_TOO_SMALL, then clicking on ok button triggers exit event`() = + testBlocking { + val error = AmountTooSmall(UiStringText("Amount must be at least US$0.50")) + whenever( + errorMapper.mapPaymentErrorToUiError( + DeclinedByBackendError.AmountTooSmall, + cardReaderConfig, + false + ) + ).thenReturn(error) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithAmountTooSmall) } + } + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onCancel!!() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given built in reader, when payment fails because of AMOUNT_TOO_SMALL, then clicking on ok button triggers exit event`() = + testBlocking { + val error = AmountTooSmall(UiStringText("Amount must be at least US$0.50")) + whenever( + errorMapper.mapPaymentErrorToUiError( + DeclinedByBackendError.AmountTooSmall, + cardReaderConfig, + true + ) + ).thenReturn(error) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithAmountTooSmall) } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onCancel!!() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 8c2c7565a63c31ececf53e71a8ce5de29e3bc7b7 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 15:14:26 +0100 Subject: [PATCH 45/89] Add `CardReaderPaymentController` test: `given payment fails because of NFC_DISABLED, when primary button clicked, then tracked and enablenfc emitted` --- .../CardReaderPaymentControllerTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 10395ba9a46..62d97d55f6d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -47,9 +47,11 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.EnableNfc import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -59,6 +61,7 @@ import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter +import com.woocommerce.android.util.captureValues import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -1056,6 +1059,39 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } + @Test + fun `given payment fails because of NFC_DISABLED, when primary button clicked, then tracked and enablenfc emitted`() = + testBlocking { + whenever( + errorMapper.mapPaymentErrorToUiError( + CardPaymentStatus.CardPaymentStatusErrorType.BuiltInReader.NfcDisabled, + cardReaderConfig, + true + ) + ).thenReturn(PaymentFlowError.BuiltInReader.NfcDisabled) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { + emit( + PaymentFailed( + CardPaymentStatus.CardPaymentStatusErrorType.BuiltInReader.NfcDisabled, + null, + "message" + ) + ) + } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).cta!!.onCallToActionTapped() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.EnableNfcTapped::class.java) + verify(tracker).trackPaymentFailedEnabledNfcTapped() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From ca8c3b545df107cddb0b3128c7b1f708f629d7e2 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 15:19:25 +0100 Subject: [PATCH 46/89] Add `CardReaderPaymentController` test: `given user clicks on retry and built in, when payment fails and retryData are null, then flow restarted from scratch` --- .../CardReaderPaymentControllerTest.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 62d97d55f6d..c61e0514f80 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -52,6 +52,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -78,6 +79,7 @@ import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -1092,6 +1094,41 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPaymentFailedEnabledNfcTapped() } + @Test + fun `given user clicks on retry and external, when payment fails and retryData are null, then flow restarted from scratch`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + controller.start() + clearInvocations(cardReaderManager) + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).collectPayment(any()) + } + + @Test + fun `given user clicks on retry and built in, when payment fails and retryData are null, then flow restarted from scratch`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + clearInvocations(cardReaderManager) + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).collectPayment(any()) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 9936c7a12dc445ca44be7ba7653e2f30353ab691 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:14:12 +0100 Subject: [PATCH 47/89] Add `CardReaderPaymentController` test: `given failed payment and external reader, when user retries, then retryCollectPayment invoked` --- .../CardReaderPaymentControllerTest.kt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index c61e0514f80..cc69c2d0453 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -47,11 +47,9 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper -import com.woocommerce.android.ui.payments.cardreader.payment.EnableNfc import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -62,7 +60,6 @@ import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter -import com.woocommerce.android.util.captureValues import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -1129,6 +1126,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderManager).collectPayment(any()) } + @Test + fun `given failed payment and external reader, when user retries, then retryCollectPayment invoked`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithValidDataForRetry) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).retryCollectPayment(any(), any()) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 8f25805ae2469f2c626284b5c81c426fc71fbd48 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:18:13 +0100 Subject: [PATCH 48/89] Add `CardReaderPaymentController` test: `given failed payment and external reader, when user retries, then flow retried with provided PaymentData` --- .../CardReaderPaymentControllerTest.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index cc69c2d0453..aef0054858b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -30,6 +30,7 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentFail import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentMethodType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted +import com.woocommerce.android.cardreader.payments.PaymentData import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -50,6 +51,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -77,6 +79,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -1142,6 +1145,40 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderManager).retryCollectPayment(any(), any()) } + @Test + fun `given failed payment and built-in reader, when user retries, then retryCollectPayment invoked`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithValidDataForRetry) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).retryCollectPayment(any(), any()) + } + + @Test + fun `given failed payment and external reader, when user retries, then flow retried with provided PaymentData`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + val paymentData = mock() + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(Generic, paymentData, "dummy msg")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).retryCollectPayment(any(), eq(paymentData)) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From ccc26d6e4dd112d2beb48ca00b32df47c6593442 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:20:04 +0100 Subject: [PATCH 49/89] Add `CardReaderPaymentController` test: `given failed payment and built-in reader, when user retries, then flow retried with provided PaymentData` --- .../CardReaderPaymentControllerTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index aef0054858b..9d4f97ec570 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1179,6 +1179,24 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderManager).retryCollectPayment(any(), eq(paymentData)) } + @Test + fun `given failed payment and built-in reader, when user retries, then flow retried with provided PaymentData`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Generic) + val paymentData = mock() + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(Generic, paymentData, "dummy msg")) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onRetry!!() + advanceUntilIdle() + + verify(cardReaderManager).retryCollectPayment(any(), eq(paymentData)) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 0f220edcfa77ef33bc055dda6937e45b25acac65 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:22:42 +0100 Subject: [PATCH 50/89] Add `CardReaderPaymentController` test: `given external failed payment, when user clicks on secondary button, then exit event is triggered` --- .../CardReaderPaymentControllerTest.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 9d4f97ec570..4e25fd87d71 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -64,6 +64,7 @@ import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -1197,6 +1198,24 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderManager).retryCollectPayment(any(), eq(paymentData)) } + @Test + fun `given external failed payment, when user clicks on secondary button, then exit event is triggered`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + val paymentData = mock() + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(Generic, paymentData, "dummy msg")) } + } + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onCancel!!() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From d8350a01bf5229330ae43d43524c1b0920018bf1 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:25:08 +0100 Subject: [PATCH 51/89] Add `CardReaderPaymentController` test: `given built in failed payment, when user clicks on secondary button, then exit event is triggered` --- .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 4e25fd87d71..40f054136bf 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1216,6 +1216,26 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } + @Test + fun `given built in failed payment, when user clicks on secondary button, then exit event is triggered`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.Generic) + val paymentData = mock() + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(Generic, paymentData, "dummy msg")) } + } + createController(cardReaderType = BUILT_IN) + + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentFailed).onCancel!!() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From b7fc22b9a9c59f04efa78e23abc54c8c205fc2b3 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:29:04 +0100 Subject: [PATCH 52/89] Add `CardReaderPaymentController` test: `when loading data, then cancellation is possible` --- .../controller/CardReaderPaymentControllerTest.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 40f054136bf..ada90f1191a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -34,6 +34,7 @@ import com.woocommerce.android.cardreader.payments.PaymentData import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order +import com.woocommerce.android.model.UiString.UiStringRes import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository @@ -1236,6 +1237,15 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } + @Test + fun `when loading data, then cancellation is possible`() = testBlocking { + controller.start() + val paymentState = controller.paymentState.value + + assertThat(paymentState).isInstanceOf(CardReaderPaymentState.LoadingData::class.java) + assertNotNull((paymentState as CardReaderPaymentState.LoadingData).onCancel) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From dcbcfcdcc416a6773ec3be2d3cc172b9468cac46 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:31:27 +0100 Subject: [PATCH 53/89] Add `CardReaderPaymentController` test: `when collecting payment, then cancellation is possible` --- .../controller/CardReaderPaymentControllerTest.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ada90f1191a..b26cc77d629 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1246,6 +1246,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertNotNull((paymentState as CardReaderPaymentState.LoadingData).onCancel) } + @Test + fun `when collecting payment, then cancellation is possible`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + + controller.start() + val viewState = controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + + assertNotNull(viewState.onCancel) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 7dcc66f3a54d76bd0bf8059b8346a90b946663fb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:37:53 +0100 Subject: [PATCH 54/89] Rename vars --- .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index b26cc77d629..e27dc429d79 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -34,7 +34,6 @@ import com.woocommerce.android.cardreader.payments.PaymentData import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order -import com.woocommerce.android.model.UiString.UiStringRes import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository @@ -52,8 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -65,7 +62,6 @@ import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -1254,9 +1250,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - val viewState = controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + val paymentState = controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState - assertNotNull(viewState.onCancel) + assertNotNull(paymentState.onCancel) + } + + @Test + fun `when processing payment, then cancellation is possible`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + + controller.start() + val paymentState = controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + assertNotNull(paymentState.onCancel) } companion object { From 6cb9005548615835a02990251778850f1d2c6ec5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:39:34 +0100 Subject: [PATCH 55/89] Add `CardReaderPaymentController` test: `when payment fails, then cancellation is possible` --- .../controller/CardReaderPaymentControllerTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index e27dc429d79..d37e2c52254 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1267,6 +1267,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertNotNull(paymentState.onCancel) } + @Test + fun `when payment fails, then cancellation is possible`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithEmptyDataForRetry) } + } + + controller.start() + val paymentState = controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment + + assertNotNull(paymentState.onCancel) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From de32048390334a60bb3b6e8d6244ec3876c48291 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:42:15 +0100 Subject: [PATCH 56/89] Move test from VM to `CardReaderPaymentController`: `when payment succeeds, then receiptUrl stored into a persistant storage` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 13 ------------- .../controller/CardReaderPaymentControllerTest.kt | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 7b7b467d420..bf3bf16be0c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1732,19 +1732,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(UiStringRes(R.string.card_reader_payment_failed_server_error_state)) } - @Test - fun `when payment succeeds, then receiptUrl stored into a persistant storage`() = - testBlocking { - val receiptUrl = "testUrl" - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted(receiptUrl)) } - } - - viewModel.start() - - verify(paymentReceiptHelper).storeReceiptUrl(eq(ORDER_ID), eq(receiptUrl)) - } - @Test fun `given external reader, when payment succeeds, then correct labels, illustration and buttons are shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d37e2c52254..312b73550b0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -38,6 +38,7 @@ import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -1282,6 +1283,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertNotNull(paymentState.onCancel) } + @Test + fun `when payment succeeds, then receiptUrl stored into a persistant storage`() = + testBlocking { + val receiptUrl = "testUrl" + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted(receiptUrl)) } + } + + controller.start() + + verify(paymentReceiptHelper).storeReceiptUrl(eq(ORDER_ID), eq(receiptUrl)) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From bf56f5ca7a7d50b7ae85413b03b81779ebbc6bba Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:43:14 +0100 Subject: [PATCH 57/89] Move test from VM to `CardReaderPaymentController`: `given payment flow already started, when start() is invoked, then flow is not restarted` --- .../CardReaderPaymentViewModelTest.kt | 16 ---------------- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index bf3bf16be0c..3fa3b2174e7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,22 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given payment flow already started, when start() is invoked, then flow is not restarted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow {} - } - - viewModel.start() - viewModel.start() - viewModel.start() - viewModel.start() - - verify(cardReaderManager, times(1)) - .collectPayment(anyOrNull()) - } - @Test fun `given billing email empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 312b73550b0..9427bd49721 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -81,6 +81,7 @@ import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel @@ -1296,6 +1297,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(paymentReceiptHelper).storeReceiptUrl(eq(ORDER_ID), eq(receiptUrl)) } + @Test + fun `given payment flow already started, when start() is invoked, then flow is not restarted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow {} + } + + controller.start() + controller.start() + controller.start() + controller.start() + + verify(cardReaderManager, times(1)) + .collectPayment(anyOrNull()) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 04b8b51893efe8e32df1127728abbba527d8a340 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:47:03 +0100 Subject: [PATCH 58/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and external, when user clicks on print receipt button, then PrintReceipt event emitted` --- .../CardReaderPaymentViewModelTest.kt | 13 ------------- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 3fa3b2174e7..e4941609cc3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,19 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given billing email empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 9427bd49721..5c8b65149f1 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -52,6 +52,8 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1313,6 +1315,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .collectPayment(anyOrNull()) } + @Test + fun `given billing email empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 47328f6273489cf74069a25f189a9b033e733445 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:49:55 +0100 Subject: [PATCH 59/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted` --- .../CardReaderPaymentViewModelTest.kt | 15 --------------- .../CardReaderPaymentControllerTest.kt | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index e4941609cc3..7c82219c275 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,21 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given billing email not empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 5c8b65149f1..eafea3e3b60 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -53,6 +53,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -1330,6 +1331,23 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given billing email empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c216f03944798434c58314e4a44ed15fddb9d11c Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:53:02 +0100 Subject: [PATCH 60/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and external, when user clicks on print receipt button, then PrintReceipt event emitted` --- .../CardReaderPaymentViewModelTest.kt | 15 --------------- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 7c82219c275..027375255c9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,21 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given billing email not empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index eafea3e3b60..d226fb6534f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -54,6 +54,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.A import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -1348,6 +1349,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given billing email not empty and external, when user clicks on print receipt button, then PrintReceipt event emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 06fcf18b8c55dd88157d89a214a9c49c9cac9825 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:55:59 +0100 Subject: [PATCH 61/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted` --- .../CardReaderPaymentViewModelTest.kt | 17 ----------------- .../CardReaderPaymentControllerTest.kt | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 027375255c9..95cfe7fa482 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,23 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given billing email empty and external, when user clicks on print receipt button, then printing receipt state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d226fb6534f..85c7999d37b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -53,6 +53,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState @@ -1365,6 +1366,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given billing email not empty and built in, when user clicks on print receipt button, then PrintReceipt event emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + } + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From d1bc07be46c2a12e994ac24cb448fea0ff44e76d Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 16:58:21 +0100 Subject: [PATCH 62/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and external, when user clicks on print receipt button, then printing receipt state shown` --- .../CardReaderPaymentViewModelTest.kt | 14 ------------- .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 95cfe7fa482..0c45d17c9d5 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,20 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and external, when user clicks on print receipt button, then printing receipt state shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(PrintingReceiptState::class.java) - } - @Test fun `given billing email empty and built in, when user clicks on print receipt button, then printing receipt state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 85c7999d37b..b0f1204a9d5 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -38,7 +38,6 @@ import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -52,11 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1382,6 +1376,20 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given billing email empty and external, when user clicks on print receipt button, then printing receipt state shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 22de1eb84bbca0ec2ccf66a571ffecfa2f95abd2 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:02:52 +0100 Subject: [PATCH 63/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and built-in, when user clicks on print receipt button, then printing receipt state shown` --- .../CardReaderPaymentViewModelTest.kt | 17 ----------------- .../CardReaderPaymentControllerTest.kt | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 0c45d17c9d5..a975a2f0175 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,23 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and built in, when user clicks on print receipt button, then printing receipt state shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(PrintingReceiptState::class.java) - } - @Test fun `given billing email not empty and external, when user clicks on print receipt button, then printing receipt state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index b0f1204a9d5..23bb74a8764 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1390,6 +1390,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) } + @Test + fun `given billing email empty and built-in, when user clicks on print receipt button, then printing receipt state shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From eaad07be8d7d975cf6c8facb5fc643492a1340bb Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:05:03 +0100 Subject: [PATCH 64/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and external, when user clicks on print receipt button, then printing receipt state shown` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 16 ---------------- .../CardReaderPaymentControllerTest.kt | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index a975a2f0175..41d5bbd86b8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,22 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and external, when user clicks on print receipt button, then printing receipt state shown`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(PrintingReceiptState::class.java) - } - @Test fun `given billing email not empty and built in, when user clicks on print receipt button, then printing receipt state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 23bb74a8764..ad1386e8517 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1405,6 +1405,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) } + @Test + fun `given billing email not empty and external, when user clicks on print receipt button, then printing receipt state shown`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From c8af83cfef55d9588c8fa968db67c9ce246f7c51 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:06:47 +0100 Subject: [PATCH 65/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and built-in, when user clicks on print receipt button, then printing receipt state shown` --- .../CardReaderPaymentViewModelTest.kt | 19 ------------------- .../CardReaderPaymentControllerTest.kt | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 41d5bbd86b8..5ce6d531c94 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,25 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and built in, when user clicks on print receipt button, then printing receipt state shown`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(PrintingReceiptState::class.java) - } - @Test fun `given billing email empty and external, when print result received, then payment successful state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ad1386e8517..4f1444eec28 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1420,6 +1420,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) } + @Test + fun `given billing email not empty and built-in, when user clicks on print receipt button, then printing receipt state shown`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 8f49f5d4b9f56f3afbb3faf21162c6970d713acd Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:13:05 +0100 Subject: [PATCH 66/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and built in, when print result received, then payment successful state shown` --- .../CardReaderPaymentViewModelTest.kt | 31 ------------------ .../CardReaderPaymentControllerTest.kt | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 5ce6d531c94..c295f331e8c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,37 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and external, when print result received, then payment successful state shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - viewModel.onPrintResult(CANCELLED) - - assertThat(viewModel.viewStateData.value).isInstanceOf(ExternalReaderPaymentSuccessfulState::class.java) - } - - @Test - fun `given billing email empty and built in, when print result received, then payment successful state shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - viewModel.onPrintResult(CANCELLED) - - assertThat(viewModel.viewStateData.value).isInstanceOf(BuiltInReaderPaymentSuccessfulState::class.java) - } - @Test fun `given billing email not empty and external, when print result received, then payment success receipt sent state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 4f1444eec28..15453a8e7a9 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -60,6 +60,7 @@ import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter +import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.CANCELLED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -1436,6 +1437,37 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) } + @Test + fun `given billing email empty and external, when print result received, then payment successful state shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + + controller.onPrintResult(CANCELLED) + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) + } + + @Test + fun `given billing email empty and built in, when print result received, then payment successful state shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(BUILT_IN) + + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + + controller.onPrintResult(CANCELLED) + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 0d046e65640e63fb63a3ea47ed399339a34773d5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:15:56 +0100 Subject: [PATCH 67/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and external, when print result received, then payment success receipt sent state shown` --- .../CardReaderPaymentViewModelTest.kt | 17 ----------------- .../CardReaderPaymentControllerTest.kt | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index c295f331e8c..553502512c8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,23 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and external, when print result received, then payment success receipt sent state shown`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - viewModel.onPrintResult(CANCELLED) - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState::class.java) - } - @Test fun `given billing email not empty and built in, when print result received, then payment success receipt sent state shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 15453a8e7a9..7c6bdc1a387 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1468,6 +1469,24 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) } + @Test + fun `given billing email not empty and external, when print result received, then payment success receipt sent state shown`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + controller.onPrintResult(CANCELLED) + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java) + } + + + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From bcea3934ff11febffe646a21e8fdfdce6e7a80bc Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:18:25 +0100 Subject: [PATCH 68/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and built in, when print result received, then payment success receipt sent state shown` --- .../CardReaderPaymentViewModelTest.kt | 20 ------------------- .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 553502512c8..2745dd2defa 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,26 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and built in, when print result received, then payment success receipt sent state shown`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - viewModel.onPrintResult(CANCELLED) - - assertThat(viewModel.viewStateData.value) - .isInstanceOf(BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState::class.java) - } - @Test fun `given in printing receipt state and external, when view recreated, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 7c6bdc1a387..a41beedf56f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -1485,6 +1486,25 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java) } + @Test + fun `given billing email not empty and built in, when print result received, then payment success receipt sent state shown`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + controller.onPrintResult(CANCELLED) + + assertThat(controller.paymentState.value) + .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java) + } + companion object { From 3d10156a8f0d8ec17bd8f4792deac8c258bf633a Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:37:51 +0100 Subject: [PATCH 69/89] Move test from VM to `CardReaderPaymentController`: `given in printing receipt state and external, when view recreated, then PrintReceipt event emitted` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 14 -------------- .../CardReaderPaymentControllerTest.kt | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 2745dd2defa..605220af217 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,20 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given in printing receipt state and external, when view recreated, then PrintReceipt event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - viewModel.onViewCreated() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given in printing receipt state and built in, when view recreated, then PrintReceipt event emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index a41beedf56f..71bd02520d8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,8 +51,10 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1505,7 +1507,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java) } + @Test + fun `given in printing receipt state and external, when view recreated, then PrintReceipt event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + } + controller.onViewCreated() + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } companion object { private const val ORDER_ID = 1L From ff0ddaf8ba21a2a38c60b5c58849d10dbfe65125 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:39:42 +0100 Subject: [PATCH 70/89] Move test from VM to `CardReaderPaymentController`: `given in printing receipt state and built in, when view recreated, then PrintReceipt event emitted` --- .../CardReaderPaymentViewModelTest.kt | 16 ---------------- .../CardReaderPaymentControllerTest.kt | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 605220af217..cbfa394f623 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,22 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given in printing receipt state and built in, when view recreated, then PrintReceipt event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - viewModel.onViewCreated() - - assertThat(viewModel.event.value).isInstanceOf(PrintReceipt::class.java) - } - @Test fun `given not in printing receipt state, when view recreated, then state not changed`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 71bd02520d8..b9433182c96 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -53,6 +53,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.A import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound @@ -1523,6 +1524,24 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given in printing receipt state and built in, when view recreated, then PrintReceipt event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + } + + controller.onViewCreated() + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 40b7495004973ce759a2d984f389f30ff14d8b5c Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:43:46 +0100 Subject: [PATCH 71/89] Move test from VM to `CardReaderPaymentController`: `given not in printing receipt state, when view recreated, then state not changed` --- .../CardReaderPaymentViewModelTest.kt | 28 ------------------- .../CardReaderPaymentControllerTest.kt | 16 +++++++++++ 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index cbfa394f623..53acda03313 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1789,34 +1789,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given not in printing receipt state, when view recreated, then state not changed`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow {} - } - viewModel.start() - val originalState = viewModel.viewStateData.value - assertThat(originalState).isNotInstanceOf(PrintingReceiptState::class.java) - - viewModel.onViewCreated() - - assertThat(viewModel.viewStateData.value).isEqualTo(originalState) - } - - @Test - fun `given billing email empty and external, when user clicks on print receipt button, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - verify(tracker).trackPrintReceiptTapped() - } - @Test fun `given billing email empty and built in, when user clicks on print receipt button, then event tracked`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index b9433182c96..8cfe6794e08 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -56,6 +56,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInR import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.PrintingReceiptState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1542,6 +1543,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } + @Test + fun `given not in printing receipt state, when view recreated, then state not changed`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow {} + } + controller.start() + val originalState = controller.paymentState.value + assertThat(originalState).isNotInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) + + controller.onViewCreated() + + assertThat(controller.paymentState.value).isEqualTo(originalState) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From fffefebd19635933d9abd9fd6f2543fa73541184 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:45:02 +0100 Subject: [PATCH 72/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and external, when user clicks on print receipt button, then event tracked` --- .../controller/CardReaderPaymentControllerTest.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 8cfe6794e08..7f8bd110970 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1558,6 +1558,19 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isEqualTo(originalState) } + @Test + fun `given billing email empty and external, when user clicks on print receipt button, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + + verify(tracker).trackPrintReceiptTapped() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 615d2ae19db50682853e74008cf44177435be867 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:46:08 +0100 Subject: [PATCH 73/89] Move test from VM to `CardReaderPaymentController`: `given billing email empty and built in, when user clicks on print receipt button, then event tracked` --- .../CardReaderPaymentViewModelTest.kt | 17 -------------- .../CardReaderPaymentControllerTest.kt | 22 ++++++++++++++----- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 53acda03313..961fed24a9c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -82,7 +82,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.External import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderProcessingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.FailedRefundState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.PrintingReceiptState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ProcessingRefundState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ReFetchingOrderState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.RefundLoadingDataState @@ -1789,22 +1788,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email empty and built in, when user clicks on print receipt button, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - - verify(tracker).trackPrintReceiptTapped() - } - @Test fun `given billing email not empty and external, when user clicks on print receipt button, then event tracked`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 7f8bd110970..d52beede435 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,12 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.PrintingReceiptState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1571,6 +1565,22 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPrintReceiptTapped() } + @Test + fun `given billing email empty and built in, when user clicks on print receipt button, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + + verify(tracker).trackPrintReceiptTapped() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From adcd228fae862d1d08947e839015476335fa4440 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:47:22 +0100 Subject: [PATCH 74/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and external, when user clicks on print receipt button, then event tracked` --- .../cardreader/CardReaderPaymentViewModelTest.kt | 15 --------------- .../controller/CardReaderPaymentControllerTest.kt | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 961fed24a9c..6a1b358a581 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1788,21 +1788,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and external, when user clicks on print receipt button, then event tracked`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - verify(tracker).trackPrintReceiptTapped() - } - @Test fun `given billing email not empty and built in, when user clicks on print receipt button, then event tracked`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d52beede435..bba5334a6e2 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1581,6 +1582,20 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPrintReceiptTapped() } + @Test + fun `given billing email not empty and external, when user clicks on print receipt button, then event tracked`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + verify(tracker).trackPrintReceiptTapped() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 2e98afe558cd0464ab068940d2bcf5f9e88df2e8 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:50:35 +0100 Subject: [PATCH 75/89] Move test from VM to `CardReaderPaymentController`: `given billing email not empty and built in, when user clicks on print receipt button, then event tracked` --- .../CardReaderPaymentViewModelTest.kt | 18 ------------------ .../CardReaderPaymentControllerTest.kt | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 6a1b358a581..904bdcd947e 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1788,24 +1788,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_payment_save_for_later) } - @Test - fun `given billing email not empty and built in, when user clicks on print receipt button, then event tracked`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onPrimaryActionClicked.invoke() - - verify(tracker).trackPrintReceiptTapped() - } - @Test fun `given get receipt url fails, when user clicks on print receipt button, then ShowSnackbar emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index bba5334a6e2..de8b3f57fb7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,7 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1596,6 +1595,23 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPrintReceiptTapped() } + @Test + fun `given billing email not empty and built in, when user clicks on print receipt button, then event tracked`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + + verify(tracker).trackPrintReceiptTapped() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 0529c00d8421b1a0d153f6e0fe3227e5a6908fd4 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:55:32 +0100 Subject: [PATCH 76/89] Add `CardReaderPaymentController` test: `given get receipt url fails, when user clicks on print receipt button, then error event emitted` --- .../CardReaderPaymentControllerTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index de8b3f57fb7..f17161d7141 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1612,6 +1612,26 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPrintReceiptTapped() } + @Test + fun `given get receipt url fails, when user clicks on print receipt button, then error event emitted`() = + testBlocking { + // GIVEN + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.failure(Exception())) + + // WHEN + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + } + + // THEN + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 43c1f96a207eaabaff8374aad8a24f86f1a70619 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 20 Nov 2024 17:58:39 +0100 Subject: [PATCH 77/89] Add `CardReaderPaymentController` test: `given get receipt url succeeds, when user clicks on print receipt button, then PrintReceipt emitted` --- .../CardReaderPaymentControllerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index f17161d7141..fbdfe0823d7 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,8 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -1632,6 +1634,26 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) } + @Test + fun `given get receipt url succeeds, when user clicks on print receipt button, then PrintReceipt emitted`() = + testBlocking { + // GIVEN + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + val receiptUrl = "testUrl" + whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.success(receiptUrl)) + + // WHEN + controller.start() + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + } + // THEN + assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).receiptUrl).isEqualTo(receiptUrl) + assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).documentName).isEqualTo("receipt-order-1") + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 78885384b30a7db790ea3335cf0640850ee520d5 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 11:07:48 +0100 Subject: [PATCH 78/89] Move tests to `CardReaderPaymentController`: `when OS accepts the print request, then print success event tracked` `when OS refuses the print request, then print failed event tracked` `when manually cancels the print request, then print cancelled event tracked` --- .../CardReaderPaymentViewModelTest.kt | 21 -------- .../CardReaderPaymentControllerTest.kt | 49 ++++++++++++++++--- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 904bdcd947e..ab7542bde22 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1826,27 +1826,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat((viewModel.event.value as PrintReceipt).documentName).isEqualTo("receipt-order-1") } - @Test - fun `when OS accepts the print request, then print success event tracked`() = testBlocking { - viewModel.onPrintResult(STARTED) - - verify(tracker).trackPrintReceiptSucceeded() - } - - @Test - fun `when OS refuses the print request, then print failed event tracked`() = testBlocking { - viewModel.onPrintResult(FAILED) - - verify(tracker).trackPrintReceiptFailed() - } - - @Test - fun `when manually cancels the print request, then print cancelled event tracked`() = testBlocking { - viewModel.onPrintResult(CANCELLED) - - verify(tracker).trackPrintReceiptCancelled() - } - @Test fun `given external reader and receipt fetching and sharing success, when user clicks on send receipt button, then PlayChaChing emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index fbdfe0823d7..a8ab0c586b8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,8 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.PrintReceipt -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -63,6 +61,8 @@ import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.CANCELLED +import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED +import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -1450,7 +1450,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.onPrintResult(CANCELLED) - assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) } @Test @@ -1467,7 +1469,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.onPrintResult(CANCELLED) - assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) } @Test @@ -1483,7 +1487,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.onPrintResult(CANCELLED) assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java) + .isInstanceOf( + CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java + ) } @Test @@ -1502,7 +1508,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.onPrintResult(CANCELLED) assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java) + .isInstanceOf( + CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java + ) } @Test @@ -1631,7 +1639,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } // THEN - assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + assertThat( + (events.last() as CardReaderPaymentEvent.ShowErrorMessage).message + ).isEqualTo(R.string.receipt_fetching_error) } @Test @@ -1651,9 +1661,32 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } // THEN assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).receiptUrl).isEqualTo(receiptUrl) - assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).documentName).isEqualTo("receipt-order-1") + assertThat( + (events.last() as CardReaderPaymentEvent.PrintReceiptTapped).documentName + ).isEqualTo("receipt-order-1") } + @Test + fun `when OS accepts the print request, then print success event tracked`() = testBlocking { + controller.onPrintResult(STARTED) + + verify(tracker).trackPrintReceiptSucceeded() + } + + @Test + fun `when OS refuses the print request, then print failed event tracked`() = testBlocking { + controller.onPrintResult(FAILED) + + verify(tracker).trackPrintReceiptFailed() + } + + @Test + fun `when manually cancels the print request, then print cancelled event tracked`() = testBlocking { + controller.onPrintResult(CANCELLED) + + verify(tracker).trackPrintReceiptCancelled() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 84687a57c8f96fd8f20de4cad0a31950575aacc1 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 13:56:33 +0100 Subject: [PATCH 79/89] Clean up code after merge --- .../payment/controller/CardReaderPaymentControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index f655d0ccd41..8c3ab38a8fe 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -105,7 +105,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { private val selectedSite: SelectedSite = mock() private val paymentCollectibilityChecker: CardReaderPaymentCollectibilityChecker = mock() private val tracker: PaymentsFlowTracker = mock() - private val trackCanceledFlow = CardReaderTrackCanceledFlow(tracker) + private val trackCanceledFlow = CardReaderTrackCanceledFlowAction(tracker) private val appPrefs: AppPrefs = mock() private val currencyFormatter: CurrencyFormatter = mock() private val wooStore: WooCommerceStore = mock() From 4722dbdfc9417acd99232953b3aef64f30a005f4 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 14:30:06 +0100 Subject: [PATCH 80/89] Move tests from `CardReaderPaymentViewModelTest` to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 211 +--------------- .../CardReaderPaymentControllerTest.kt | 226 +++++++++++++++++- 2 files changed, 225 insertions(+), 212 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index a8b7b438f88..50de750c72c 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -93,9 +93,6 @@ import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper import com.woocommerce.android.ui.payments.tracking.PaymentsFlowTracker import com.woocommerce.android.util.CurrencyFormatter -import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.CANCELLED -import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED -import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.captureValues import com.woocommerce.android.viewmodel.BaseUnitTest import com.woocommerce.android.viewmodel.MultiLiveEvent.Event @@ -1827,213 +1824,7 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat((viewModel.event.value as PrintReceipt).receiptUrl).isEqualTo(receiptUrl) assertThat((viewModel.event.value as PrintReceipt).documentName).isEqualTo("receipt-order-1") } - - @Test - fun `given external reader and receipt fetching and sharing success, when user clicks on send receipt button, then PlayChaChing emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("url")) } - } - whenever(paymentReceiptShare("test url", 1L)).thenReturn( - PaymentReceiptShare.ReceiptShareResult.Success - ) - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat(viewModel.event.value).isEqualTo(PlayChaChing) - } - - @Test - fun `given built in reader and receipt fetching and sharing success, when user clicks on send receipt button, then PlayChaChing emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat(viewModel.event.value).isEqualTo(PlayChaChing) - } - - @Test - fun `given receipt fetching success and receipt file not created, when user clicks on send receipt button, then ShowSnackbar emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("url")) } - } - whenever(paymentReceiptShare("test url", 1L)).thenReturn( - PaymentReceiptShare.ReceiptShareResult.Error.FileCreation - ) - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat((viewModel.event.value as ShowSnackbar).message).isEqualTo( - R.string.card_reader_payment_receipt_can_not_be_stored - ) - verify(tracker).trackPaymentsReceiptSharingFailed(PaymentReceiptShare.ReceiptShareResult.Error.FileCreation) - } - - @Test - fun `given receipt fetching success and receipt file not downloaded, when user clicks on send receipt button, then ShowSnackbar emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("url")) } - } - whenever(paymentReceiptShare("test url", 1L)).thenReturn( - PaymentReceiptShare.ReceiptShareResult.Error.FileDownload - ) - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat((viewModel.event.value as ShowSnackbar).message).isEqualTo( - R.string.card_reader_payment_receipt_can_not_be_downloaded - ) - verify(tracker).trackPaymentsReceiptSharingFailed(PaymentReceiptShare.ReceiptShareResult.Error.FileDownload) - } - - @Test - fun `given receipt fetching success and receipt file not shared, when user clicks on send receipt button, then ShowSnackbar emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("url")) } - } - val sharing = PaymentReceiptShare.ReceiptShareResult.Error.Sharing(Exception()) - whenever(paymentReceiptShare("test url", 1L)).thenReturn(sharing) - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat((viewModel.event.value as ShowSnackbar).message).isEqualTo( - R.string.card_reader_payment_email_client_not_found - ) - verify(tracker).trackPaymentsReceiptSharingFailed(sharing) - } - - @Test - fun `given external reader and receipt fetching fails, when user clicks on send receipt button, then ShowSnackabar event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.failure(Exception())) - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat((viewModel.event.value as ShowSnackbar).message).isEqualTo(R.string.receipt_fetching_error) - } - - @Test - fun `given built reader and receipt fetching fails, when user clicks on send receipt button, then ShowSnackabar event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.failure(Exception())) - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - assertThat((viewModel.event.value as ShowSnackbar).message).isEqualTo(R.string.receipt_fetching_error) - } - - @Test - fun `given external reader, when user clicks on send receipt button, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - verify(tracker).trackEmailReceiptTapped() - } - - @Test - fun `given built in reader, when user clicks on send receipt button, then event tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onSecondaryActionClicked.invoke() - - verify(tracker).trackEmailReceiptTapped() - } - - @Test - fun `given billing email empty and external, when user clicks on save for later button, then Exit event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onTertiaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given billing email built in and external, when user clicks on save for later button, then Exit event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onTertiaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given billing email not empty and external, when user clicks on save for later button, then Exit event emitted`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onTertiaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given billing email not empty and built in, when user clicks on save for later button, then Exit event emitted`() = - testBlocking { - whenever(mockedAddress.email).thenReturn("nonemptyemail") - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulReceiptSentAutomaticallyState) - .onTertiaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - + // @Test fun `given user presses back button, when re-fetching order, then ReFetchingOrderState shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 8c3ab38a8fe..f4e02c1c183 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,7 +51,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -66,7 +65,6 @@ import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -1709,6 +1707,230 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker).trackPrintReceiptCancelled() } + @Test + fun `given external reader and receipt fetching and sharing success, when user clicks on send receipt button, then PlayChaChing emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("url")) } + } + whenever(paymentReceiptShare("test url", 1L)).thenReturn( + PaymentReceiptShare.ReceiptShareResult.Success + ) + + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) + } + + @Test + fun `given built in reader and receipt fetching and sharing success, when user clicks on send receipt button, then PlayChaChing emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) + } + + @Test + fun `given receipt fetching success and receipt file not created, when user clicks on send receipt button, then ShowSnackbar emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("url")) } + } + whenever(paymentReceiptShare("test url", 1L)).thenReturn( + PaymentReceiptShare.ReceiptShareResult.Error.FileCreation + ) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( + R.string.card_reader_payment_receipt_can_not_be_stored + ) + verify(tracker).trackPaymentsReceiptSharingFailed(PaymentReceiptShare.ReceiptShareResult.Error.FileCreation) + } + + @Test + fun `given receipt fetching success and receipt file not downloaded, when user clicks on send receipt button, then ShowSnackbar emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("url")) } + } + whenever(paymentReceiptShare("test url", 1L)).thenReturn( + PaymentReceiptShare.ReceiptShareResult.Error.FileDownload + ) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( + R.string.card_reader_payment_receipt_can_not_be_downloaded + ) + verify(tracker).trackPaymentsReceiptSharingFailed(PaymentReceiptShare.ReceiptShareResult.Error.FileDownload) + } + + @Test + fun `given receipt fetching success and receipt file not shared, when user clicks on send receipt button, then ShowSnackbar emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("url")) } + } + val sharing = PaymentReceiptShare.ReceiptShareResult.Error.Sharing(Exception()) + whenever(paymentReceiptShare("test url", 1L)).thenReturn(sharing) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( + R.string.card_reader_payment_email_client_not_found + ) + verify(tracker).trackPaymentsReceiptSharingFailed(sharing) + } + + @Test + fun `given external reader and receipt fetching fails, when user clicks on send receipt button, then ShowSnackabar event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.failure(Exception())) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + } + + @Test + fun `given built reader and receipt fetching fails, when user clicks on send receipt button, then ShowSnackabar event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + whenever(paymentReceiptHelper.getReceiptUrl(any())).thenReturn(Result.failure(Exception())) + + createController(BUILT_IN) + controller.start() + + val events = controller.event.runAndCaptureValues { + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + } + + assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + } + + @Test + fun `given external reader, when user clicks on send receipt button, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + + verify(tracker).trackEmailReceiptTapped() + } + + @Test + fun `given built in reader, when user clicks on send receipt button, then event tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(BUILT_IN) + + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + + verify(tracker).trackEmailReceiptTapped() + } + + @Test + fun `given billing email empty and external, when user clicks on save for later button, then Exit event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSaveUserClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given billing email built in and external, when user clicks on save for later button, then Exit event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(BUILT_IN) + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSaveUserClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given billing email not empty and external, when user clicks on save for later button, then Exit event emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically) + .onSaveUserClicked() + } + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given billing email not empty and built in, when user clicks on save for later button, then Exit event emitted`() = + testBlocking { + whenever(mockedAddress.email).thenReturn("nonemptyemail") + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically) + .onSaveUserClicked() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 2a6d9d316f08937619de874392f0da9e1f09e8de Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 14:41:25 +0100 Subject: [PATCH 81/89] Move tests from `CardReaderPaymentViewModelTest` to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 203 ---------------- .../CardReaderPaymentControllerTest.kt | 225 ++++++++++++++++++ 2 files changed, 225 insertions(+), 203 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 50de750c72c..0e236a1ba03 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1835,209 +1835,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(ReFetchingOrderState::class.java) } - @Test - fun `given payment flow is loading, when user presses back button, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(LoadingDataState(mock())) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackPaymentCancelled("Loading") - } - - @Test - fun `given payment flow is collecting state, when user presses back button, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(CollectingPayment) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackPaymentCancelled("Collecting") - } - - @Test - fun `given payment flow is processing state, when user presses back button, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPayment) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackPaymentCancelled("Processing") - } - - @Test - fun `given payment flow is capturing state, when user presses back button, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(CapturingPayment) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackPaymentCancelled("Capturing") - } - - @Test - fun `given payment flow is payment failed, when user presses back button, then cancel event is not tracked`() = - testBlocking { - whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.NoNetwork) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentFailed(NoNetwork, null, "")) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker, never()).trackPaymentCancelled(anyOrNull()) - } - - @Test - fun `given payment flow is success state, when user presses back button, then cancel event is not tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker, never()).trackPaymentCancelled(anyOrNull()) - } - - @Test - fun `given payment flow is initializing payment state, when user presses cancel, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(InitializingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as LoadingDataState).onSecondaryActionClicked.invoke() - - verify(tracker).trackPaymentCancelled("Loading") - } - - @Test - fun `given payment flow is initializing payment state, when user presses cancel, then exit event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(InitializingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as LoadingDataState).onSecondaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given payment flow is collection payment state, when user presses cancel, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(CollectingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderCollectPaymentState).onSecondaryActionClicked.invoke() - - verify(tracker).trackPaymentCancelled("Collecting") - } - - @Test - fun `given payment flow is collection payment state, when user presses cancel, then exit event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(CollectingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderCollectPaymentState).onSecondaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given payment flow is processing payment state, when user presses cancel, then cancel event is tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderProcessingPaymentState).onSecondaryActionClicked.invoke() - - verify(tracker).trackPaymentCancelled("Processing") - } - - @Test - fun `given payment flow is processing payment state, when user presses cancel, then exit event emitted`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(ProcessingPayment) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderProcessingPaymentState).onSecondaryActionClicked.invoke() - - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given payment flow is receipt print state and external, when user presses back button, then cancel event is not tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - viewModel.onBackPressed() - - verify(tracker, never()).trackPaymentCancelled(anyOrNull()) - } - - @Test - fun `given payment flow is receipt print state and built in, when user presses back button, then cancel event is not tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onPrimaryActionClicked.invoke() - viewModel.onBackPressed() - - verify(tracker, never()).trackPaymentCancelled(anyOrNull()) - } - - @Test - fun `given payment flow is refetching order, when user presses back button, then cancel event is not tracked`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - simulateFetchOrderJobState(inProgress = true) - - viewModel.onBackPressed() - - verify(tracker, never()).trackPaymentCancelled(anyOrNull()) - } - @Test fun `given re-fetching order and external, when user clicks on save for later button, then ReFetchingOrderState shown`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index f4e02c1c183..420c5c70345 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -51,6 +51,11 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentO import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderProcessingPaymentState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -65,6 +70,7 @@ import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -80,6 +86,8 @@ import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doSuspendableAnswer import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -1931,6 +1939,223 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } + @Test + fun `given payment flow is loading, when user presses back button, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(LoadingDataState(mock())) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackPaymentCancelled("Loading") + } + + @Test + fun `given payment flow is collecting state, when user presses back button, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackPaymentCancelled("Collecting") + } + + @Test + fun `given payment flow is processing state, when user presses back button, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackPaymentCancelled("Processing") + } + + @Test + fun `given payment flow is capturing state, when user presses back button, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CapturingPayment) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackPaymentCancelled("Capturing") + } + + @Test + fun `given payment flow is payment failed, when user presses back button, then cancel event is not tracked`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.NoNetwork) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(NoNetwork, null, "")) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker, never()).trackPaymentCancelled(anyOrNull()) + } + + @Test + fun `given payment flow is success state, when user presses back button, then cancel event is not tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker, never()).trackPaymentCancelled(anyOrNull()) + } + + @Test + fun `given payment flow is initializing payment state, when user presses cancel, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(InitializingPayment) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.LoadingData).onCancel() + + verify(tracker).trackPaymentCancelled("Loading") + } + + @Test + fun `given payment flow is initializing payment state, when user presses cancel, then exit event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(InitializingPayment) } + } + + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.LoadingData).onCancel() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given payment flow is collection payment state, when user presses cancel, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState).onCancel() + + verify(tracker).trackPaymentCancelled("Collecting") + } + + @Test + fun `given payment flow is collection payment state, when user presses cancel, then exit event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(CollectingPayment) } + } + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState).onCancel() + } + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given payment flow is processing payment state, when user presses cancel, then cancel event is tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment).onCancel() + + verify(tracker).trackPaymentCancelled("Processing") + } + + @Test + fun `given payment flow is processing payment state, when user presses cancel, then exit event emitted`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(ProcessingPayment) } + } + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment).onCancel() + } + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given payment flow is receipt print state and external, when user presses back button, then cancel event is not tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + controller.onBackPressed() + + verify(tracker, never()).trackPaymentCancelled(anyOrNull()) + } + + @Test + fun `given payment flow is receipt print state and built in, when user presses back button, then cancel event is not tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + controller.start() + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + controller.onBackPressed() + + verify(tracker, never()).trackPaymentCancelled(anyOrNull()) + } + + @Test + fun `given payment flow is refetching order, when user presses back button, then cancel event is not tracked`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + simulateFetchOrderJobState(inProgress = true) + + controller.onBackPressed() + + verify(tracker, never()).trackPaymentCancelled(anyOrNull()) + } + + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { + if (inProgress) { + whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { + delay(1000) + mock() + } + } else { + whenever(orderRepository.fetchOrderById(any())).doReturn(mock()) + } + controller.reFetchOrder() + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 21611e341b9938d9771396c10ca2f293ca28c466 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 15:04:59 +0100 Subject: [PATCH 82/89] Move tests from `CardReaderPaymentViewModelTest` to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 40 ------------------ .../CardReaderPaymentControllerTest.kt | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 0e236a1ba03..727dfd193d4 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1825,46 +1825,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat((viewModel.event.value as PrintReceipt).documentName).isEqualTo("receipt-order-1") } // - @Test - fun `given user presses back button, when re-fetching order, then ReFetchingOrderState shown`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - - viewModel.onBackPressed() - - assertThat(viewModel.viewStateData.value).isInstanceOf(ReFetchingOrderState::class.java) - } - - @Test - fun `given re-fetching order and external, when user clicks on save for later button, then ReFetchingOrderState shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - simulateFetchOrderJobState(inProgress = true) - - (viewModel.viewStateData.value as ExternalReaderPaymentSuccessfulState).onTertiaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value).isInstanceOf(ReFetchingOrderState::class.java) - } - - @Test - fun `given re-fetching order and built in, when user clicks on save for later button, then ReFetchingOrderState shown`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel(BUILT_IN) - - viewModel.start() - simulateFetchOrderJobState(inProgress = true) - - (viewModel.viewStateData.value as BuiltInReaderPaymentSuccessfulState).onTertiaryActionClicked.invoke() - - assertThat(viewModel.viewStateData.value).isInstanceOf(ReFetchingOrderState::class.java) - } @Test fun `given user presses back, when already in ReFetchingOrderState, then snackbar shown and screen dismissed`() = diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 420c5c70345..711e977393a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -56,6 +56,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.External import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderProcessingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ReFetchingOrderState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState @@ -2144,6 +2145,47 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(tracker, never()).trackPaymentCancelled(anyOrNull()) } + @Test + fun `given user presses back button, when re-fetching order, then ReFetchingOrderState shown`() = + testBlocking { + simulateFetchOrderJobState(inProgress = true) + + controller.onBackPressed() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) + } + + @Test + fun `given re-fetching order and external, when user clicks on save for later button, then ReFetchingOrderState shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + simulateFetchOrderJobState(inProgress = true) + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSaveUserClicked() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) + } + + @Test + fun `given re-fetching order and built in, when user clicks on save for later button, then ReFetchingOrderState shown`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController(cardReaderType = BUILT_IN) + + controller.start() + simulateFetchOrderJobState(inProgress = true) + + (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSaveUserClicked() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) + } + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { From 20568e881715a82e20c73ae7d5754eb6f68e8ccf Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 18:34:57 +0100 Subject: [PATCH 83/89] Move tests from `CardReaderPaymentViewModelTest` to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 413 ------------------ .../CardReaderPaymentControllerTest.kt | 404 +++++++++++++++++ 2 files changed, 404 insertions(+), 413 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 727dfd193d4..cccdf4b31dd 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1826,187 +1826,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { } // - @Test - fun `given user presses back, when already in ReFetchingOrderState, then snackbar shown and screen dismissed`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - viewModel.onBackPressed() // shows ReFetchingOrderState screen - val events = mutableListOf() - viewModel.event.observeForever { - events.add(it) - } - - viewModel.onBackPressed() - - assertThat(events[0]).isInstanceOf(ShowSnackbar::class.java) - assertThat(events[1]).isEqualTo(Exit) - } - - @Test - fun `given user presses back, when already showing ReFetchingOrderState, then correct snackbar message shown`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - viewModel.onBackPressed() // shows ReFetchingOrderState screen - val events = mutableListOf() - viewModel.event.observeForever { - events.add(it) - } - - viewModel.onBackPressed() - - assertThat((events[0] as ShowSnackbar).message) - .isEqualTo(R.string.card_reader_refetching_order_failed) - } - - @Test - fun `given user presses back button, when re-fetching order, then screen not dismissed`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - - viewModel.onBackPressed() - - assertThat(viewModel.event.value).isNotEqualTo(Exit) - } - - @Test - fun `given user presses back button, when not re-fetching order, then screen dismissed`() = - testBlocking { - simulateFetchOrderJobState(inProgress = false) - - viewModel.onBackPressed() - - assertThat(viewModel.event.value).isEqualTo(Exit) - } - - @Test - fun `given ReFetchingOrderState shown, when re-fetching order completes, then screen auto-dismissed`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - viewModel.onBackPressed() // show ReFetchingOrderState screen - - advanceUntilIdle() - - assertThat(viewModel.event.value).isEqualTo(Exit) - } - - @Test - fun `given built in payment failed state and connected BI, when user presses back, then disconnect from reader invoked`() = - testBlocking { - val cardReader: CardReader = mock { - on { type }.thenReturn("COTS_DEVICE") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, true)) - .thenReturn(PaymentFlowError.NoNetwork) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentFailed(NoNetwork, null, "")) } - } - initViewModel(BUILT_IN) - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager).disconnectReader() - } - - @Test - fun `given payment failed state and connected BT, when user presses back, then disconnect not invoked`() = - testBlocking { - val cardReader: CardReader = mock { - on { type }.thenReturn("STRIPE_M2") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.NoNetwork) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentFailed(NoNetwork, null, "")) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager, never()).disconnectReader() - } - - @Test - fun `given payment processing state and connected BT, when user presses back, then disconnect not invoked`() = - testBlocking { - val cardReader: CardReader = mock { - on { type }.thenReturn("STRIPE_M2") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager, never()).disconnectReader() - } - - @Test - fun `given ReFetchingOrderState not shown, when re-fetching order completes, then screen not auto-dismissed`() = - testBlocking { - simulateFetchOrderJobState(inProgress = true) - - viewModel.reFetchOrder() - - assertThat(viewModel.event.value).isNotEqualTo(Exit) - } - - @Test - fun `when re-fetching order fails, then SnackBar shown`() = - testBlocking { - whenever(orderRepository.fetchOrderById(any())).thenReturn(null) - val events = mutableListOf() - viewModel.event.observeForever { - events.add(it) - } - - viewModel.reFetchOrder() - - assertThat(events[0]).isInstanceOf(ShowSnackbar::class.java) - } - - @Test - fun `given user leaves the screen, when payment fails, then payment canceled`() = - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(paymentFailedWithValidDataForRetry) } - } - viewModel.start() - - viewModel.onCleared() - - verify(cardReaderManager).cancelPayment(any()) - } - - @Test - fun `given user leaves the screen, when payment succeeded on retry, then payment NOT canceled`() = - testBlocking { - whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) - .thenReturn(PaymentFlowError.Generic) - whenever(cardReaderManager.collectPayment(any())) - .thenAnswer { - flow { - emit(paymentFailedWithValidDataForRetry) - emit(PaymentCompleted("")) - } - } - viewModel.start() - - viewModel.onCleared() - - verify(cardReaderManager, never()).cancelPayment(any()) - } - @Test fun `given collect payment NOT shown, when show additional info event received, then event ignored`() = testBlocking { @@ -2036,238 +1855,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.viewStateData.value).isInstanceOf(ExternalReaderProcessingPaymentState::class.java) } - @Test - fun `given reader status is connecting, when payment screen is shown, then make sure NOT to initiate payment`() = - testBlocking { - // Given - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) - - // when - viewModel.start() - - // Then - verify(cardReaderManager, never()).collectPayment(any()) - } - - @Test - fun `given reader status is NOT connected, when payment screen is shown, then make sure NOT to initiate payment`() = - testBlocking { - // Given - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) - - // When - viewModel.start() - - // Then - verify(cardReaderManager, never()).collectPayment(any()) - } - - @Test - fun `given reader status is connected, when payment screen is shown, then proceed to initiate payment`() = - testBlocking { - // Given - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connected(mock()))) - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(any()) - } - - @Test - fun `given reader status is NOT connected, when payment screen is shown, then show error Snackbar`() = - testBlocking { - // Given - val events = mutableListOf() - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) - viewModel.event.observeForever { - events.add(it) - } - - // When - viewModel.start() - - // Then - assertThat(events[0]).isInstanceOf(ShowSnackbar::class.java) - } - - @Test - fun `given reader status is NOT connected, when payment screen is shown, then Snackbar is shown with message`() = - testBlocking { - // Given - val events = mutableListOf() - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) - viewModel.event.observeForever { - events.add(it) - } - - // When - viewModel.start() - - // Then - assertThat((events[0] as ShowSnackbar).message) - .isEqualTo(R.string.card_reader_payment_reader_not_connected) - } - - @Test - fun `given reader status is NOT connected, when payment screen is shown, then exit event is triggered`() = - testBlocking { - // Given - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) - - // When - viewModel.start() - advanceUntilIdle() - - // Then - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `given reader status is connecting, when payment screen is shown, then show error Snackbar`() = - testBlocking { - // Given - val events = mutableListOf() - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) - viewModel.event.observeForever { - events.add(it) - } - - // When - viewModel.start() - - // Then - assertThat(events[0]).isInstanceOf(ShowSnackbar::class.java) - } - - @Test - fun `given reader status is connecting, when payment screen is shown, then Snackbar is shown with the message`() = - testBlocking { - // Given - val events = mutableListOf() - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) - viewModel.event.observeForever { - events.add(it) - } - - // When - viewModel.start() - - // Then - assertThat((events[0] as ShowSnackbar).message) - .isEqualTo(R.string.card_reader_payment_reader_not_connected) - } - - @Test - fun `given reader status is connecting, when payment screen is shown, then exit event is triggered`() = - testBlocking { - // Given - whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) - - // When - viewModel.start() - advanceUntilIdle() - - // Then - assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) - } - - @Test - fun `when flow started, then correct order key is propagated to CardReaderManager`() = - testBlocking { - // Given - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.orderKey).isEqualTo("wc_order_j0LMK3bFhalEL") - } - - @Test - fun `given plugin can not be send, when flow started, then wc pay can send receipt is false`() = - testBlocking { - // Given - whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(false) - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.isPluginCanSendReceipt).isFalse() - } - - @Test - fun `given plugin can be send, when flow started, then wc pay can send receipt is true`() = - testBlocking { - // Given - whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.isPluginCanSendReceipt).isTrue() - } - - @Test - fun `given canada and total 0,58, when flow started, then fee set to 15`() = - testBlocking { - // Given - whenever(wooStore.getStoreCountryCode(any())).thenReturn("CA") - whenever(mockedOrder.total).thenReturn(BigDecimal(0.58)) - whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.feeAmount).isEqualTo(15) - } - - @Test - fun `given canada and total 135,6, when flow started, then fee set to 15`() = - testBlocking { - // Given - whenever(wooStore.getStoreCountryCode(any())).thenReturn("CA") - whenever(mockedOrder.total).thenReturn(BigDecimal(145.6)) - whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.feeAmount).isEqualTo(15) - } - - @Test - fun `given us and total 1,49, when flow started, then fee is not set`() = - testBlocking { - // Given - whenever(wooStore.getStoreCountryCode(any())).thenReturn("US") - whenever(mockedOrder.total).thenReturn(BigDecimal(1.49)) - whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) - val captor = argumentCaptor() - - // When - viewModel.start() - - // Then - verify(cardReaderManager).collectPayment(captor.capture()) - assertThat(captor.firstValue.feeAmount).isNull() - } - //endregion - Payments tests //region - Interac Refund tests diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 711e977393a..2b5c6f15714 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -5,6 +5,7 @@ import com.woocommerce.android.R import com.woocommerce.android.cardreader.CardReaderManager import com.woocommerce.android.cardreader.config.CardReaderConfigForSupportedCountry import com.woocommerce.android.cardreader.config.CardReaderConfigForUSA +import com.woocommerce.android.cardreader.connection.CardReader import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus @@ -38,6 +39,7 @@ import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider +import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -71,7 +73,9 @@ import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit +import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -2186,6 +2190,406 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) } + @Test + fun `given user presses back, when already in ReFetchingOrderState, then snackbar shown and screen dismissed`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = true) + controller.onBackPressed() // shows ReFetchingOrderState screen + controller.onBackPressed() + } + + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.ShowErrorMessage::class.java) + assertThat(events[1]).isEqualTo(CardReaderPaymentEvent.Exit) + } + + @Test + fun `given user presses back, when already showing ReFetchingOrderState, then correct snackbar message shown`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = true) + controller.onBackPressed() // shows ReFetchingOrderState screen + controller.onBackPressed() + } + + assertThat((events[0] as CardReaderPaymentEvent.ShowErrorMessage).message) + .isEqualTo(R.string.card_reader_refetching_order_failed) + } + + @Test + fun `given user presses back button, when re-fetching order, then screen not dismissed`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = true) + controller.onBackPressed() + } + assertThat(events).isEmpty() + } + + @Test + fun `given user presses back button, when not re-fetching order, then screen dismissed`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = false) + controller.onBackPressed() + } + + assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.Exit) + } + + @Test + fun `given ReFetchingOrderState shown, when re-fetching order completes, then screen auto-dismissed`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = true) + controller.onBackPressed() // show ReFetchingOrderState screen + controller.onBackPressed() + } + advanceUntilIdle() + + assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.Exit) + } + + @Test + fun `given built in payment failed state and connected BI, when user presses back, then disconnect from reader invoked`() = + testBlocking { + val cardReader: CardReader = mock { + on { type }.thenReturn("COTS_DEVICE") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, true)) + .thenReturn(PaymentFlowError.NoNetwork) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(NoNetwork, null, "")) } + } + createController(cardReaderType = BUILT_IN) + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager).disconnectReader() + } + + @Test + fun `given payment failed state and connected BT, when user presses back, then disconnect not invoked`() = + testBlocking { + val cardReader: CardReader = mock { + on { type }.thenReturn("STRIPE_M2") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever(errorMapper.mapPaymentErrorToUiError(NoNetwork, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.NoNetwork) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentFailed(NoNetwork, null, "")) } + } + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager, never()).disconnectReader() + } + + @Test + fun `given payment processing state and connected BT, when user presses back, then disconnect not invoked`() = + testBlocking { + val cardReader: CardReader = mock { + on { type }.thenReturn("STRIPE_M2") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager, never()).disconnectReader() + } + + @Test + fun `given ReFetchingOrderState not shown, when re-fetching order completes, then screen not auto-dismissed`() = + testBlocking { + val events = controller.event.runAndCaptureValues { + simulateFetchOrderJobState(inProgress = true) + controller.reFetchOrder() + } + assertThat(events).isEmpty() + } + + @Test + fun `when re-fetching order fails, then SnackBar shown`() = + testBlocking { + whenever(orderRepository.fetchOrderById(any())).thenReturn(null) + + val events = controller.event.runAndCaptureValues { + controller.reFetchOrder() + } + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.ShowErrorMessage::class.java) + } + + @Test + fun `given user leaves the screen, when payment fails, then payment canceled`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(paymentFailedWithValidDataForRetry) } + } + controller.start() + + controller.onCleared() + + verify(cardReaderManager).cancelPayment(any()) + } + + @Test + fun `given user leaves the screen, when payment succeeded on retry, then payment NOT canceled`() = + testBlocking { + whenever(errorMapper.mapPaymentErrorToUiError(Generic, cardReaderConfig, false)) + .thenReturn(PaymentFlowError.Generic) + whenever(cardReaderManager.collectPayment(any())) + .thenAnswer { + flow { + emit(paymentFailedWithValidDataForRetry) + emit(PaymentCompleted("")) + } + } + controller.start() + + controller.onCleared() + + verify(cardReaderManager, never()).cancelPayment(any()) + } + + @Test + fun `given reader status is connecting, when payment screen is shown, then make sure NOT to initiate payment`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) + + // when + controller.start() + + // Then + verify(cardReaderManager, never()).collectPayment(any()) + } + + @Test + fun `given reader status is NOT connected, when payment screen is shown, then make sure NOT to initiate payment`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) + + // When + controller.start() + + // Then + verify(cardReaderManager, never()).collectPayment(any()) + } + + @Test + fun `given reader status is connected, when payment screen is shown, then proceed to initiate payment`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connected(mock()))) + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(any()) + } + + @Test + fun `given reader status is NOT connected, when payment screen is shown, then show error Snackbar`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) + + val events = controller.event.runAndCaptureValues { + // When + controller.start() + } + + // Then + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.ShowErrorMessage::class.java) + } + + @Test + fun `given reader status is NOT connected, when payment screen is shown, then Snackbar is shown with message`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) + val events = controller.event.runAndCaptureValues { + // When + controller.start() + } + + // Then + assertThat((events[0] as CardReaderPaymentEvent.ShowErrorMessage).message) + .isEqualTo(R.string.card_reader_payment_reader_not_connected) + } + + @Test + fun `given reader status is NOT connected, when payment screen is shown, then exit event is triggered`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.NotConnected())) + + // When + val events = controller.event.runAndCaptureValues { + controller.start() + advanceUntilIdle() + } + + // Then + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given reader status is connecting, when payment screen is shown, then show error Snackbar`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) + val events = controller.event.runAndCaptureValues { + // When + controller.start() + } + + // Then + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.ShowErrorMessage::class.java) + } + + @Test + fun `given reader status is connecting, when payment screen is shown, then Snackbar is shown with the message`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) + + val events = controller.event.runAndCaptureValues { + // When + controller.start() + } + + // Then + assertThat((events[0] as ShowErrorMessage).message) + .isEqualTo(R.string.card_reader_payment_reader_not_connected) + } + + @Test + fun `given reader status is connecting, when payment screen is shown, then exit event is triggered`() = + testBlocking { + // Given + whenever(cardReaderManager.readerStatus).thenReturn(MutableStateFlow(CardReaderStatus.Connecting)) + + val events = controller.event.runAndCaptureValues { + // When + controller.start() + } + + // Then + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `when flow started, then correct order key is propagated to CardReaderManager`() = + testBlocking { + // Given + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.orderKey).isEqualTo("wc_order_j0LMK3bFhalEL") + } + + @Test + fun `given plugin can not be send, when flow started, then wc pay can send receipt is false`() = + testBlocking { + // Given + whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(false) + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.isPluginCanSendReceipt).isFalse() + } + + @Test + fun `given plugin can be send, when flow started, then wc pay can send receipt is true`() = + testBlocking { + // Given + whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.isPluginCanSendReceipt).isTrue() + } + + @Test + fun `given canada and total 0,58, when flow started, then fee set to 15`() = + testBlocking { + // Given + whenever(wooStore.getStoreCountryCode(any())).thenReturn("CA") + whenever(mockedOrder.total).thenReturn(BigDecimal(0.58)) + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.feeAmount).isEqualTo(15) + } + + @Test + fun `given canada and total 135,6, when flow started, then fee set to 15`() = + testBlocking { + // Given + whenever(wooStore.getStoreCountryCode(any())).thenReturn("CA") + whenever(mockedOrder.total).thenReturn(BigDecimal(145.6)) + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.feeAmount).isEqualTo(15) + } + + @Test + fun `given us and total 1,49, when flow started, then fee is not set`() = + testBlocking { + // Given + whenever(wooStore.getStoreCountryCode(any())).thenReturn("US") + whenever(mockedOrder.total).thenReturn(BigDecimal(1.49)) + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(mockedOrder) + val captor = argumentCaptor() + + // When + controller.start() + + // Then + verify(cardReaderManager).collectPayment(captor.capture()) + assertThat(captor.firstValue.feeAmount).isNull() + } + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { From 455bd7e0331a726668f0021fe1b0949d1c057897 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 18:44:27 +0100 Subject: [PATCH 84/89] Add `CardReaderPaymentController` test: `given collect payment NOT shown, when show additional info event received, then event ignored` --- .../CardReaderPaymentViewModelTest.kt | 1 - .../CardReaderPaymentControllerTest.kt | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index cccdf4b31dd..027a145d685 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -1824,7 +1824,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat((viewModel.event.value as PrintReceipt).receiptUrl).isEqualTo(receiptUrl) assertThat((viewModel.event.value as PrintReceipt).documentName).isEqualTo("receipt-order-1") } - // @Test fun `given collect payment NOT shown, when show additional info event received, then event ignored`() = diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 2b5c6f15714..ea3aa00e9e3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -12,10 +12,12 @@ import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStat import com.woocommerce.android.cardreader.payments.CardPaymentStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CARD_REMOVED_TOO_EARLY +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CHECK_MOBILE_DEVICE import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.INSERT_OR_SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.MULTIPLE_CONTACTLESS_CARDS_DETECTED import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.REMOVE_CARD +import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.RETRY_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.SWIPE_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_CARD import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.TRY_ANOTHER_READ_METHOD @@ -2590,6 +2592,36 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(captor.firstValue.feeAmount).isNull() } + @Test + fun `given collect payment NOT shown, when show additional info event received, then event ignored`() = + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { + emit(ProcessingPayment) + } + } + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(RETRY_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_OR_SWIPE_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(SWIPE_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(REMOVE_CARD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(MULTIPLE_CONTACTLESS_CARDS_DETECTED)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_READ_METHOD)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(CHECK_MOBILE_DEVICE)) + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(CARD_REMOVED_TOO_EARLY)) + } + } + val events = controller.event.runAndCaptureValues { + controller.start() + } + + assertThat((events)).isEmpty() + assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) + } + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { From 08dd973a31ee30debd267e1f8cca293f1e45a783 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 19:27:57 +0100 Subject: [PATCH 85/89] Move Interac flow tests to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 301 ------ .../CardReaderPaymentControllerTest.kt | 880 +++++++++++++++++- 2 files changed, 871 insertions(+), 310 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index 027a145d685..eebd7529db6 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -35,7 +35,6 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentComp import com.woocommerce.android.cardreader.payments.CardPaymentStatus.PaymentFailed import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPayment import com.woocommerce.android.cardreader.payments.PaymentData -import com.woocommerce.android.cardreader.payments.PaymentInfo import com.woocommerce.android.cardreader.payments.RefundParams import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order @@ -83,7 +82,6 @@ import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.External import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.FailedRefundState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ProcessingRefundState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ReFetchingOrderState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.RefundLoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.RefundSuccessfulState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentStateProvider @@ -110,7 +108,6 @@ import org.junit.Test import org.mockito.ArgumentMatchers.anyFloat import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull -import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.doReturn import org.mockito.kotlin.doSuspendableAnswer @@ -2549,135 +2546,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { .isEqualTo(R.string.card_reader_interac_refund_refund_failed_ok) } - @Test - fun `when interac refund fails, then interac refund failed event is triggered`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { - emit( - CardInteracRefundStatus.InteracRefundFailure( - CardInteracRefundStatus.RefundStatusErrorType.Generic, - "", - RefundParams( - amount = BigDecimal.TEN, - chargeId = "", - currency = "USD" - ) - ) - ) - } - } - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed(any(), any(), any()) - } - - @Test - fun `when interac refund fails, then interac refund failed event is triggered with correct data`() = - testBlocking { - setupViewModelForInteracRefund() - val expectedOrderId = ORDER_ID - val expectedErrorMessage = "Error Message" - val expectedErrorType = CardInteracRefundStatus.RefundStatusErrorType.Cancelled - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { - emit( - CardInteracRefundStatus.InteracRefundFailure( - expectedErrorType, - expectedErrorMessage, - RefundParams( - amount = BigDecimal.TEN, - chargeId = "", - currency = "USD" - ) - ) - ) - } - } - val captor = argumentCaptor() - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed( - captor.first.capture(), - captor.second.capture(), - captor.third.capture(), - ) - assertThat(captor.first.firstValue).isEqualTo(expectedOrderId) - assertThat(captor.second.firstValue).isEqualTo(expectedErrorMessage) - assertThat(captor.third.firstValue).isEqualTo(expectedErrorType) - } - - @Test - fun `given failed to fetch order, when interac refund fails, then interac refund failed event is triggered`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed(any(), any(), any()) - } - - @Test - fun `given failed to fetch order, when interac refund fails, then event is triggered with correct data`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) - val captor = argumentCaptor() - val expectedErrorMessage = "Fetching order failed" - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed(any(), captor.capture(), any()) - assertThat(captor.firstValue).isEqualTo(expectedErrorMessage) - } - - @Test - fun `given null chargeid on order, when interac refund fails, then interac refund failed event is triggered`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(mockedOrder.chargeId).thenReturn(null) - whenever( - interacRefundErrorMapper.mapRefundErrorToUiError( - CardInteracRefundStatus.RefundStatusErrorType.NonRetryable - ) - ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed(any(), any(), any()) - } - - @Test - fun `given null chargeid on order, when interac refund fails, then event is triggered with correct data`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(mockedOrder.chargeId).thenReturn(null) - whenever( - interacRefundErrorMapper.mapRefundErrorToUiError( - CardInteracRefundStatus.RefundStatusErrorType.NonRetryable - ) - ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) - val expectedOrderId = ORDER_ID - val expectedErrorMessage = "Charge id is null for the order." - val expectedErrorType = CardInteracRefundStatus.RefundStatusErrorType.NonRetryable - val captor = argumentCaptor() - - viewModel.start() - - verify(tracker).trackInteracPaymentFailed( - captor.first.capture(), - captor.second.capture(), - captor.third.capture(), - ) - assertThat(captor.first.firstValue).isEqualTo(expectedOrderId) - assertThat(captor.second.firstValue).isEqualTo(expectedErrorMessage) - assertThat(captor.third.firstValue).isEqualTo(expectedErrorType) - } - @Test fun `when interac refund succeeds, then correct labels, illustration and buttons are shown`() = testBlocking { @@ -2700,23 +2568,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewState.hintLabel).describedAs("hintLabel").isNull() } - @Test - fun `given interac refund flow already started, when start() is invoked, then flow is not restarted`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow {} - } - - viewModel.start() - viewModel.start() - viewModel.start() - viewModel.start() - - verify(cardReaderManager, times(1)) - .refundInteracPayment(anyOrNull(), anyOrNull()) - } - @Test fun `given user clicks on retry, when interac refund fails, then refundInteracPayment invoked`() = testBlocking { @@ -2751,157 +2602,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { verify(cardReaderManager, times(2)).refundInteracPayment(any(), any()) } - @Test - fun `given refund flow is loading, when user presses back button, then refund cancel event is tracked`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { emit(CardInteracRefundStatus.InitializingInteracRefund) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackInteracRefundCancelled("Loading") - } - - @Test - fun `given refund flow is collecting, when user presses back button, then refund cancel event is tracked`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackInteracRefundCancelled("Collecting") - } - - @Test - fun `given refund flow is processing, when user presses back button, then refund cancel event is tracked`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { emit(CardInteracRefundStatus.ProcessingInteracRefund) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(tracker).trackInteracRefundCancelled("Processing") - } - - @Test - fun `given refund failed state and connected BI, when user presses back, then disconnect from a reader invoked`() = - testBlocking { - setupViewModelForInteracRefund() - val cardReader: CardReader = mock { - on { type }.thenReturn("COTS_DEVICE") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever( - interacRefundErrorMapper.mapRefundErrorToUiError( - CardInteracRefundStatus.RefundStatusErrorType.Generic - ) - ).thenReturn(InteracRefundFlowError.Generic) - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { - emit( - CardInteracRefundStatus.InteracRefundFailure( - CardInteracRefundStatus.RefundStatusErrorType.Generic, - "", - RefundParams( - amount = BigDecimal.TEN, - chargeId = "", - currency = "CAD" - ) - ) - ) - } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager).disconnectReader() - } - - @Test - fun `given refund failed state and connected BT, when user presses back, then disconnect not invoked`() = - testBlocking { - setupViewModelForInteracRefund() - val cardReader: CardReader = mock { - on { type }.thenReturn("WISEPAD_3") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever( - interacRefundErrorMapper.mapRefundErrorToUiError( - CardInteracRefundStatus.RefundStatusErrorType.Generic - ) - ).thenReturn(InteracRefundFlowError.Generic) - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { - emit( - CardInteracRefundStatus.InteracRefundFailure( - CardInteracRefundStatus.RefundStatusErrorType.Generic, - "", - RefundParams( - amount = BigDecimal.TEN, - chargeId = "", - currency = "CAD" - ) - ) - ) - } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager, never()).disconnectReader() - } - - @Test - fun `given refund failed state and not connected, when user presses back, then disconnect not invoked`() = - testBlocking { - setupViewModelForInteracRefund() - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.NotConnected()) - ) - - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager, never()).disconnectReader() - } - - @Test - fun `given refund success state and connected BT, when user presses back, then disconnect not invoked`() = - testBlocking { - setupViewModelForInteracRefund() - val cardReader: CardReader = mock { - on { type }.thenReturn("WISEPAD_3") - } - whenever(cardReaderManager.readerStatus).thenReturn( - MutableStateFlow(CardReaderStatus.Connected(cardReader)) - ) - whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { - flow { emit(CardInteracRefundStatus.InteracRefundSuccess) } - } - viewModel.start() - - viewModel.onBackPressed() - - verify(cardReaderManager, never()).disconnectReader() - } - @Test fun `given refund failed state, when user clicks on secondary button, then exit event is triggered`() = testBlocking { @@ -2932,7 +2632,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) } - //endregion - Interac Refund tests @Test diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index ea3aa00e9e3..364e1c0318f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -9,6 +9,7 @@ import com.woocommerce.android.cardreader.connection.CardReader import com.woocommerce.android.cardreader.connection.CardReaderStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus +import com.woocommerce.android.cardreader.payments.CardInteracRefundStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType import com.woocommerce.android.cardreader.payments.CardPaymentStatus.AdditionalInfoType.CARD_REMOVED_TOO_EARLY @@ -35,13 +36,13 @@ import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingP import com.woocommerce.android.cardreader.payments.CardPaymentStatus.ProcessingPaymentCompleted import com.woocommerce.android.cardreader.payments.PaymentData import com.woocommerce.android.cardreader.payments.PaymentInfo +import com.woocommerce.android.cardreader.payments.RefundParams import com.woocommerce.android.model.Address import com.woocommerce.android.model.Order import com.woocommerce.android.model.UiString.UiStringText import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.details.OrderDetailRepository import com.woocommerce.android.ui.payments.cardreader.CardReaderCountryConfigProvider -import com.woocommerce.android.ui.payments.cardreader.CardReaderPaymentViewModelTest import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.ORDER import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker @@ -52,17 +53,14 @@ import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracR import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentOrderHelper +import com.woocommerce.android.ui.payments.cardreader.payment.InteracRefundFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderPaymentSuccessfulState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderCollectPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderPaymentSuccessfulState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ExternalReaderProcessingPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState -import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.ReFetchingOrderState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderInteracRefundState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentFailed.* import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper @@ -75,9 +73,6 @@ import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.FAILED import com.woocommerce.android.util.PrintHtmlHelper.PrintJobResult.STARTED import com.woocommerce.android.util.runAndCaptureValues import com.woocommerce.android.viewmodel.BaseUnitTest -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit -import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.delay @@ -2622,6 +2617,843 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) } + // region - Interac refund + @Test + fun `given interac refund shown, when RETRY message received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(RETRY_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_retry_card_prompt) + } + + @Test + fun `given Unknown refund error, when view model starts, then ui has contact support button`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Unknown) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + + controller.start() + + val externalReaderFailedPaymentState = controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure + assertThat(externalReaderFailedPaymentState.cta!!.label).isEqualTo(R.string.support_contact) + assertNotNull(externalReaderFailedPaymentState.onCancel) + } + + @Test + fun `given unknown error, when contact support clicked, then contact support event emited`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Unknown) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + val events = controller.event.runAndCaptureValues { + controller.start() + val externalReaderFailedPaymentState = controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure + externalReaderFailedPaymentState.cta!!.onCallToActionTapped() + } + + assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.ContactSupportTapped) + } + + @Test + fun `given interac refund shown, when INSERT_CARD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) + } + + @Test + fun `given interac refund shown, when INSERT_OR_SWIPE_CARD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(INSERT_OR_SWIPE_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) + } + + @Test + fun `given interac refund shown, when SWIPE_CARD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(SWIPE_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) + } + + @Test + fun `given interac refund shown, when REMOVE_CARD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(REMOVE_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_remove_card_prompt) + } + + @Test + fun `given interac refund, when MULTIPLE_CONTACTLESS_CARDS_DETECTED received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(MULTIPLE_CONTACTLESS_CARDS_DETECTED)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_multiple_contactless_cards_detected_prompt) + } + + @Test + fun `given interac refund shown, when TRY_ANOTHER_READ_METHOD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_READ_METHOD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_try_another_read_method_prompt) + } + + @Test + fun `given interac refund, when TRY_ANOTHER_CARD received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(TRY_ANOTHER_CARD)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_try_another_card_prompt) + } + + @Test + fun `given interac refund, when CHECK_MOBILE_DEVICE received, then refund payment hint updated`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.displayBluetoothCardReaderMessages).thenAnswer { + flow { + emit(BluetoothCardReaderMessages.CardReaderDisplayMessage(CHECK_MOBILE_DEVICE)) + } + } + + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + .isEqualTo(R.string.card_reader_payment_check_mobile_device_prompt) + } + + @Test + fun `given interac refund, when payment screen shown, then loading data state is shown`() { + setupControllerForInteracRefund() + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.LoadingData::class.java) + } + + @Test + fun `when initializing interac refund, then ui updated to initializing refund state `() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InitializingInteracRefund) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.LoadingData::class.java) + } + + @Test + fun `given fetch order failed, when initializing interac refund, then ui updated to proper error state `() = + testBlocking { + setupControllerForInteracRefund() + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardInteracRefundStatus.InteracRefundFailure::class.java) + } + + @Test + fun `when collecting interac refund, then ui updated to collecting refund state`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.CollectingInteracRefund::class.java) + } + + @Test + fun `when processing interac refund, then ui updated to processing refund state`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.ProcessingInteracRefund) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.ProcessingInteracRefund::class.java) + } + + @Test + fun `when interac refund completed, then ui updated to refund successful state`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InteracRefundSuccess) } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundSuccessful::class.java) + } + + @Test + fun `when interac refund fails, then ui updated to refund failed state`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) + } + + @Test + fun `when interac refund fails, then invalidate onboarding cache`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + + controller.start() + + verify(cardReaderOnboardingChecker).invalidateCache() + } + + @Test + fun `given chargeId is null, when interac refund initiated, then proper state is shown`() = + testBlocking { + setupControllerForInteracRefund() + whenever(mockedOrder.chargeId).thenReturn(null) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.NonRetryable + ) + ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) + + controller.start() + + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) + } + + @Test + fun `given non retryable error, when interac refund initiated, then primary action is back press`() = + testBlocking { + setupControllerForInteracRefund() + whenever(mockedOrder.chargeId).thenReturn(null) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.NonRetryable + ) + ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) + val events = controller.event.runAndCaptureValues { + controller.start() + val viewState = controller.paymentState.value + (viewState as CardReaderInteracRefundState.InteracRefundFailure.Cancelable).onCancel() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given refund flow is initializing state, when user presses cancel, then cancel event is tracked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InitializingInteracRefund) } + } + controller.start() + + (controller.paymentState.value as CardReaderInteracRefundState.LoadingData).onCancel() + + verify(tracker).trackInteracRefundCancelled("Loading") + } + + @Test + fun `given refund flow is initializing state, when user presses cancel, then exit event emitted`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InitializingInteracRefund) } + } + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderInteracRefundState.LoadingData).onCancel() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `given refund flow is collection state, when user presses cancel, then cancel event is tracked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + controller.start() + + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).onCancel() + + verify(tracker).trackInteracRefundCancelled("Collecting") + } + + @Test + fun `given refund flow is collection state, when user presses cancel, then exit event emitted`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).onCancel() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + + @Test + fun `when interac refund fails, then interac refund failed event is triggered`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + + controller.start() + + verify(tracker).trackInteracPaymentFailed(any(), any(), any()) + } + + @Test + fun `when interac refund fails, then interac refund failed event is triggered with correct data`() = + testBlocking { + setupControllerForInteracRefund() + val expectedOrderId = ORDER_ID + val expectedErrorMessage = "Error Message" + val expectedErrorType = CardInteracRefundStatus.RefundStatusErrorType.Cancelled + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + expectedErrorType, + expectedErrorMessage, + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "USD" + ) + ) + ) + } + } + val captor = argumentCaptor() + + controller.start() + + verify(tracker).trackInteracPaymentFailed( + captor.first.capture(), + captor.second.capture(), + captor.third.capture(), + ) + assertThat(captor.first.firstValue).isEqualTo(expectedOrderId) + assertThat(captor.second.firstValue).isEqualTo(expectedErrorMessage) + assertThat(captor.third.firstValue).isEqualTo(expectedErrorType) + } + + @Test + fun `given failed to fetch order, when interac refund fails, then interac refund failed event is triggered`() = + testBlocking { + setupControllerForInteracRefund() + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + + controller.start() + + verify(tracker).trackInteracPaymentFailed(any(), any(), any()) + } + + @Test + fun `given failed to fetch order, when interac refund fails, then event is triggered with correct data`() = + testBlocking { + setupControllerForInteracRefund() + whenever(orderRepository.fetchOrderById(ORDER_ID)).thenReturn(null) + val captor = argumentCaptor() + val expectedErrorMessage = "Fetching order failed" + + controller.start() + + verify(tracker).trackInteracPaymentFailed(any(), captor.capture(), any()) + assertThat(captor.firstValue).isEqualTo(expectedErrorMessage) + } + + @Test + fun `given null chargeid on order, when interac refund fails, then interac refund failed event is triggered`() = + testBlocking { + setupControllerForInteracRefund() + whenever(mockedOrder.chargeId).thenReturn(null) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.NonRetryable + ) + ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) + + controller.start() + + verify(tracker).trackInteracPaymentFailed(any(), any(), any()) + } + + @Test + fun `given null chargeid on order, when interac refund fails, then event is triggered with correct data`() = + testBlocking { + setupControllerForInteracRefund() + whenever(mockedOrder.chargeId).thenReturn(null) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.NonRetryable + ) + ).thenReturn(InteracRefundFlowError.NonRetryableGeneric) + val expectedOrderId = ORDER_ID + val expectedErrorMessage = "Charge id is null for the order." + val expectedErrorType = CardInteracRefundStatus.RefundStatusErrorType.NonRetryable + val captor = argumentCaptor() + + controller.start() + + verify(tracker).trackInteracPaymentFailed( + captor.first.capture(), + captor.second.capture(), + captor.third.capture(), + ) + assertThat(captor.first.firstValue).isEqualTo(expectedOrderId) + assertThat(captor.second.firstValue).isEqualTo(expectedErrorMessage) + assertThat(captor.third.firstValue).isEqualTo(expectedErrorType) + } + + @Test + fun `given interac refund flow already started, when start() is invoked, then flow is not restarted`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow {} + } + + controller.start() + controller.start() + controller.start() + controller.start() + + verify(cardReaderManager, times(1)) + .refundInteracPayment(anyOrNull(), anyOrNull()) + } + + @Test + fun `given user clicks on retry, when interac refund fails, then refundInteracPayment invoked`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "CAD" + ) + ) + ) + } + } + controller.start() + + (controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure).onRetry!!() + advanceUntilIdle() + + // Times 2 because, refundInteracPayment() method gets called when refund is initiated + // as well as when the refund is retried. + verify(cardReaderManager, times(2)).refundInteracPayment(any(), any()) + } + + @Test + fun `given refund flow is loading, when user presses back button, then refund cancel event is tracked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InitializingInteracRefund) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackInteracRefundCancelled("Loading") + } + + @Test + fun `given refund flow is collecting, when user presses back button, then refund cancel event is tracked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.CollectingInteracRefund) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackInteracRefundCancelled("Collecting") + } + + @Test + fun `given refund flow is processing, when user presses back button, then refund cancel event is tracked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.ProcessingInteracRefund) } + } + controller.start() + + controller.onBackPressed() + + verify(tracker).trackInteracRefundCancelled("Processing") + } + + @Test + fun `given refund failed state and connected BI, when user presses back, then disconnect from a reader invoked`() = + testBlocking { + setupControllerForInteracRefund() + val cardReader: CardReader = mock { + on { type }.thenReturn("COTS_DEVICE") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "CAD" + ) + ) + ) + } + } + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager).disconnectReader() + } + + @Test + fun `given refund failed state and connected BT, when user presses back, then disconnect not invoked`() = + testBlocking { + setupControllerForInteracRefund() + val cardReader: CardReader = mock { + on { type }.thenReturn("WISEPAD_3") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "CAD" + ) + ) + ) + } + } + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager, never()).disconnectReader() + } + + @Test + fun `given refund failed state and not connected, when user presses back, then disconnect not invoked`() = + testBlocking { + setupControllerForInteracRefund() + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.NotConnected()) + ) + + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager, never()).disconnectReader() + } + + @Test + fun `given refund success state and connected BT, when user presses back, then disconnect not invoked`() = + testBlocking { + setupControllerForInteracRefund() + val cardReader: CardReader = mock { + on { type }.thenReturn("WISEPAD_3") + } + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { emit(CardInteracRefundStatus.InteracRefundSuccess) } + } + controller.start() + + controller.onBackPressed() + + verify(cardReaderManager, never()).disconnectReader() + } + + @Test + fun `given refund failed state, when user clicks on secondary button, then exit event is triggered`() = + testBlocking { + setupControllerForInteracRefund() + whenever( + interacRefundErrorMapper.mapRefundErrorToUiError( + CardInteracRefundStatus.RefundStatusErrorType.Generic + ) + ).thenReturn(InteracRefundFlowError.Generic) + whenever(cardReaderManager.refundInteracPayment(any(), any())).thenAnswer { + flow { + emit( + CardInteracRefundStatus.InteracRefundFailure( + CardInteracRefundStatus.RefundStatusErrorType.Generic, + "", + RefundParams( + amount = BigDecimal.TEN, + chargeId = "", + currency = "CAD" + ) + ) + ) + } + } + + val events = controller.event.runAndCaptureValues { + controller.start() + (controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure.Cancelable).onCancel() + } + + assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + // endregion - Interac refund + + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { @@ -2634,6 +3466,36 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.reFetchOrder() } + private fun setupControllerForInteracRefund() { + val param = CardReaderFlowParam.PaymentOrRefund.Refund(ORDER_ID, refundAmount = BigDecimal(10.72)) + controller = CardReaderPaymentController( + scope = TestScope(coroutinesTestRule.testDispatcher), + cardReaderManager = cardReaderManager, + orderRepository = orderRepository, + selectedSite = selectedSite, + appPrefs = appPrefs, + paymentCollectibilityChecker = paymentCollectibilityChecker, + interacRefundableChecker = interacRefundableChecker, + tracker = tracker, + trackCancelledFlow = trackCanceledFlow, + currencyFormatter = currencyFormatter, + errorMapper = errorMapper, + interacRefundErrorMapper = interacRefundErrorMapper, + wooStore = wooStore, + dispatchers = coroutinesTestRule.testDispatchers, + cardReaderTrackingInfoKeeper = cardReaderTrackingInfoKeeper, + paymentStateProvider = paymentStateProvider, + cardReaderPaymentOrderHelper = cardReaderPaymentOrderHelper, + paymentReceiptHelper = paymentReceiptHelper, + cardReaderOnboardingChecker = cardReaderOnboardingChecker, + cardReaderConfigProvider = cardReaderConfigProvider, + paymentReceiptShare = paymentReceiptShare, + paymentOrRefund = param, + cardReaderType = CardReaderType.EXTERNAL, + isTTPPaymentInProgress = isTTPinProgressProp, + ) + } + companion object { private const val ORDER_ID = 1L private val siteModel = SiteModel().apply { name = "testName" }.apply { url = "testUrl.com" } From 3cce3d10f30e93c383e2fc829b129b42b7adf789 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 19:29:22 +0100 Subject: [PATCH 86/89] Move tests to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 35 ----------------- .../CardReaderPaymentControllerTest.kt | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index eebd7529db6..a071f2c8a90 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -2633,41 +2633,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) } //endregion - Interac Refund tests - - @Test - fun `when new battery status event is received, then tracking is updated with new battery level`() = - testBlocking { - val batteryLevel1 = .5F - val batteryLevel2 = .45F - whenever(cardReaderManager.batteryStatus).thenAnswer { - flow { - emit(CardReaderBatteryStatus.StatusChanged(batteryLevel1, BatteryStatus.NOMINAL, false)) - emit(CardReaderBatteryStatus.StatusChanged(batteryLevel2, BatteryStatus.NOMINAL, false)) - } - } - - viewModel.start() - - val inOrder = inOrder(cardReaderTrackingInfoKeeper) - inOrder.verify(cardReaderTrackingInfoKeeper).setCardReaderBatteryLevel(batteryLevel1) - inOrder.verify(cardReaderTrackingInfoKeeper).setCardReaderBatteryLevel(batteryLevel2) - } - - @Test - fun `when new battery status event is received, then tracking is not updated if the battery level didn't change`() = - testBlocking { - whenever(cardReaderManager.batteryStatus).thenAnswer { - flow { - emit(CardReaderBatteryStatus.Unknown) - emit(CardReaderBatteryStatus.Warning) - } - } - - viewModel.start() - - verify(cardReaderTrackingInfoKeeper, never()).setCardReaderBatteryLevel(anyFloat()) - } - @Test fun `given ttp in progress and reader connected, when vm starts, then AppKilledWhileInBackground state emitted`() = testBlocking { diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 364e1c0318f..d8f941dd096 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -7,6 +7,7 @@ import com.woocommerce.android.cardreader.config.CardReaderConfigForSupportedCou import com.woocommerce.android.cardreader.config.CardReaderConfigForUSA import com.woocommerce.android.cardreader.connection.CardReader import com.woocommerce.android.cardreader.connection.CardReaderStatus +import com.woocommerce.android.cardreader.connection.event.BatteryStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus import com.woocommerce.android.cardreader.payments.CardInteracRefundStatus @@ -84,6 +85,7 @@ import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test +import org.mockito.ArgumentMatchers.anyFloat import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor @@ -91,6 +93,7 @@ import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.doReturn import org.mockito.kotlin.doSuspendableAnswer import org.mockito.kotlin.eq +import org.mockito.kotlin.inOrder import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times @@ -3453,6 +3456,41 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } // endregion - Interac refund + @Test + fun `when new battery status event is received, then tracking is updated with new battery level`() = + testBlocking { + val batteryLevel1 = .5F + val batteryLevel2 = .45F + whenever(cardReaderManager.batteryStatus).thenAnswer { + flow { + emit(CardReaderBatteryStatus.StatusChanged(batteryLevel1, BatteryStatus.NOMINAL, false)) + emit(CardReaderBatteryStatus.StatusChanged(batteryLevel2, BatteryStatus.NOMINAL, false)) + } + } + + controller.start() + + val inOrder = inOrder(cardReaderTrackingInfoKeeper) + inOrder.verify(cardReaderTrackingInfoKeeper).setCardReaderBatteryLevel(batteryLevel1) + inOrder.verify(cardReaderTrackingInfoKeeper).setCardReaderBatteryLevel(batteryLevel2) + } + + @Test + fun `when new battery status event is received, then tracking is not updated if the battery level didn't change`() = + testBlocking { + whenever(cardReaderManager.batteryStatus).thenAnswer { + flow { + emit(CardReaderBatteryStatus.Unknown) + emit(CardReaderBatteryStatus.Warning) + } + } + + controller.start() + + verify(cardReaderTrackingInfoKeeper, never()).setCardReaderBatteryLevel(anyFloat()) + } + + private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { From 8648d46dbc7fa1efa2c70e08317dd85fa415566d Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 19:50:15 +0100 Subject: [PATCH 87/89] Move tests to `CardReaderPaymentController` --- .../CardReaderPaymentViewModelTest.kt | 44 --------- .../CardReaderPaymentControllerTest.kt | 89 +++++++++++++++++-- 2 files changed, 83 insertions(+), 50 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index a071f2c8a90..f81428ecf20 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -8,7 +8,6 @@ import com.woocommerce.android.cardreader.config.CardReaderConfigForSupportedCou import com.woocommerce.android.cardreader.config.CardReaderConfigForUSA import com.woocommerce.android.cardreader.connection.CardReader import com.woocommerce.android.cardreader.connection.CardReaderStatus -import com.woocommerce.android.cardreader.connection.event.BatteryStatus import com.woocommerce.android.cardreader.connection.event.BluetoothCardReaderMessages import com.woocommerce.android.cardreader.connection.event.CardReaderBatteryStatus import com.woocommerce.android.cardreader.payments.CardInteracRefundStatus @@ -105,14 +104,10 @@ import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test -import org.mockito.ArgumentMatchers.anyFloat import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.clearInvocations -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.doSuspendableAnswer import org.mockito.kotlin.eq -import org.mockito.kotlin.inOrder import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times @@ -246,7 +241,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { flow {} } whenever(paymentReceiptHelper.isPluginCanSendReceipt(siteModel)).thenReturn(true) - whenever(paymentReceiptHelper.getReceiptUrl(ORDER_ID)).thenReturn(Result.success("test url")) whenever(cardReaderPaymentOrderHelper.getPaymentDescription(mockedOrder)).thenReturn("test description") whenever(cardReaderPaymentOrderHelper.getAmountLabel(mockedOrder)) .thenReturn("$DUMMY_CURRENCY_SYMBOL$DUMMY_TOTAL") @@ -2709,44 +2703,6 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { } } - @Test - fun `given point of sale, when payment captured, then should exit`() { - testBlocking { - whenever(cardReaderManager.collectPayment(any())).thenAnswer { - flow { emit(PaymentCompleted("")) } - } - - initViewModel( - readerType = EXTERNAL, - cardReaderFlowParam = CardReaderFlowParam.PaymentOrRefund.Payment( - orderId = ORDER_ID, - paymentType = CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS - ) - ) - - val events = mutableListOf() - viewModel.event.observeForever { - events.add(it) - } - - viewModel.start() - - assertThat(events[0]).isInstanceOf(Exit::class.java) - } - } - - private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { - if (inProgress) { - whenever(orderRepository.fetchOrderById(any())).doSuspendableAnswer { - delay(1000) - mock() - } - } else { - whenever(orderRepository.fetchOrderById(any())).doReturn(mock()) - } - viewModel.reFetchOrder() - } - private fun setupViewModelForInteracRefund() { viewModel = CardReaderPaymentViewModel( interacRefundSavedState, diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index d8f941dd096..8bb7eb6a99f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -49,6 +49,7 @@ import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderFlowP import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderOnboardingChecker import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.BUILT_IN +import com.woocommerce.android.ui.payments.cardreader.onboarding.CardReaderType.EXTERNAL import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundErrorMapper import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderInteracRefundableChecker import com.woocommerce.android.ui.payments.cardreader.payment.CardReaderPaymentCollectibilityChecker @@ -58,6 +59,7 @@ import com.woocommerce.android.ui.payments.cardreader.payment.InteracRefundFlowE import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.AmountTooSmall import com.woocommerce.android.ui.payments.cardreader.payment.PaymentFlowError.Unknown +import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.BuiltInReaderFailedPaymentState import com.woocommerce.android.ui.payments.cardreader.payment.ViewState.LoadingDataState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.PlaySuccessfulPaymentSound import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage @@ -142,9 +144,6 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { private val cardReaderConfig: CardReaderConfigForSupportedCountry = CardReaderConfigForUSA private val paymentFailedWithEmptyDataForRetry = PaymentFailed(Generic, null, "dummy msg") private val paymentFailedWithValidDataForRetry = PaymentFailed(Generic, mock(), "dummy msg") - private val paymentFailedWithNoNetwork = PaymentFailed(NoNetwork, mock(), "dummy msg") - private val paymentFailedWithPaymentDeclined = PaymentFailed(DeclinedByBackendError.Unknown, mock(), "dummy msg") - private val paymentFailedWithCardReadTimeOut = PaymentFailed(Generic, mock(), "dummy msg") private val paymentFailedWithServerError = PaymentFailed(Server(""), mock(), "dummy msg") private val paymentFailedWithAmountTooSmall = PaymentFailed( DeclinedByBackendError.AmountTooSmall, @@ -205,7 +204,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } @OptIn(ExperimentalCoroutinesApi::class) - private fun createController(cardReaderType: CardReaderType = CardReaderType.EXTERNAL) { + private fun createController( + cardReaderType: CardReaderType = CardReaderType.EXTERNAL, + cardReaderFlowParam: CardReaderFlowParam.PaymentOrRefund = paymentParam, + ) { controller = CardReaderPaymentController( scope = TestScope(coroutinesTestRule.testDispatcher), cardReaderManager = cardReaderManager, @@ -228,7 +230,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { cardReaderOnboardingChecker = cardReaderOnboardingChecker, cardReaderConfigProvider = cardReaderConfigProvider, paymentReceiptShare = paymentReceiptShare, - paymentOrRefund = paymentParam, + paymentOrRefund = cardReaderFlowParam, cardReaderType = cardReaderType, isTTPPaymentInProgress = isTTPinProgressProp, ) @@ -2896,7 +2898,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardInteracRefundStatus.InteracRefundFailure::class.java) + assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) } @Test @@ -3490,7 +3492,82 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { verify(cardReaderTrackingInfoKeeper, never()).setCardReaderBatteryLevel(anyFloat()) } + @Test + fun `given ttp not in progress and reader connected, when vm starts, then AppKilledWhileInBackground state not emitted`() = + testBlocking { + val cardReader: CardReader = mock() + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + isTTPinProgress = false + createController(BUILT_IN) + + controller.start() + + verify(tracker, never()).trackPaymentFailed("VM killed when TTP activity in foreground") + assertThat(controller.paymentState.value).isNotInstanceOf(BuiltInReaderFailedPaymentState::class.java) + } + @Test + fun `given AppKilledWhileInBackground, when vm starts, then payment collection doesnt start`() = + testBlocking { + val cardReader: CardReader = mock() + whenever(cardReaderManager.readerStatus).thenReturn( + MutableStateFlow(CardReaderStatus.Connected(cardReader)) + ) + isTTPinProgress = true + createController(cardReaderType = BUILT_IN,) + + controller.start() + + verify(cardReaderManager, never()).collectPayment(any()) + } + + @Test + fun `given point of sale, when payment captured, then should not show success state`() { + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController( + cardReaderType = EXTERNAL, + cardReaderFlowParam = CardReaderFlowParam.PaymentOrRefund.Payment( + orderId = ORDER_ID, + paymentType = CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + ) + ) + + controller.start() + + assertThat(controller.paymentState.value).isNotInstanceOf( + CardReaderPaymentState.PaymentSuccessful::class.java, + ) + } + } + + @Test + fun `given point of sale, when payment captured, then should exit`() { + testBlocking { + whenever(cardReaderManager.collectPayment(any())).thenAnswer { + flow { emit(PaymentCompleted("")) } + } + + createController( + cardReaderType = EXTERNAL, + cardReaderFlowParam = CardReaderFlowParam.PaymentOrRefund.Payment( + orderId = ORDER_ID, + paymentType = CardReaderFlowParam.PaymentOrRefund.Payment.PaymentType.WOO_POS + ) + ) + + val events = controller.event.runAndCaptureValues { + controller.start() + } + + assertThat(events[0]).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + } + } private suspend fun simulateFetchOrderJobState(inProgress: Boolean) { if (inProgress) { From 93c337e16d2d7b789ce7c33882a01188cccb6aad Mon Sep 17 00:00:00 2001 From: samiuelson Date: Mon, 25 Nov 2024 20:35:59 +0100 Subject: [PATCH 88/89] Satisfy detekt's complaints --- .../CardReaderPaymentViewModelTest.kt | 1 + .../CardReaderPaymentControllerTest.kt | 311 +++++++++++++----- 2 files changed, 232 insertions(+), 80 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt index f81428ecf20..1bdb2a484f0 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/CardReaderPaymentViewModelTest.kt @@ -2626,6 +2626,7 @@ class CardReaderPaymentViewModelTest : BaseUnitTest() { assertThat(viewModel.event.value).isInstanceOf(Exit::class.java) } + //endregion - Interac Refund tests @Test fun `given ttp in progress and reader connected, when vm starts, then AppKilledWhileInBackground state emitted`() = diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 8bb7eb6a99f..071ac2a010d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -65,7 +65,9 @@ import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardRea import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentEvent.ShowErrorMessage import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderInteracRefundState import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState -import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentFailed.* +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentFailed.BuiltInReaderFailedPayment +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment +import com.woocommerce.android.ui.payments.cardreader.payment.controller.CardReaderPaymentOrRefundState.CardReaderPaymentState.PaymentSuccessful import com.woocommerce.android.ui.payments.receipt.PaymentReceiptHelper import com.woocommerce.android.ui.payments.receipt.PaymentReceiptShare import com.woocommerce.android.ui.payments.tracking.CardReaderTrackingInfoKeeper @@ -701,7 +703,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) + .isInstanceOf(PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) } @Test @@ -715,7 +717,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value) - .isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) + .isInstanceOf(PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) } @Test @@ -729,7 +731,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value).isInstanceOf( - CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java ) } @@ -745,7 +747,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value).isInstanceOf( - CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java ) } @@ -1269,7 +1271,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - val paymentState = controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + val paymentState = + controller.paymentState.value as + CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState assertNotNull(paymentState.onCancel) } @@ -1282,7 +1286,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - val paymentState = controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + val paymentState = controller.paymentState.value as + CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment assertNotNull(paymentState.onCancel) } @@ -1296,7 +1301,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - val paymentState = controller.paymentState.value as CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment + val paymentState = controller.paymentState.value as + CardReaderPaymentState.PaymentFailed.ExternalReaderFailedPayment assertNotNull(paymentState.onCancel) } @@ -1339,7 +1345,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1356,7 +1365,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1372,7 +1384,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1389,7 +1404,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } @@ -1402,7 +1420,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + (controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() assertThat(controller.paymentState.value) .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) @@ -1417,7 +1435,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + (controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() assertThat(controller.paymentState.value) .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) @@ -1432,7 +1450,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() assertThat(controller.paymentState.value) .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) @@ -1448,7 +1469,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() assertThat(controller.paymentState.value) .isInstanceOf(CardReaderPaymentState.PrintingReceipt::class.java) @@ -1461,13 +1485,16 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { flow { emit(PaymentCompleted("")) } } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() controller.onPrintResult(CANCELLED) assertThat( controller.paymentState.value - ).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) + ).isInstanceOf(PaymentSuccessful.ExternalReaderPaymentSuccessful::class.java) } @Test @@ -1480,13 +1507,13 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(BUILT_IN) controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + (controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() controller.onPrintResult(CANCELLED) assertThat( controller.paymentState.value - ).isInstanceOf(CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) + ).isInstanceOf(PaymentSuccessful.BuiltInReaderPaymentSuccessful::class.java) } @Test @@ -1497,13 +1524,16 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { flow { emit(PaymentCompleted("")) } } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() controller.onPrintResult(CANCELLED) assertThat(controller.paymentState.value) .isInstanceOf( - CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically::class.java ) } @@ -1518,13 +1548,16 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() controller.onPrintResult(CANCELLED) assertThat(controller.paymentState.value) .isInstanceOf( - CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically::class.java ) } @@ -1536,7 +1569,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() } controller.onViewCreated() @@ -1554,7 +1590,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onPrintReceiptClicked() } controller.onViewCreated() @@ -1585,7 +1624,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1601,7 +1643,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1615,7 +1660,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1632,7 +1680,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + ).onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1650,18 +1701,21 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() } // THEN assertThat( - (events[events.size-2] as CardReaderPaymentEvent.ShowErrorMessage).message + (events[events.size - 2] as CardReaderPaymentEvent.ShowErrorMessage).message ).isEqualTo(R.string.receipt_fetching_error) assertThat( - (events[events.size-1])).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) + (events[events.size - 1]) + ).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } - @Test fun `given fetching receipt URL fails, when startPrintingFlow, then payment flow is canceled`() = testBlocking { val errorMessage = "Receipt fetching error" @@ -1671,10 +1725,12 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() } - verify(tracker).trackReceiptUrlFetchingFails(errorDescription = errorMessage) assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -1692,7 +1748,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { // WHEN controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onPrintReceiptClicked() } // THEN assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).receiptUrl).isEqualTo(receiptUrl) @@ -1734,7 +1793,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() } assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) @@ -1751,7 +1813,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onSendReceiptClicked() } assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) @@ -1769,7 +1834,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1790,7 +1858,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1810,7 +1881,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1829,10 +1903,15 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() } - assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + assertThat( + (events.last() as CardReaderPaymentEvent.ShowErrorMessage).message + ).isEqualTo(R.string.receipt_fetching_error) } @Test @@ -1847,10 +1926,15 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onSendReceiptClicked() } - assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo(R.string.receipt_fetching_error) + assertThat( + (events.last() as CardReaderPaymentEvent.ShowErrorMessage).message + ).isEqualTo(R.string.receipt_fetching_error) } @Test @@ -1861,7 +1945,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSendReceiptClicked() verify(tracker).trackEmailReceiptTapped() } @@ -1877,7 +1964,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSendReceiptClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onSendReceiptClicked() verify(tracker).trackEmailReceiptTapped() } @@ -1890,7 +1980,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSaveUserClicked() + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + ).onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -1906,7 +1999,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(BUILT_IN) val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSaveUserClicked() + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessful + ).onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -1922,7 +2018,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically) + ( + controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + ) .onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -1939,7 +2038,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically) + ( + controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + ) .onSaveUserClicked() } @@ -2062,7 +2164,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState).onCancel() + ( + controller.paymentState.value as + CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + ).onCancel() verify(tracker).trackPaymentCancelled("Collecting") } @@ -2075,7 +2180,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState).onCancel() + ( + controller.paymentState.value as + CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + ).onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -2088,7 +2196,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment).onCancel() + ( + controller.paymentState.value as + CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + ).onCancel() verify(tracker).trackPaymentCancelled("Processing") } @@ -2101,7 +2212,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment).onCancel() + ( + controller.paymentState.value as + CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + ).onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -2114,7 +2228,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() + (controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful).onPrintReceiptClicked() controller.onBackPressed() verify(tracker, never()).trackPaymentCancelled(anyOrNull()) @@ -2131,7 +2245,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() + (controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful).onPrintReceiptClicked() controller.onBackPressed() verify(tracker, never()).trackPaymentCancelled(anyOrNull()) @@ -2170,7 +2284,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() simulateFetchOrderJobState(inProgress = true) - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.ExternalReaderPaymentSuccessful).onSaveUserClicked() + (controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful).onSaveUserClicked() assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) } @@ -2187,7 +2301,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() simulateFetchOrderJobState(inProgress = true) - (controller.paymentState.value as CardReaderPaymentState.PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSaveUserClicked() + (controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful).onSaveUserClicked() assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ReFetchingOrder::class.java) } @@ -2619,7 +2733,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } assertThat((events)).isEmpty() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment::class.java) } // region - Interac refund @@ -2639,7 +2755,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_retry_card_prompt) } @@ -2670,7 +2788,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - val externalReaderFailedPaymentState = controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure + val externalReaderFailedPaymentState = controller.paymentState.value as + CardReaderInteracRefundState.InteracRefundFailure assertThat(externalReaderFailedPaymentState.cta!!.label).isEqualTo(R.string.support_contact) assertNotNull(externalReaderFailedPaymentState.onCancel) } @@ -2701,7 +2820,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - val externalReaderFailedPaymentState = controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure + val externalReaderFailedPaymentState = controller.paymentState.value as + CardReaderInteracRefundState.InteracRefundFailure externalReaderFailedPaymentState.cta!!.onCallToActionTapped() } @@ -2724,7 +2844,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) } @@ -2744,7 +2866,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) } @@ -2764,7 +2888,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_interac_refund_refund_payment_hint) } @@ -2784,7 +2910,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_remove_card_prompt) } @@ -2804,7 +2932,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_multiple_contactless_cards_detected_prompt) } @@ -2824,7 +2954,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_try_another_read_method_prompt) } @@ -2844,7 +2976,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_try_another_card_prompt) } @@ -2864,7 +2998,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat((controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint) + assertThat( + (controller.paymentState.value as CardReaderInteracRefundState.CollectingInteracRefund).cardReaderHint + ) .isEqualTo(R.string.card_reader_payment_check_mobile_device_prompt) } @@ -2898,7 +3034,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) } @Test @@ -2911,7 +3049,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.CollectingInteracRefund::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.CollectingInteracRefund::class.java) } @Test @@ -2924,7 +3064,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.ProcessingInteracRefund::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.ProcessingInteracRefund::class.java) } @Test @@ -2937,7 +3079,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundSuccessful::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.InteracRefundSuccessful::class.java) } @Test @@ -2967,7 +3111,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) } @Test @@ -3013,7 +3159,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - assertThat(controller.paymentState.value).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) + assertThat( + controller.paymentState.value + ).isInstanceOf(CardReaderInteracRefundState.InteracRefundFailure::class.java) } @Test @@ -3451,7 +3599,10 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - (controller.paymentState.value as CardReaderInteracRefundState.InteracRefundFailure.Cancelable).onCancel() + ( + controller.paymentState.value as + CardReaderInteracRefundState.InteracRefundFailure.Cancelable + ).onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -3541,7 +3692,7 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() assertThat(controller.paymentState.value).isNotInstanceOf( - CardReaderPaymentState.PaymentSuccessful::class.java, + PaymentSuccessful::class.java, ) } } From e9cd84dae5f3ddcfc4aeceb5ef538c631e049b23 Mon Sep 17 00:00:00 2001 From: samiuelson Date: Wed, 27 Nov 2024 13:50:26 +0100 Subject: [PATCH 89/89] Improve formatting --- .../CardReaderPaymentControllerTest.kt | 182 +++++++----------- 1 file changed, 68 insertions(+), 114 deletions(-) diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt index 071ac2a010d..7e5b5345ac8 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/payments/cardreader/payment/controller/CardReaderPaymentControllerTest.kt @@ -1345,10 +1345,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1365,10 +1363,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1384,10 +1380,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically - ).onPrintReceiptClicked() + val state = controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + state.onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) @@ -1404,10 +1399,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically - ).onPrintReceiptClicked() + val state = controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + state.onPrintReceiptClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.PrintReceiptTapped::class.java) } @@ -1569,10 +1563,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onPrintReceiptClicked() } controller.onViewCreated() @@ -1590,10 +1582,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onPrintReceiptClicked() } controller.onViewCreated() @@ -1643,10 +1633,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1680,10 +1668,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically - ).onPrintReceiptClicked() + val state = controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + state.onPrintReceiptClicked() verify(tracker).trackPrintReceiptTapped() } @@ -1701,10 +1688,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onPrintReceiptClicked() } // THEN @@ -1748,10 +1734,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { // WHEN controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onPrintReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onPrintReceiptClicked() } // THEN assertThat((events.last() as CardReaderPaymentEvent.PrintReceiptTapped).receiptUrl).isEqualTo(receiptUrl) @@ -1793,10 +1777,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) @@ -1813,10 +1796,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat(events.last()).isEqualTo(CardReaderPaymentEvent.PlaySuccessfulPaymentSound) @@ -1834,10 +1815,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1858,10 +1837,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1881,10 +1858,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat((events.last() as CardReaderPaymentEvent.ShowErrorMessage).message).isEqualTo( @@ -1903,10 +1878,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat( @@ -1926,10 +1899,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() val events = controller.event.runAndCaptureValues { - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onSendReceiptClicked() } assertThat( @@ -1945,10 +1916,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSendReceiptClicked() verify(tracker).trackEmailReceiptTapped() } @@ -1964,10 +1933,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onSendReceiptClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onSendReceiptClicked() verify(tracker).trackEmailReceiptTapped() } @@ -1980,10 +1947,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessful - ).onSaveUserClicked() + val state = controller.paymentState.value as PaymentSuccessful.ExternalReaderPaymentSuccessful + state.onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -1999,10 +1964,8 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(BUILT_IN) val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessful - ).onSaveUserClicked() + val state = controller.paymentState.value as PaymentSuccessful.BuiltInReaderPaymentSuccessful + state.onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -2018,11 +1981,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically - ) - .onSaveUserClicked() + val state = controller.paymentState.value as + PaymentSuccessful.ExternalReaderPaymentSuccessfulReceiptSentAutomatically + state.onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -2038,11 +1999,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { createController(cardReaderType = BUILT_IN) val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically - ) - .onSaveUserClicked() + val state = controller.paymentState.value as + PaymentSuccessful.BuiltInReaderPaymentSuccessfulReceiptSentAutomatically + state.onSaveUserClicked() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) @@ -2164,10 +2123,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - ( - controller.paymentState.value as - CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState - ).onCancel() + val state = controller.paymentState.value as + CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + state.onCancel() verify(tracker).trackPaymentCancelled("Collecting") } @@ -2180,10 +2138,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState - ).onCancel() + val state = controller.paymentState.value as + CardReaderPaymentState.CollectingPayment.ExternalReaderCollectPaymentState + state.onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -2196,10 +2153,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } controller.start() - ( - controller.paymentState.value as - CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment - ).onCancel() + val state = controller.paymentState.value as + CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + state.onCancel() verify(tracker).trackPaymentCancelled("Processing") } @@ -2212,10 +2168,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { } val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment - ).onCancel() + val state = controller.paymentState.value as + CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment + state.onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java) } @@ -3599,10 +3554,9 @@ class CardReaderPaymentControllerTest : BaseUnitTest() { val events = controller.event.runAndCaptureValues { controller.start() - ( - controller.paymentState.value as - CardReaderInteracRefundState.InteracRefundFailure.Cancelable - ).onCancel() + val state = controller.paymentState.value as + CardReaderInteracRefundState.InteracRefundFailure.Cancelable + state.onCancel() } assertThat(events.last()).isInstanceOf(CardReaderPaymentEvent.Exit::class.java)