diff --git a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt index 66cd77a89c..624698b320 100644 --- a/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt +++ b/ach/src/main/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegate.kt @@ -104,7 +104,7 @@ internal class DefaultACHDirectDebitDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(ACHDirectDebitComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -363,10 +363,12 @@ internal class DefaultACHDirectDebitDelegate( analyticsManager.clear(this) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit( state = state, diff --git a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt index 01eafac788..7f10877a75 100644 --- a/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt +++ b/ach/src/test/java/com/adyen/checkout/ach/internal/ui/DefaultACHDirectDebitDelegateTest.kt @@ -47,7 +47,9 @@ import com.adyen.checkout.ui.core.internal.util.AddressFormUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -64,7 +66,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -335,33 +340,34 @@ internal class DefaultACHDirectDebitDelegateTest( } @Test - fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { - genericEncryptor.shouldThrowException = true + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = + runTest { + genericEncryptor.shouldThrowException = true - delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) + delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) - delegate.updateInputData { - bankLocationId = TEST_BANK_BANK_LOCATION_ID - bankAccountNumber = TEST_BANK_ACCOUNT_NUMBER - ownerName = TEST_OWNER_NAME - address = AddressInputModel( - postalCode = "34220", - street = "Street Name", - stateOrProvince = "province", - houseNumberOrName = "44", - apartmentSuite = "aparment", - city = "Istanbul", - country = "Turkey", - ) - } + delegate.updateInputData { + bankLocationId = TEST_BANK_BANK_LOCATION_ID + bankAccountNumber = TEST_BANK_ACCOUNT_NUMBER + ownerName = TEST_OWNER_NAME + address = AddressInputModel( + postalCode = "34220", + street = "Street Name", + stateOrProvince = "province", + houseNumberOrName = "44", + apartmentSuite = "aparment", + city = "Istanbul", + country = "Turkey", + ) + } - val componentState = delegate.componentStateFlow.first() + val componentState = delegate.componentStateFlow.first() - val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) - analyticsManager.assertLastEventEquals(expectedEvent) + val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) - assertFalse(componentState.isValid) - } + assertFalse(componentState.isValid) + } @Test fun `when bankLocationId is invalid, then component state should be invalid`() = runTest { @@ -655,11 +661,15 @@ internal class DefaultACHDirectDebitDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createAchDelegate() - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/DefaultBacsDirectDebitDelegate.kt b/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/DefaultBacsDirectDebitDelegate.kt index dbadaf3077..e3f02c5650 100644 --- a/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/DefaultBacsDirectDebitDelegate.kt +++ b/bacs/src/main/java/com/adyen/checkout/bacs/internal/ui/DefaultBacsDirectDebitDelegate.kt @@ -34,6 +34,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultBacsDirectDebitDelegate( @@ -55,7 +56,7 @@ internal class DefaultBacsDirectDebitDelegate( private val _componentStateFlow = MutableStateFlow(createComponentState()) override val componentStateFlow: Flow = _componentStateFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -122,6 +123,11 @@ internal class DefaultBacsDirectDebitDelegate( onInputDataChanged() } + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { + val event = GenericEvents.submit(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value when (inputData.mode) { @@ -134,12 +140,7 @@ internal class DefaultBacsDirectDebitDelegate( } } - BacsDirectDebitMode.CONFIRMATION -> { - val event = GenericEvents.submit(paymentMethod.type.orEmpty()) - analyticsManager.trackEvent(event) - - submitHandler.onSubmit(state) - } + BacsDirectDebitMode.CONFIRMATION -> submitHandler.onSubmit(state) } } diff --git a/bacs/src/test/java/com/adyen/checkout/bacs/internal/DefaultBacsDirectDebitDelegateTest.kt b/bacs/src/test/java/com/adyen/checkout/bacs/internal/DefaultBacsDirectDebitDelegateTest.kt index 40d6987840..7cc4193646 100644 --- a/bacs/src/test/java/com/adyen/checkout/bacs/internal/DefaultBacsDirectDebitDelegateTest.kt +++ b/bacs/src/test/java/com/adyen/checkout/bacs/internal/DefaultBacsDirectDebitDelegateTest.kt @@ -34,6 +34,8 @@ import com.adyen.checkout.test.LoggingExtension import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -49,7 +51,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -566,23 +571,15 @@ internal class DefaultBacsDirectDebitDelegateTest( } @Test - fun `when onSubmit is called and component is in confirmation mode, then submit event is tracked`() { - delegate.updateInputData { mode = BacsDirectDebitMode.CONFIRMATION } - - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) - } + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createBacsDelegate() - @Test - fun `when onSubmit is called and component is not in confirmation mode, then submit event is not tracked`() { - delegate.updateInputData { mode = BacsDirectDebitMode.INPUT } - - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventNotEquals(expectedEvent) + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/blik/src/main/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegate.kt b/blik/src/main/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegate.kt index 910ebf01c0..1979299447 100644 --- a/blik/src/main/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegate.kt +++ b/blik/src/main/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegate.kt @@ -33,6 +33,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultBlikDelegate( @@ -58,7 +59,7 @@ internal class DefaultBlikDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(BlikComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow @@ -150,10 +151,12 @@ internal class DefaultBlikDelegate( ) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state) } diff --git a/blik/src/test/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegateTest.kt b/blik/src/test/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegateTest.kt index 5eb99626cc..bfbe49de84 100644 --- a/blik/src/test/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegateTest.kt +++ b/blik/src/test/java/com/adyen/checkout/blik/internal/ui/DefaultBlikDelegateTest.kt @@ -28,6 +28,8 @@ import com.adyen.checkout.test.LoggingExtension import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -43,7 +45,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -264,11 +269,15 @@ internal class DefaultBlikDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createBlikDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt index 2b596506f3..f3fa71cfda 100644 --- a/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt +++ b/boleto/src/main/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegate.kt @@ -83,7 +83,7 @@ internal class DefaultBoletoDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(BoletoComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -292,10 +292,12 @@ internal class DefaultBoletoDelegate( observerRepository.removeObservers() } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { submitHandler.onSubmit(_componentStateFlow.value) } diff --git a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt index 5cc9b9f6d3..d34b4b17a8 100644 --- a/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt +++ b/boleto/src/test/java/com/adyen/checkout/boleto/internal/ui/DefaultBoletoDelegateTest.kt @@ -32,6 +32,8 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -47,7 +49,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -526,11 +531,15 @@ internal class DefaultBoletoDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createBoletoDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt index 4476ff257a..6cd066770d 100644 --- a/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt +++ b/card/src/main/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegate.kt @@ -143,7 +143,7 @@ class DefaultCardDelegate( MutableStateFlow(CardComponentViewType.DefaultCardView) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -486,10 +486,12 @@ class DefaultCardDelegate( ) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state = state) } diff --git a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt index 6c08efc7ac..289ea5d5fa 100644 --- a/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt +++ b/card/src/test/java/com/adyen/checkout/card/internal/ui/DefaultCardDelegateTest.kt @@ -76,6 +76,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest @@ -95,6 +97,7 @@ import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.util.Locale @@ -695,24 +698,25 @@ internal class DefaultCardDelegateTest( } @Test - fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { - cardEncryptor.shouldThrowException = true + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = + runTest { + cardEncryptor.shouldThrowException = true - delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) + delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) - delegate.componentStateFlow.test { - delegate.updateComponentState(createOutputData()) + delegate.componentStateFlow.test { + delegate.updateComponentState(createOutputData()) - val componentState = expectMostRecentItem() + val componentState = expectMostRecentItem() - val expectedEvent = GenericEvents.error(PaymentMethodTypes.SCHEME, ErrorEvent.ENCRYPTION) - analyticsManager.assertLastEventEquals(expectedEvent) + val expectedEvent = GenericEvents.error(PaymentMethodTypes.SCHEME, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) - assertTrue(componentState.isReady) - assertFalse(componentState.isInputValid) - assertNull(componentState.lastFourDigits) + assertTrue(componentState.isReady) + assertFalse(componentState.isInputValid) + assertNull(componentState.lastFourDigits) + } } - } @Test fun `card number in output data is invalid, then component state should be invalid`() = runTest { @@ -1063,11 +1067,15 @@ internal class DefaultCardDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createCardDelegate() - val expectedEvent = GenericEvents.submit(PaymentMethodTypes.SCHEME) - analyticsManager.assertLastEventEquals(expectedEvent) + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(PaymentMethodTypes.SCHEME) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt index 802487ef68..2dee36b608 100644 --- a/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt +++ b/cashapppay/src/main/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegate.kt @@ -52,6 +52,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -82,7 +83,7 @@ constructor( private val exceptionChannel: Channel = bufferedChannel() val exceptionFlow: Flow = exceptionChannel.receiveAsFlow() - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() private var _coroutineScope: CoroutineScope? = null private val coroutineScope: CoroutineScope get() = requireNotNull(_coroutineScope) @@ -192,6 +193,11 @@ constructor( ) } + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { + val event = GenericEvents.submit(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(event) + } + override fun onSubmit() { if (isConfirmationRequired()) { initiatePayment() @@ -274,9 +280,6 @@ constructor( authorizationData = createAuthorizationData(newState.responseData) } - val event = GenericEvents.submit(paymentMethod.type.orEmpty()) - analyticsManager.trackEvent(event) - submitHandler.onSubmit(_componentStateFlow.value) } diff --git a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt index 43296b23f5..4ecfd30ade 100644 --- a/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt +++ b/cashapppay/src/test/java/com/adyen/checkout/cashapppay/internal/ui/DefaultCashAppPayDelegateTest.kt @@ -47,6 +47,8 @@ import com.adyen.checkout.test.extensions.test import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -480,20 +482,6 @@ internal class DefaultCashAppPayDelegateTest( analyticsManager.assertLastEventNotEquals(expectedEvent) } - @Test - fun `when delegate is initialized and confirmation is not required, then submit event is tracked`() { - delegate = createDefaultCashAppPayDelegate( - createCheckoutConfiguration(Amount("USD", 10L)) { - setShowStorePaymentField(false) - }, - ) - - delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) - } - @Test fun `when component state is valid then PaymentMethodDetails should contain checkoutAttemptId`() = runTest { analyticsManager.setCheckoutAttemptId(TEST_CHECKOUT_ATTEMPT_ID) @@ -512,11 +500,15 @@ internal class DefaultCashAppPayDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createDefaultCashAppPayDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/econtext/src/main/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegate.kt b/econtext/src/main/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegate.kt index 55ff652f7f..cd94ec5b65 100644 --- a/econtext/src/main/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegate.kt +++ b/econtext/src/main/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegate.kt @@ -39,6 +39,7 @@ import com.adyen.checkout.ui.core.internal.util.CountryUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach import java.util.Locale @Suppress("TooManyFunctions", "LongParameterList") @@ -73,7 +74,7 @@ internal class DefaultEContextDelegate< private val _viewFlow: MutableStateFlow = MutableStateFlow(EContextComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -202,10 +203,12 @@ internal class DefaultEContextDelegate< analyticsManager.clear(this) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state) } diff --git a/econtext/src/test/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegateTest.kt b/econtext/src/test/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegateTest.kt index ce2542bc71..80732f95e0 100644 --- a/econtext/src/test/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegateTest.kt +++ b/econtext/src/test/java/com/adyen/checkout/econtext/internal/ui/DefaultEContextDelegateTest.kt @@ -30,6 +30,8 @@ import com.adyen.checkout.test.LoggingExtension import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -46,6 +48,9 @@ import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -269,11 +274,15 @@ internal class DefaultEContextDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createEContextDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt b/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt index 313fa52e35..5d985c1716 100644 --- a/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt +++ b/giftcard/src/main/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegate.kt @@ -56,6 +56,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch @@ -90,7 +91,7 @@ class DefaultGiftCardDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(protocol.getComponentViewType()) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow @@ -251,10 +252,12 @@ class DefaultGiftCardDelegate( ) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state) } diff --git a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt index 66da89942a..27d85525e5 100644 --- a/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt +++ b/giftcard/src/test/java/com/adyen/checkout/giftcard/internal/ui/DefaultGiftCardDelegateTest.kt @@ -40,6 +40,8 @@ import com.adyen.checkout.test.extensions.test import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -56,7 +58,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -127,25 +132,26 @@ internal class DefaultGiftCardDelegateTest( } @Test - fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = runTest { - cardEncryptor.shouldThrowException = true + fun `encryption fails, then component state should be invalid and analytics error event is tracked`() = + runTest { + cardEncryptor.shouldThrowException = true - delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) + delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) - delegate.componentStateFlow.test { - delegate.updateComponentState(createValidOutputData()) + delegate.componentStateFlow.test { + delegate.updateComponentState(createValidOutputData()) - val componentState = expectMostRecentItem() + val componentState = expectMostRecentItem() - val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) - analyticsManager.assertLastEventEquals(expectedEvent) + val expectedEvent = GenericEvents.error(TEST_PAYMENT_METHOD_TYPE, ErrorEvent.ENCRYPTION) + analyticsManager.assertLastEventEquals(expectedEvent) - assertTrue(componentState.isReady) - assertFalse(componentState.isInputValid) - assertEquals(null, componentState.lastFourDigits) - assertEquals(GiftCardAction.Idle, componentState.giftCardAction) + assertTrue(componentState.isReady) + assertFalse(componentState.isInputValid) + assertEquals(null, componentState.lastFourDigits) + assertEquals(GiftCardAction.Idle, componentState.giftCardAction) + } } - } @Test fun `everything is valid, then component state should be good`() = runTest { @@ -377,11 +383,15 @@ internal class DefaultGiftCardDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createGiftCardDelegate() - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/issuer-list/src/main/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegate.kt b/issuer-list/src/main/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegate.kt index c438256fd5..39b7319d5b 100644 --- a/issuer-list/src/main/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegate.kt +++ b/issuer-list/src/main/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegate.kt @@ -35,6 +35,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions", "LongParameterList") internal class DefaultIssuerListDelegate< @@ -68,7 +69,7 @@ internal class DefaultIssuerListDelegate< private val _viewFlow: MutableStateFlow = MutableStateFlow(getIssuerListComponentViewType()) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -121,10 +122,12 @@ internal class DefaultIssuerListDelegate< onInputDataChanged() } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state) } diff --git a/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegateTest.kt b/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegateTest.kt index ce91016bae..b6bccd8d98 100644 --- a/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegateTest.kt +++ b/issuer-list/src/test/java/com/adyen/checkout/issuerlist/internal/ui/DefaultIssuerListDelegateTest.kt @@ -30,6 +30,8 @@ import com.adyen.checkout.test.LoggingExtension import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -46,7 +48,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -306,11 +311,15 @@ internal class DefaultIssuerListDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(PaymentMethodTypes.IDEAL) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createIssuerListDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(PaymentMethodTypes.IDEAL) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/mbway/src/main/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegate.kt b/mbway/src/main/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegate.kt index 344bbc1d18..5a5b579712 100644 --- a/mbway/src/main/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegate.kt +++ b/mbway/src/main/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegate.kt @@ -35,6 +35,7 @@ import com.adyen.checkout.ui.core.internal.util.CountryUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultMBWayDelegate( @@ -59,7 +60,7 @@ internal class DefaultMBWayDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(MbWayComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow @@ -78,8 +79,8 @@ internal class DefaultMBWayDelegate( adyenLog(AdyenLogLevel.VERBOSE) { "initializeAnalytics" } analyticsManager.initialize(this, coroutineScope) - val event = GenericEvents.rendered(paymentMethod.type.orEmpty()) - analyticsManager.trackEvent(event) + val renderedEvent = GenericEvents.rendered(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(renderedEvent) } override fun observe( @@ -166,10 +167,12 @@ internal class DefaultMBWayDelegate( return countries.firstOrNull { it.isoCode == ISO_CODE_PORTUGAL } ?: countries.firstOrNull() } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state) } diff --git a/mbway/src/test/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegateTest.kt b/mbway/src/test/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegateTest.kt index 2cc1edbdb4..f659b8f7a6 100644 --- a/mbway/src/test/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegateTest.kt +++ b/mbway/src/test/java/com/adyen/checkout/mbway/internal/ui/DefaultMBWayDelegateTest.kt @@ -27,6 +27,8 @@ import com.adyen.checkout.mbway.mbWay import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -42,7 +44,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -269,11 +274,15 @@ internal class DefaultMBWayDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createMBWayDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/online-banking-core/src/main/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegate.kt b/online-banking-core/src/main/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegate.kt index 4ce120e348..219dca1961 100644 --- a/online-banking-core/src/main/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegate.kt +++ b/online-banking-core/src/main/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegate.kt @@ -41,6 +41,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow @Suppress("TooManyFunctions", "LongParameterList") @@ -80,7 +81,7 @@ internal class DefaultOnlineBankingDelegate< private val _viewFlow: MutableStateFlow = MutableStateFlow(OnlineBankingComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -176,10 +177,12 @@ internal class DefaultOnlineBankingDelegate< } } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state = state) } diff --git a/online-banking-core/src/test/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegateTest.kt b/online-banking-core/src/test/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegateTest.kt index bd1eb44666..d881df63ab 100644 --- a/online-banking-core/src/test/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegateTest.kt +++ b/online-banking-core/src/test/java/com/adyen/checkout/onlinebankingcore/internal/ui/DefaultOnlineBankingDelegateTest.kt @@ -29,6 +29,8 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import com.adyen.checkout.ui.core.internal.util.PdfOpener import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -46,7 +48,9 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.util.Locale @@ -250,11 +254,15 @@ internal class DefaultOnlineBankingDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createOnlineBankingDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/paybybank/src/main/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegate.kt b/paybybank/src/main/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegate.kt index 08d0646634..b7a831d553 100644 --- a/paybybank/src/main/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegate.kt +++ b/paybybank/src/main/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegate.kt @@ -35,6 +35,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultPayByBankDelegate( @@ -59,7 +60,7 @@ internal class DefaultPayByBankDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(null) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -186,10 +187,12 @@ internal class DefaultPayByBankDelegate( } } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state = state) } diff --git a/paybybank/src/test/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegateTest.kt b/paybybank/src/test/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegateTest.kt index 3dc22356a7..f285aa49ba 100644 --- a/paybybank/src/test/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegateTest.kt +++ b/paybybank/src/test/java/com/adyen/checkout/paybybank/internal/ui/DefaultPayByBankDelegateTest.kt @@ -29,6 +29,8 @@ import com.adyen.checkout.test.LoggingExtension import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -45,7 +47,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -262,11 +267,15 @@ internal class DefaultPayByBankDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createPayByBankDelegate(issuers = emptyList()) + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/sepa/src/main/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegate.kt b/sepa/src/main/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegate.kt index 66d0be7204..2dd71c2aad 100644 --- a/sepa/src/main/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegate.kt +++ b/sepa/src/main/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegate.kt @@ -33,6 +33,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultSepaDelegate( @@ -57,7 +58,7 @@ internal class DefaultSepaDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(SepaComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow override val uiEventFlow: Flow = submitHandler.uiEventFlow @@ -140,10 +141,12 @@ internal class DefaultSepaDelegate( ) } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { val state = _componentStateFlow.value submitHandler.onSubmit(state = state) } diff --git a/sepa/src/test/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegateTest.kt b/sepa/src/test/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegateTest.kt index 5f9a0ad68a..e69d0304d0 100644 --- a/sepa/src/test/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegateTest.kt +++ b/sepa/src/test/java/com/adyen/checkout/sepa/internal/ui/DefaultSepaDelegateTest.kt @@ -29,6 +29,8 @@ import com.adyen.checkout.sepa.sepa import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions @@ -44,7 +46,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -196,11 +201,15 @@ internal class DefaultSepaDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createSepaDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/twint/src/main/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegate.kt b/twint/src/main/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegate.kt index 4fb4c70b86..b7a1ac4a9a 100644 --- a/twint/src/main/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegate.kt +++ b/twint/src/main/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegate.kt @@ -33,6 +33,7 @@ import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultTwintDelegate( @@ -54,7 +55,7 @@ internal class DefaultTwintDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(TwintComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override fun initialize(coroutineScope: CoroutineScope) { submitHandler.initialize(coroutineScope, componentStateFlow) @@ -149,6 +150,11 @@ internal class DefaultTwintDelegate( private fun shouldStorePaymentMethod(): Boolean = componentParams.showStorePaymentField && outputData.isStorePaymentSelected + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { + val event = GenericEvents.submit(paymentMethod.type.orEmpty()) + analyticsManager.trackEvent(event) + } + override fun onSubmit() { if (isConfirmationRequired()) { initiatePayment() @@ -156,9 +162,6 @@ internal class DefaultTwintDelegate( } private fun initiatePayment() { - val event = GenericEvents.submit(paymentMethod.type.orEmpty()) - analyticsManager.trackEvent(event) - val state = _componentStateFlow.value submitHandler.onSubmit(state = state) } diff --git a/twint/src/test/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegateTest.kt b/twint/src/test/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegateTest.kt index 040e0d016c..2b53883089 100644 --- a/twint/src/test/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegateTest.kt +++ b/twint/src/test/java/com/adyen/checkout/twint/internal/ui/DefaultTwintDelegateTest.kt @@ -22,6 +22,8 @@ import com.adyen.checkout.twint.twint import com.adyen.checkout.ui.core.internal.ui.SubmitHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -39,8 +41,11 @@ import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.times import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -294,20 +299,6 @@ internal class DefaultTwintDelegateTest( analyticsManager.assertLastEventNotEquals(expectedEvent) } - @Test - fun `when delegate is initialized and confirmation is not required, then submit event is tracked`() { - delegate = createDefaultTwintDelegate( - createCheckoutConfiguration(Amount("USD", 10L)) { - setShowStorePaymentField(false) - }, - ) - - delegate.initialize(CoroutineScope(UnconfinedTestDispatcher())) - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) - } - @Test fun `when component state is valid, then payment method should contain checkoutAttemptId`() = runTest { analyticsManager.setCheckoutAttemptId(TEST_CHECKOUT_ATTEMPT_ID) @@ -320,11 +311,15 @@ internal class DefaultTwintDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createDefaultTwintDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test diff --git a/upi/src/main/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegate.kt b/upi/src/main/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegate.kt index 5549d05871..64c84c066c 100644 --- a/upi/src/main/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegate.kt +++ b/upi/src/main/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegate.kt @@ -42,6 +42,7 @@ import com.adyen.checkout.upi.internal.ui.model.mapToSelectedMode import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.onEach @Suppress("TooManyFunctions") internal class DefaultUPIDelegate( @@ -66,7 +67,7 @@ internal class DefaultUPIDelegate( private val _viewFlow: MutableStateFlow = MutableStateFlow(UPIComponentViewType) override val viewFlow: Flow = _viewFlow - override val submitFlow: Flow = submitHandler.submitFlow + override val submitFlow: Flow = getTrackedSubmitFlow() override val uiStateFlow: Flow = submitHandler.uiStateFlow @@ -312,10 +313,12 @@ internal class DefaultUPIDelegate( return paymentMethod.type ?: PaymentMethodTypes.UNKNOWN } - override fun onSubmit() { + private fun getTrackedSubmitFlow() = submitHandler.submitFlow.onEach { val event = GenericEvents.submit(paymentMethod.type.orEmpty()) analyticsManager.trackEvent(event) + } + override fun onSubmit() { submitHandler.onSubmit(_componentStateFlow.value) } diff --git a/upi/src/test/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegateTest.kt b/upi/src/test/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegateTest.kt index 40e23abccf..e43678c429 100644 --- a/upi/src/test/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegateTest.kt +++ b/upi/src/test/java/com/adyen/checkout/upi/internal/ui/DefaultUPIDelegateTest.kt @@ -38,6 +38,8 @@ import com.adyen.checkout.upi.upi import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -54,7 +56,10 @@ import org.junit.jupiter.params.provider.Arguments.arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import java.util.Locale @OptIn(ExperimentalCoroutinesApi::class) @@ -555,11 +560,15 @@ internal class DefaultUPIDelegateTest( } @Test - fun `when onSubmit is called, then submit event is tracked`() { - delegate.onSubmit() - - val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) - analyticsManager.assertLastEventEquals(expectedEvent) + fun `when submitFlow emits an event, then submit event is tracked`() = runTest { + val submitFlow = flow { emit(mock()) } + whenever(submitHandler.submitFlow) doReturn submitFlow + val delegate = createUPIDelegate() + + delegate.submitFlow.collectLatest { + val expectedEvent = GenericEvents.submit(TEST_PAYMENT_METHOD_TYPE) + analyticsManager.assertLastEventEquals(expectedEvent) + } } @Test