From e2e62ab4b953276d9e38c015ccbc669bac26a647 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Wed, 1 Sep 2021 12:46:52 -0700 Subject: [PATCH 01/16] inject payment launcher into model --- .../paymentsheet/PaymentSheetActivity.kt | 5 +- .../paymentsheet/PaymentSheetViewModel.kt | 50 ++++++++++++------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt index a2f46fe655a..ddd99234dd6 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt @@ -145,10 +145,7 @@ internal class PaymentSheetActivity : BaseSheetActivity() { val confirmParams = event.getContentIfNotHandled() if (confirmParams != null) { lifecycleScope.launch { - viewModel.confirmStripeIntent( - AuthActivityStarterHost.create(this@PaymentSheetActivity), - confirmParams - ) + viewModel.confirmStripeIntent(confirmParams) } } } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 2041613373f..6901f816726 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -1,6 +1,7 @@ package com.stripe.android.paymentsheet import android.app.Application +import android.util.Log import androidx.activity.result.ActivityResultCaller import androidx.activity.result.ActivityResultLauncher import androidx.annotation.IntegerRes @@ -21,6 +22,8 @@ import com.stripe.android.googlepaylauncher.GooglePayEnvironment import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherFactory +import com.stripe.android.model.ConfirmPaymentIntentParams +import com.stripe.android.model.ConfirmSetupIntentParams import com.stripe.android.model.ConfirmStripeIntentParams import com.stripe.android.model.PaymentIntent import com.stripe.android.model.PaymentMethod @@ -29,6 +32,11 @@ import com.stripe.android.networking.ApiRequest import com.stripe.android.payments.PaymentFlowResult import com.stripe.android.payments.PaymentFlowResultProcessor import com.stripe.android.payments.core.injection.IOContext +import com.stripe.android.payments.paymentlauncher.PaymentLauncher +import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract +import com.stripe.android.payments.paymentlauncher.PaymentLauncherFactory +import com.stripe.android.payments.paymentlauncher.PaymentResult +import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory import com.stripe.android.paymentsheet.analytics.EventReporter import com.stripe.android.paymentsheet.injection.DaggerPaymentSheetViewModelComponent import com.stripe.android.paymentsheet.model.ConfirmStripeIntentParamsFactory @@ -80,7 +88,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( private val paymentFlowResultProcessorProvider: Provider>>, prefsRepository: PrefsRepository, - private val paymentController: PaymentController, + private val paymentLauncherFactory: StripePaymentLauncherAssistedFactory, private val googlePayPaymentMethodLauncherFactory: GooglePayPaymentMethodLauncherFactory, private val logger: Logger, @IOContext workContext: CoroutineContext @@ -155,6 +163,9 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } + @VisibleForTesting + internal var paymentLauncher: PaymentLauncher? = null + init { eventReporter.onInit(config) if (googlePayLauncherConfig == null) { @@ -301,29 +312,34 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - suspend fun confirmStripeIntent( - authActivityStarterHost: AuthActivityStarterHost, - confirmStripeIntentParams: ConfirmStripeIntentParams - ) { - paymentController.startConfirmAndAuth( - authActivityStarterHost, - confirmStripeIntentParams, - ApiRequest.Options( - lazyPaymentConfig.get().publishableKey, - lazyPaymentConfig.get().stripeAccountId - ) - ) + fun confirmStripeIntent(confirmStripeIntentParams: ConfirmStripeIntentParams) { + when (confirmStripeIntentParams) { + is ConfirmPaymentIntentParams -> { + paymentLauncher?.confirm(confirmStripeIntentParams) + } + is ConfirmSetupIntentParams -> { + paymentLauncher?.confirm(confirmStripeIntentParams) + } + } + } + + fun onPaymentResult(paymentResult: PaymentResult) { + Log.d("Skyler", "result: $paymentResult") } fun registerFromActivity(activityResultCaller: ActivityResultCaller) { - paymentController.registerLaunchersWithActivityResultCaller( - activityResultCaller, - ::onPaymentFlowResult + paymentLauncher = paymentLauncherFactory.create( + { lazyPaymentConfig.get().publishableKey }, + { lazyPaymentConfig.get().stripeAccountId }, + activityResultCaller.registerForActivityResult( + PaymentLauncherContract(), + ::onPaymentResult + ) ) } fun unregisterFromActivity() { - paymentController.unregisterLaunchers() + paymentLauncher = null } private fun confirmPaymentSelection(paymentSelection: PaymentSelection?) { From 9eb21ea93b6323778f199c413f3e041248ecb70d Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Wed, 1 Sep 2021 13:48:10 -0700 Subject: [PATCH 02/16] process paymentResult rather than StripeIntentResult --- .../paymentsheet/PaymentSheetViewModel.kt | 80 +++++-------------- 1 file changed, 19 insertions(+), 61 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 6901f816726..4edb6e0a09e 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -1,7 +1,6 @@ package com.stripe.android.paymentsheet import android.app.Application -import android.util.Log import androidx.activity.result.ActivityResultCaller import androidx.activity.result.ActivityResultLauncher import androidx.annotation.IntegerRes @@ -15,9 +14,6 @@ import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.viewModelScope import com.stripe.android.Logger import com.stripe.android.PaymentConfiguration -import com.stripe.android.PaymentController -import com.stripe.android.StripeIntentResult -import com.stripe.android.exception.APIConnectionException import com.stripe.android.googlepaylauncher.GooglePayEnvironment import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract @@ -28,13 +24,9 @@ import com.stripe.android.model.ConfirmStripeIntentParams import com.stripe.android.model.PaymentIntent import com.stripe.android.model.PaymentMethod import com.stripe.android.model.StripeIntent -import com.stripe.android.networking.ApiRequest -import com.stripe.android.payments.PaymentFlowResult -import com.stripe.android.payments.PaymentFlowResultProcessor import com.stripe.android.payments.core.injection.IOContext import com.stripe.android.payments.paymentlauncher.PaymentLauncher import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract -import com.stripe.android.payments.paymentlauncher.PaymentLauncherFactory import com.stripe.android.payments.paymentlauncher.PaymentResult import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory import com.stripe.android.paymentsheet.analytics.EventReporter @@ -49,13 +41,10 @@ import com.stripe.android.paymentsheet.repositories.CustomerRepository import com.stripe.android.paymentsheet.repositories.StripeIntentRepository import com.stripe.android.paymentsheet.ui.PrimaryButton import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel -import com.stripe.android.view.AuthActivityStarterHost import dagger.Lazy import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import javax.inject.Inject -import javax.inject.Provider import javax.inject.Singleton import kotlin.coroutines.CoroutineContext @@ -85,8 +74,6 @@ internal class PaymentSheetViewModel @Inject internal constructor( private val stripeIntentRepository: StripeIntentRepository, private val stripeIntentValidator: StripeIntentValidator, customerRepository: CustomerRepository, - private val paymentFlowResultProcessorProvider: - Provider>>, prefsRepository: PrefsRepository, private val paymentLauncherFactory: StripePaymentLauncherAssistedFactory, private val googlePayPaymentMethodLauncherFactory: GooglePayPaymentMethodLauncherFactory, @@ -173,19 +160,6 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - private fun apiThrowableToString(throwable: Throwable): String? { - return when (throwable) { - is APIConnectionException -> { - getApplication().resources.getString( - R.string.stripe_failure_connection_error - ) - } - else -> { - throwable.localizedMessage - } - } - } - fun setupGooglePay( lifecycleScope: CoroutineScope, activityResultLauncher: ActivityResultLauncher @@ -323,10 +297,6 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - fun onPaymentResult(paymentResult: PaymentResult) { - Log.d("Skyler", "result: $paymentResult") - } - fun registerFromActivity(activityResultCaller: ActivityResultCaller) { paymentLauncher = paymentLauncherFactory.create( { lazyPaymentConfig.get().publishableKey }, @@ -356,16 +326,27 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - private fun onStripeIntentResult( - stripeIntentResult: StripeIntentResult - ) { - when (stripeIntentResult.outcome) { - StripeIntentResult.Outcome.SUCCEEDED -> { + private fun onPaymentResult(paymentResult: PaymentResult) { + viewModelScope.launch { + runCatching { + stripeIntentRepository.get(args.clientSecret) + }.fold( + onSuccess = { + processPayment(it, paymentResult) + }, + onFailure = ::onFatal + ) + } + } + + private fun processPayment(stripeIntent: StripeIntent, paymentResult: PaymentResult) { + when (paymentResult) { + PaymentResult.Completed -> { eventReporter.onPaymentSuccess(selection.value) // SavedSelection needs to happen after new cards have been saved. when (selection.value) { - is PaymentSelection.New -> stripeIntentResult.intent.paymentMethod?.let { + is PaymentSelection.New -> stripeIntent.paymentMethod?.let { PaymentSelection.Saved(it) } PaymentSelection.GooglePay -> selection.value @@ -383,11 +364,11 @@ internal class PaymentSheetViewModel @Inject internal constructor( eventReporter.onPaymentFailure(selection.value) runCatching { - stripeIntentValidator.requireValid(stripeIntentResult.intent) + stripeIntentValidator.requireValid(stripeIntent) }.fold( onSuccess = { resetViewState( - stripeIntentResult.failureMessage + stripeIntent.lastErrorMessage ) }, onFailure = ::onFatal @@ -415,29 +396,6 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - fun onPaymentFlowResult(paymentFlowResult: PaymentFlowResult.Unvalidated) { - viewModelScope.launch { - runCatching { - withContext(workContext) { - paymentFlowResultProcessorProvider.get().processResult( - paymentFlowResult - ) - } - }.fold( - onSuccess = { - onStripeIntentResult(it) - }, - onFailure = { error -> - selection.value?.let { - eventReporter.onPaymentFailure(it) - } - - resetViewState(apiThrowableToString(error)) - } - ) - } - } - override fun onFatal(throwable: Throwable) { logger.error("Payment Sheet error", throwable) _fatal.value = throwable From a7a64641ad342e6028c242bc3169ec08b1697a47 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Wed, 1 Sep 2021 15:18:12 -0700 Subject: [PATCH 03/16] add correct error messages to payment sheet --- .../payments/PaymentFlowFailureMessageFactory.kt | 14 +++++++++++--- .../android/paymentsheet/PaymentSheetViewModel.kt | 4 +++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt index 59925721dc9..e0ea93b5869 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt @@ -1,22 +1,30 @@ package com.stripe.android.payments import android.content.Context +import androidx.annotation.RestrictTo import com.stripe.android.R import com.stripe.android.StripeIntentResult import com.stripe.android.model.PaymentIntent import com.stripe.android.model.SetupIntent import com.stripe.android.model.StripeIntent -internal class PaymentFlowFailureMessageFactory( +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +class PaymentFlowFailureMessageFactory( private val context: Context ) { fun create( intent: StripeIntent, @StripeIntentResult.Outcome outcome: Int - ) = when { - outcome == StripeIntentResult.Outcome.TIMEDOUT -> { + ) = when (outcome) { + StripeIntentResult.Outcome.TIMEDOUT -> { context.resources.getString(R.string.stripe_failure_reason_timed_out) } + else -> create(intent) + } + + fun create( + intent: StripeIntent, + ) = when { (intent.status == StripeIntent.Status.RequiresPaymentMethod) || (intent.status == StripeIntent.Status.RequiresAction) -> { when (intent) { diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 4edb6e0a09e..f1766d1e18c 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -23,7 +23,9 @@ import com.stripe.android.model.ConfirmSetupIntentParams import com.stripe.android.model.ConfirmStripeIntentParams import com.stripe.android.model.PaymentIntent import com.stripe.android.model.PaymentMethod +import com.stripe.android.model.SetupIntent import com.stripe.android.model.StripeIntent +import com.stripe.android.payments.PaymentFlowFailureMessageFactory import com.stripe.android.payments.core.injection.IOContext import com.stripe.android.payments.paymentlauncher.PaymentLauncher import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract @@ -368,7 +370,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( }.fold( onSuccess = { resetViewState( - stripeIntent.lastErrorMessage + PaymentFlowFailureMessageFactory(getApplication()).create(stripeIntent) ) }, onFailure = ::onFatal From 30437db0be7790122891a3181602c06dbc8f81d3 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Wed, 1 Sep 2021 15:38:39 -0700 Subject: [PATCH 04/16] fix klint --- .../java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt | 1 - .../com/stripe/android/paymentsheet/PaymentSheetViewModel.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt index ddd99234dd6..5fa3e2e61ba 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetActivity.kt @@ -27,7 +27,6 @@ import com.stripe.android.paymentsheet.model.PaymentSheetViewState import com.stripe.android.paymentsheet.ui.AnimationConstants import com.stripe.android.paymentsheet.ui.BaseSheetActivity import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel -import com.stripe.android.view.AuthActivityStarterHost import kotlinx.coroutines.launch internal class PaymentSheetActivity : BaseSheetActivity() { diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index f1766d1e18c..4a484f68f6a 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -23,7 +23,6 @@ import com.stripe.android.model.ConfirmSetupIntentParams import com.stripe.android.model.ConfirmStripeIntentParams import com.stripe.android.model.PaymentIntent import com.stripe.android.model.PaymentMethod -import com.stripe.android.model.SetupIntent import com.stripe.android.model.StripeIntent import com.stripe.android.payments.PaymentFlowFailureMessageFactory import com.stripe.android.payments.core.injection.IOContext From 341444e788dbec4d6cb1bb66c0f727eab7780485 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Wed, 1 Sep 2021 20:17:43 -0700 Subject: [PATCH 05/16] update unit tests --- .../paymentlauncher/StripePaymentLauncher.kt | 2 +- .../paymentsheet/PaymentSheetViewModel.kt | 3 +- .../paymentsheet/PaymentSheetActivityTest.kt | 33 ++++-- .../paymentsheet/PaymentSheetViewModelTest.kt | 108 +++++++----------- 4 files changed, 66 insertions(+), 80 deletions(-) diff --git a/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt b/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt index 583bcaad86f..20d3d693329 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt @@ -28,7 +28,7 @@ import kotlin.coroutines.CoroutineContext * handle next actions for intents. */ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -class StripePaymentLauncher @AssistedInject internal constructor( +open class StripePaymentLauncher @AssistedInject internal constructor( @Assisted(PUBLISHABLE_KEY) publishableKeyProvider: () -> String, @Assisted(STRIPE_ACCOUNT_ID) stripeAccountIdProvider: () -> String?, @Assisted private val hostActivityLauncher: ActivityResultLauncher, diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 4a484f68f6a..55d9a8ef215 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -327,7 +327,8 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - private fun onPaymentResult(paymentResult: PaymentResult) { + @VisibleForTesting + fun onPaymentResult(paymentResult: PaymentResult) { viewModelScope.launch { runCatching { stripeIntentRepository.get(args.clientSecret) diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt index 411b5fddf95..79973e1beca 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt @@ -27,6 +27,12 @@ import com.stripe.android.model.PaymentMethodCreateParamsFixtures import com.stripe.android.model.PaymentMethodFixtures import com.stripe.android.payments.PaymentFlowResult import com.stripe.android.payments.PaymentFlowResultProcessor +import com.stripe.android.payments.core.injection.PUBLISHABLE_KEY +import com.stripe.android.payments.core.injection.STRIPE_ACCOUNT_ID +import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract +import com.stripe.android.payments.paymentlauncher.PaymentResult +import com.stripe.android.payments.paymentlauncher.StripePaymentLauncher +import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory import com.stripe.android.paymentsheet.PaymentSheetViewModel.CheckoutIdentifier import com.stripe.android.paymentsheet.analytics.EventReporter import com.stripe.android.paymentsheet.databinding.PrimaryButtonBinding @@ -44,6 +50,7 @@ import com.stripe.android.utils.TestUtils.idleLooper import com.stripe.android.utils.TestUtils.viewModelFactoryFor import com.stripe.android.utils.injectableActivityScenario import com.stripe.android.view.ActivityScenarioFactory +import dagger.assisted.Assisted import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -73,6 +80,8 @@ internal class PaymentSheetActivityTest { private val eventReporter = mock() private val googlePayPaymentMethodLauncherFactory = createGooglePayPaymentMethodLauncherFactory() + private val stripePaymentLauncherAssistedFactory = + stripePaymentLauncherAssistedFactory() private val viewModel = createViewModel() @@ -508,13 +517,8 @@ internal class PaymentSheetActivityTest { idleLooper() viewModel.checkoutIdentifier = CheckoutIdentifier.SheetBottomBuy + viewModel.onPaymentResult(PaymentResult.Completed) - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated( - "client_secret", - StripeIntentResult.Outcome.SUCCEEDED - ) - ) idleLooper() assertThat(activity.bottomSheetBehavior.state) @@ -723,7 +727,7 @@ internal class PaymentSheetActivityTest { mock>() whenever(paymentFlowResultProcessor.processResult(any())).thenReturn(paymentIntentResult) - val mockPaymentController: PaymentController = mock() + val mockPaymentLauncher: PaymentController = mock() PaymentSheetViewModel( ApplicationProvider.getApplicationContext(), PaymentSheetFixtures.ARGS_CUSTOMER_WITH_GOOGLEPAY, @@ -732,9 +736,8 @@ internal class PaymentSheetActivityTest { StripeIntentRepository.Static(paymentIntent), StripeIntentValidator(), FakeCustomerRepository(paymentMethods), - { paymentFlowResultProcessor }, FakePrefsRepository(), - mockPaymentController, + stripePaymentLauncherAssistedFactory, googlePayPaymentMethodLauncherFactory, Logger.noop(), testDispatcher @@ -755,6 +758,18 @@ internal class PaymentSheetActivityTest { } } + private fun stripePaymentLauncherAssistedFactory() = + object : StripePaymentLauncherAssistedFactory { + override fun create( + @Assisted(PUBLISHABLE_KEY) publishableKey: () -> String, + @Assisted(STRIPE_ACCOUNT_ID) stripeAccountId: () -> String?, + hostActivityLauncher: ActivityResultLauncher + ): StripePaymentLauncher { + val stripePaymentLauncher = mock() + return stripePaymentLauncher + } + } + private companion object { private val PAYMENT_INTENT = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD private val PAYMENT_METHODS = listOf(PaymentMethodFixtures.CARD_PAYMENT_METHOD) diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt index c0af3ee465b..fc90c9472b5 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt @@ -22,8 +22,7 @@ import com.stripe.android.model.PaymentMethodCreateParamsFixtures import com.stripe.android.model.PaymentMethodFixtures import com.stripe.android.model.StripeIntent import com.stripe.android.networking.StripeRepository -import com.stripe.android.payments.PaymentFlowResult -import com.stripe.android.payments.PaymentIntentFlowResultProcessor +import com.stripe.android.payments.paymentlauncher.PaymentResult import com.stripe.android.paymentsheet.PaymentSheetViewModel.CheckoutIdentifier import com.stripe.android.paymentsheet.analytics.EventReporter import com.stripe.android.paymentsheet.model.FragmentConfig @@ -75,7 +74,6 @@ internal class PaymentSheetViewModelTest { private val prefsRepository = FakePrefsRepository() private val eventReporter = mock() private val viewModel: PaymentSheetViewModel by lazy { createViewModel() } - private val paymentFlowResultProcessor = mock() private val application = ApplicationProvider.getApplicationContext() @Captor @@ -382,12 +380,8 @@ internal class PaymentSheetViewModelTest { } @Test - fun `onPaymentFlowResult() should update ViewState and save preferences`() = + fun `onPaymentResult() should update ViewState and save preferences`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenReturn( - PAYMENT_INTENT_RESULT - ) - val selection = PaymentSelection.Saved(PaymentMethodFixtures.CARD_PAYMENT_METHOD) viewModel.updateSelection(selection) @@ -401,12 +395,8 @@ internal class PaymentSheetViewModelTest { paymentSheetResult = it } - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated( - "client_secret", - StripeIntentResult.Outcome.SUCCEEDED - ) - ) + viewModel.onPaymentResult(PaymentResult.Completed) + assertThat(viewState[1]) .isInstanceOf(PaymentSheetViewState.FinishProcessing::class.java) @@ -426,10 +416,12 @@ internal class PaymentSheetViewModelTest { } @Test - fun `onPaymentFlowResult() should update ViewState and save new payment method`() = + fun `onPaymentResult() should update ViewState and save new payment method`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenReturn( - PAYMENT_INTENT_RESULT_WITH_PM + val viewModel = createViewModel( + ARGS_CUSTOMER_WITH_GOOGLEPAY, + StripeIntentRepository.Static(PAYMENT_INTENT_WITH_PM), + FakeCustomerRepository(PAYMENT_METHODS) ) val selection = PaymentSelection.New.Card( @@ -449,12 +441,8 @@ internal class PaymentSheetViewModelTest { paymentSheetResult = it } - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated( - "client_secret", - StripeIntentResult.Outcome.SUCCEEDED - ) - ) + viewModel.onPaymentResult(PaymentResult.Completed) + assertThat(viewState[1]) .isInstanceOf(PaymentSheetViewState.FinishProcessing::class.java) @@ -480,14 +468,8 @@ internal class PaymentSheetViewModelTest { } @Test - fun `onPaymentFlowResult() with non-success outcome should report failure event`() = + fun `onPaymentResult() with non-success outcome should report failure event`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenReturn( - PAYMENT_INTENT_RESULT.copy( - outcomeFromFlow = StripeIntentResult.Outcome.FAILED - ) - ) - val selection = PaymentSelection.Saved(PaymentMethodFixtures.CARD_PAYMENT_METHOD) viewModel.updateSelection(selection) @@ -496,9 +478,7 @@ internal class PaymentSheetViewModelTest { stripeIntent = it } - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated() - ) + viewModel.onPaymentResult(PaymentResult.Failed(Throwable())) verify(eventReporter) .onPaymentFailure(selection) @@ -506,56 +486,52 @@ internal class PaymentSheetViewModelTest { } @Test - fun `onPaymentFlowResult() with processing status for payment method which has delay should report success event`() = + fun `onPaymentResult() with processing status for payment method which has delay should report success event`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenReturn( - PaymentIntentResult( - PaymentIntentFixtures.PI_WITH_SHIPPING.copy( - paymentMethod = PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD, - status = StripeIntent.Status.Processing - ), - StripeIntentResult.Outcome.UNKNOWN - ) + val paymentIntent = PaymentIntentFixtures.PI_WITH_SHIPPING.copy( + paymentMethod = PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD, + status = StripeIntent.Status.Processing + ) + + val viewModel = createViewModel( + stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), ) val selection = PaymentSelection.Saved(PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD) viewModel.updateSelection(selection) - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated() - ) + viewModel.onPaymentResult(PaymentResult.Completed) + verify(eventReporter) .onPaymentSuccess(selection) } @Test - fun `onPaymentFlowResult() with processing status for payment method which does not have delay should report failure event`() = + fun `onPaymentResult() with processing status for payment method which does not have delay should report failure event`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenReturn( - PaymentIntentResult( - PaymentIntentFixtures.PI_WITH_SHIPPING.copy( - paymentMethod = PaymentMethodFixtures.CARD_PAYMENT_METHOD, - status = StripeIntent.Status.Processing - ), - StripeIntentResult.Outcome.UNKNOWN - ) + val paymentIntent = PaymentIntentFixtures.PI_WITH_SHIPPING.copy( + paymentMethod = PaymentMethodFixtures.CARD_PAYMENT_METHOD, + status = StripeIntent.Status.Processing + ) + + val viewModel = createViewModel( + stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), ) val selection = PaymentSelection.Saved(PaymentMethodFixtures.CARD_PAYMENT_METHOD) viewModel.updateSelection(selection) - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated() - ) + viewModel.onPaymentResult(PaymentResult.Failed(Throwable())) verify(eventReporter) .onPaymentFailure(selection) } @Test - fun `onPaymentFlowResult() should update emit API errors`() = + fun `onPaymentResult() should update emit API errors`() = testDispatcher.runBlockingTest { - whenever(paymentFlowResultProcessor.processResult(any())).thenThrow( - RuntimeException("Your card was declined.") + val paymentIntent = PaymentIntentFixtures.PI_WITH_LAST_PAYMENT_ERROR + val viewModel = createViewModel( + stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), ) viewModel.fetchStripeIntent() @@ -564,9 +540,8 @@ internal class PaymentSheetViewModelTest { viewModel.viewState.observeForever { viewStateList.add(it) } - viewModel.onPaymentFlowResult( - PaymentFlowResult.Unvalidated() - ) + + viewModel.onPaymentResult(PaymentResult.Failed(Throwable())) assertThat(viewStateList[0]) .isEqualTo( @@ -575,7 +550,7 @@ internal class PaymentSheetViewModelTest { assertThat(viewStateList[1]) .isEqualTo( PaymentSheetViewState.Reset( - UserErrorMessage("Your card was declined.") + UserErrorMessage(application.resources.getString(R.string.stripe_failure_reason_authentication)) ) ) } @@ -807,7 +782,6 @@ internal class PaymentSheetViewModelTest { stripeIntentRepository, StripeIntentValidator(), customerRepository, - { paymentFlowResultProcessor }, prefsRepository, mock(), mock(), @@ -826,10 +800,6 @@ internal class PaymentSheetViewModelTest { private val PAYMENT_METHODS = listOf(PaymentMethodFixtures.CARD_PAYMENT_METHOD) val PAYMENT_INTENT = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD - val PAYMENT_INTENT_RESULT = PaymentIntentResult( - intent = PAYMENT_INTENT, - outcomeFromFlow = StripeIntentResult.Outcome.SUCCEEDED - ) val PAYMENT_INTENT_WITH_PM = PaymentIntentFixtures.PI_SUCCEEDED.copy( paymentMethod = PaymentMethodFixtures.CARD_PAYMENT_METHOD From ce39c5688efbd81fde7d692c6f7fa4eef90884db Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 10:51:40 -0700 Subject: [PATCH 06/16] fix api check failure --- payments-core/api/payments-core.api | 9 ++++++++- paymentsheet/api/paymentsheet.api | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/payments-core/api/payments-core.api b/payments-core/api/payments-core.api index 905ce7b6fba..225b763d6c1 100644 --- a/payments-core/api/payments-core.api +++ b/payments-core/api/payments-core.api @@ -5047,6 +5047,13 @@ public abstract class com/stripe/android/networking/StripeRequest { protected final fun getQuery ()Ljava/lang/String; } +public final class com/stripe/android/payments/PaymentFlowFailureMessageFactory { + public static final field $stable I + public fun (Landroid/content/Context;)V + public final fun create (Lcom/stripe/android/model/StripeIntent;)Ljava/lang/String; + public final fun create (Lcom/stripe/android/model/StripeIntent;I)Ljava/lang/String; +} + public abstract class com/stripe/android/payments/PaymentFlowResult { public static final field $stable I } @@ -5575,7 +5582,7 @@ public final class com/stripe/android/payments/paymentlauncher/PaymentResult$Fai public fun writeToParcel (Landroid/os/Parcel;I)V } -public final class com/stripe/android/payments/paymentlauncher/StripePaymentLauncher : com/stripe/android/payments/core/injection/Injector, com/stripe/android/payments/paymentlauncher/PaymentLauncher { +public class com/stripe/android/payments/paymentlauncher/StripePaymentLauncher : com/stripe/android/payments/core/injection/Injector, com/stripe/android/payments/paymentlauncher/PaymentLauncher { public static final field $stable I public fun confirm (Lcom/stripe/android/model/ConfirmPaymentIntentParams;)V public fun confirm (Lcom/stripe/android/model/ConfirmSetupIntentParams;)V diff --git a/paymentsheet/api/paymentsheet.api b/paymentsheet/api/paymentsheet.api index 108a6c201d6..2e0fc458475 100644 --- a/paymentsheet/api/paymentsheet.api +++ b/paymentsheet/api/paymentsheet.api @@ -271,11 +271,11 @@ public abstract interface class com/stripe/android/paymentsheet/PaymentSheetResu } public final class com/stripe/android/paymentsheet/PaymentSheetViewModel_Factory : dagger/internal/Factory { - public fun (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V - public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel_Factory; + public fun (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V + public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel_Factory; public fun get ()Lcom/stripe/android/paymentsheet/PaymentSheetViewModel; public synthetic fun get ()Ljava/lang/Object; - public static fun newInstance (Landroid/app/Application;Lcom/stripe/android/paymentsheet/PaymentSheetContract$Args;Lcom/stripe/android/paymentsheet/analytics/EventReporter;Ldagger/Lazy;Lcom/stripe/android/paymentsheet/repositories/StripeIntentRepository;Lcom/stripe/android/paymentsheet/model/StripeIntentValidator;Lcom/stripe/android/paymentsheet/repositories/CustomerRepository;Ljavax/inject/Provider;Lcom/stripe/android/paymentsheet/PrefsRepository;Lcom/stripe/android/PaymentController;Lcom/stripe/android/googlepaylauncher/GooglePayPaymentMethodLauncherFactory;Lcom/stripe/android/Logger;Lkotlin/coroutines/CoroutineContext;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel; + public static fun newInstance (Landroid/app/Application;Lcom/stripe/android/paymentsheet/PaymentSheetContract$Args;Lcom/stripe/android/paymentsheet/analytics/EventReporter;Ldagger/Lazy;Lcom/stripe/android/paymentsheet/repositories/StripeIntentRepository;Lcom/stripe/android/paymentsheet/model/StripeIntentValidator;Lcom/stripe/android/paymentsheet/repositories/CustomerRepository;Lcom/stripe/android/paymentsheet/PrefsRepository;Lcom/stripe/android/payments/paymentlauncher/StripePaymentLauncherAssistedFactory;Lcom/stripe/android/googlepaylauncher/GooglePayPaymentMethodLauncherFactory;Lcom/stripe/android/Logger;Lkotlin/coroutines/CoroutineContext;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel; } public final class com/stripe/android/paymentsheet/address/AddressFieldElementRepository_Factory : dagger/internal/Factory { From e7e4b30fc488378a69fd45f3e720a0e7bbb80e41 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 11:02:54 -0700 Subject: [PATCH 07/16] fix klint again --- .../com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt index 79973e1beca..97c85cfee14 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt @@ -14,7 +14,6 @@ import com.stripe.android.Logger import com.stripe.android.PaymentConfiguration import com.stripe.android.PaymentController import com.stripe.android.PaymentIntentResult -import com.stripe.android.StripeIntentResult import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherFactory @@ -25,7 +24,6 @@ import com.stripe.android.model.PaymentIntentFixtures import com.stripe.android.model.PaymentMethod import com.stripe.android.model.PaymentMethodCreateParamsFixtures import com.stripe.android.model.PaymentMethodFixtures -import com.stripe.android.payments.PaymentFlowResult import com.stripe.android.payments.PaymentFlowResultProcessor import com.stripe.android.payments.core.injection.PUBLISHABLE_KEY import com.stripe.android.payments.core.injection.STRIPE_ACCOUNT_ID From c1c352599862fc93f0c4c69a6a70534b80a746f6 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 11:44:54 -0700 Subject: [PATCH 08/16] some clean up --- .../stripe/android/paymentsheet/PaymentSheetViewModel.kt | 1 - .../android/paymentsheet/PaymentSheetActivityTest.kt | 3 +-- .../android/paymentsheet/PaymentSheetViewModelTest.kt | 8 +++++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 55d9a8ef215..6adf14ebbdf 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -151,7 +151,6 @@ internal class PaymentSheetViewModel @Inject internal constructor( } } - @VisibleForTesting internal var paymentLauncher: PaymentLauncher? = null init { diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt index 97c85cfee14..8b4ab92b965 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt @@ -763,8 +763,7 @@ internal class PaymentSheetActivityTest { @Assisted(STRIPE_ACCOUNT_ID) stripeAccountId: () -> String?, hostActivityLauncher: ActivityResultLauncher ): StripePaymentLauncher { - val stripePaymentLauncher = mock() - return stripePaymentLauncher + return mock() } } diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt index fc90c9472b5..9dc6b3df12d 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt @@ -382,6 +382,10 @@ internal class PaymentSheetViewModelTest { @Test fun `onPaymentResult() should update ViewState and save preferences`() = testDispatcher.runBlockingTest { + val viewModel = createViewModel( + stripeIntentRepository = StripeIntentRepository.Static(PAYMENT_INTENT), + ) + val selection = PaymentSelection.Saved(PaymentMethodFixtures.CARD_PAYMENT_METHOD) viewModel.updateSelection(selection) @@ -419,9 +423,7 @@ internal class PaymentSheetViewModelTest { fun `onPaymentResult() should update ViewState and save new payment method`() = testDispatcher.runBlockingTest { val viewModel = createViewModel( - ARGS_CUSTOMER_WITH_GOOGLEPAY, - StripeIntentRepository.Static(PAYMENT_INTENT_WITH_PM), - FakeCustomerRepository(PAYMENT_METHODS) + stripeIntentRepository = StripeIntentRepository.Static(PAYMENT_INTENT_WITH_PM) ) val selection = PaymentSelection.New.Card( From 51992c5164de08c278682c50262c5d5244869f1f Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 15:44:34 -0700 Subject: [PATCH 09/16] use throwable message instead of removal internal from message factory class --- .../payments/PaymentFlowFailureMessageFactory.kt | 16 ++++------------ .../paymentsheet/PaymentSheetViewModel.kt | 6 ++++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt index e0ea93b5869..fc281892895 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt @@ -1,30 +1,22 @@ package com.stripe.android.payments import android.content.Context -import androidx.annotation.RestrictTo import com.stripe.android.R import com.stripe.android.StripeIntentResult import com.stripe.android.model.PaymentIntent import com.stripe.android.model.SetupIntent import com.stripe.android.model.StripeIntent -@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -class PaymentFlowFailureMessageFactory( +internal class PaymentFlowFailureMessageFactory( private val context: Context ) { fun create( intent: StripeIntent, @StripeIntentResult.Outcome outcome: Int - ) = when (outcome) { - StripeIntentResult.Outcome.TIMEDOUT -> { + ) = when { + outcome == StripeIntentResult.Outcome.TIMEDOUT -> { context.resources.getString(R.string.stripe_failure_reason_timed_out) } - else -> create(intent) - } - - fun create( - intent: StripeIntent, - ) = when { (intent.status == StripeIntent.Status.RequiresPaymentMethod) || (intent.status == StripeIntent.Status.RequiresAction) -> { when (intent) { @@ -69,4 +61,4 @@ class PaymentFlowFailureMessageFactory( null } } -} +} \ No newline at end of file diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 6adf14ebbdf..b1702e37774 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -24,7 +24,6 @@ import com.stripe.android.model.ConfirmStripeIntentParams import com.stripe.android.model.PaymentIntent import com.stripe.android.model.PaymentMethod import com.stripe.android.model.StripeIntent -import com.stripe.android.payments.PaymentFlowFailureMessageFactory import com.stripe.android.payments.core.injection.IOContext import com.stripe.android.payments.paymentlauncher.PaymentLauncher import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract @@ -369,7 +368,10 @@ internal class PaymentSheetViewModel @Inject internal constructor( }.fold( onSuccess = { resetViewState( - PaymentFlowFailureMessageFactory(getApplication()).create(stripeIntent) + when (paymentResult) { + is PaymentResult.Failed -> paymentResult.throwable.message + else -> "" //indicates canceled payment + } ) }, onFailure = ::onFatal From adadcc56fd3fc120e834483d4a9afcdf11ab8875 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 15:49:41 -0700 Subject: [PATCH 10/16] use already retrieved stripe intent instead of fetching --- .../com/stripe/android/paymentsheet/PaymentSheetViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index b1702e37774..8c0f8395725 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -329,7 +329,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( fun onPaymentResult(paymentResult: PaymentResult) { viewModelScope.launch { runCatching { - stripeIntentRepository.get(args.clientSecret) + stripeIntentValidator.requireValid(stripeIntent.value!!) }.fold( onSuccess = { processPayment(it, paymentResult) From 624b602d698914c8015b0bbac3771453e562de17 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 15:55:59 -0700 Subject: [PATCH 11/16] close payment launcher again --- .../paymentlauncher/StripePaymentLauncher.kt | 2 +- .../paymentsheet/PaymentSheetActivityTest.kt | 18 +----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt b/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt index 20d3d693329..583bcaad86f 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/paymentlauncher/StripePaymentLauncher.kt @@ -28,7 +28,7 @@ import kotlin.coroutines.CoroutineContext * handle next actions for intents. */ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -open class StripePaymentLauncher @AssistedInject internal constructor( +class StripePaymentLauncher @AssistedInject internal constructor( @Assisted(PUBLISHABLE_KEY) publishableKeyProvider: () -> String, @Assisted(STRIPE_ACCOUNT_ID) stripeAccountIdProvider: () -> String?, @Assisted private val hostActivityLauncher: ActivityResultLauncher, diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt index 8b4ab92b965..77f9255c2c5 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetActivityTest.kt @@ -25,11 +25,7 @@ import com.stripe.android.model.PaymentMethod import com.stripe.android.model.PaymentMethodCreateParamsFixtures import com.stripe.android.model.PaymentMethodFixtures import com.stripe.android.payments.PaymentFlowResultProcessor -import com.stripe.android.payments.core.injection.PUBLISHABLE_KEY -import com.stripe.android.payments.core.injection.STRIPE_ACCOUNT_ID -import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract import com.stripe.android.payments.paymentlauncher.PaymentResult -import com.stripe.android.payments.paymentlauncher.StripePaymentLauncher import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory import com.stripe.android.paymentsheet.PaymentSheetViewModel.CheckoutIdentifier import com.stripe.android.paymentsheet.analytics.EventReporter @@ -48,7 +44,6 @@ import com.stripe.android.utils.TestUtils.idleLooper import com.stripe.android.utils.TestUtils.viewModelFactoryFor import com.stripe.android.utils.injectableActivityScenario import com.stripe.android.view.ActivityScenarioFactory -import dagger.assisted.Assisted import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -79,7 +74,7 @@ internal class PaymentSheetActivityTest { private val googlePayPaymentMethodLauncherFactory = createGooglePayPaymentMethodLauncherFactory() private val stripePaymentLauncherAssistedFactory = - stripePaymentLauncherAssistedFactory() + mock() private val viewModel = createViewModel() @@ -756,17 +751,6 @@ internal class PaymentSheetActivityTest { } } - private fun stripePaymentLauncherAssistedFactory() = - object : StripePaymentLauncherAssistedFactory { - override fun create( - @Assisted(PUBLISHABLE_KEY) publishableKey: () -> String, - @Assisted(STRIPE_ACCOUNT_ID) stripeAccountId: () -> String?, - hostActivityLauncher: ActivityResultLauncher - ): StripePaymentLauncher { - return mock() - } - } - private companion object { private val PAYMENT_INTENT = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD private val PAYMENT_METHODS = listOf(PaymentMethodFixtures.CARD_PAYMENT_METHOD) From 3c2adea9c9739e0d77125e0813dea596d8dc6905 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Thu, 2 Sep 2021 15:59:20 -0700 Subject: [PATCH 12/16] linter fixes --- .../stripe/android/payments/PaymentFlowFailureMessageFactory.kt | 2 +- .../com/stripe/android/paymentsheet/PaymentSheetViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt index fc281892895..59925721dc9 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/PaymentFlowFailureMessageFactory.kt @@ -61,4 +61,4 @@ internal class PaymentFlowFailureMessageFactory( null } } -} \ No newline at end of file +} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 8c0f8395725..39a10662786 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -370,7 +370,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( resetViewState( when (paymentResult) { is PaymentResult.Failed -> paymentResult.throwable.message - else -> "" //indicates canceled payment + else -> "" // indicates canceled payment } ) }, From 90b242c18d9d0a7ab9fc3867976999decfc9e3dd Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Fri, 3 Sep 2021 11:17:04 -0700 Subject: [PATCH 13/16] continue refetching stripe intent --- .../com/stripe/android/paymentsheet/PaymentSheetViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index 39a10662786..d322d5bf7e7 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -329,7 +329,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( fun onPaymentResult(paymentResult: PaymentResult) { viewModelScope.launch { runCatching { - stripeIntentValidator.requireValid(stripeIntent.value!!) + stripeIntentRepository.get(args.clientSecret) }.fold( onSuccess = { processPayment(it, paymentResult) From fb76f58e12f1724b9e51d0d7649b0db6e89bdf5a Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Fri, 3 Sep 2021 11:22:32 -0700 Subject: [PATCH 14/16] update unit tests to reflect new api --- .../paymentsheet/PaymentSheetViewModelTest.kt | 51 ++----------------- 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt index 9dc6b3df12d..28086712cdf 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetViewModelTest.kt @@ -487,55 +487,9 @@ internal class PaymentSheetViewModelTest { assertThat(stripeIntent).isNull() } - @Test - fun `onPaymentResult() with processing status for payment method which has delay should report success event`() = - testDispatcher.runBlockingTest { - val paymentIntent = PaymentIntentFixtures.PI_WITH_SHIPPING.copy( - paymentMethod = PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD, - status = StripeIntent.Status.Processing - ) - - val viewModel = createViewModel( - stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), - ) - - val selection = PaymentSelection.Saved(PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD) - viewModel.updateSelection(selection) - - viewModel.onPaymentResult(PaymentResult.Completed) - - verify(eventReporter) - .onPaymentSuccess(selection) - } - - @Test - fun `onPaymentResult() with processing status for payment method which does not have delay should report failure event`() = - testDispatcher.runBlockingTest { - val paymentIntent = PaymentIntentFixtures.PI_WITH_SHIPPING.copy( - paymentMethod = PaymentMethodFixtures.CARD_PAYMENT_METHOD, - status = StripeIntent.Status.Processing - ) - - val viewModel = createViewModel( - stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), - ) - - val selection = PaymentSelection.Saved(PaymentMethodFixtures.CARD_PAYMENT_METHOD) - viewModel.updateSelection(selection) - - viewModel.onPaymentResult(PaymentResult.Failed(Throwable())) - verify(eventReporter) - .onPaymentFailure(selection) - } - @Test fun `onPaymentResult() should update emit API errors`() = testDispatcher.runBlockingTest { - val paymentIntent = PaymentIntentFixtures.PI_WITH_LAST_PAYMENT_ERROR - val viewModel = createViewModel( - stripeIntentRepository = StripeIntentRepository.Static(paymentIntent), - ) - viewModel.fetchStripeIntent() val viewStateList = mutableListOf() @@ -543,7 +497,8 @@ internal class PaymentSheetViewModelTest { viewStateList.add(it) } - viewModel.onPaymentResult(PaymentResult.Failed(Throwable())) + val errorMessage = "very helpful error message" + viewModel.onPaymentResult(PaymentResult.Failed(Throwable(errorMessage))) assertThat(viewStateList[0]) .isEqualTo( @@ -552,7 +507,7 @@ internal class PaymentSheetViewModelTest { assertThat(viewStateList[1]) .isEqualTo( PaymentSheetViewState.Reset( - UserErrorMessage(application.resources.getString(R.string.stripe_failure_reason_authentication)) + UserErrorMessage(errorMessage) ) ) } From f60fdeda0afd67312aec94716c70571a056e053e Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Fri, 3 Sep 2021 11:50:19 -0700 Subject: [PATCH 15/16] fix apicheck --- payments-core/api/payments-core.api | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/payments-core/api/payments-core.api b/payments-core/api/payments-core.api index 225b763d6c1..905ce7b6fba 100644 --- a/payments-core/api/payments-core.api +++ b/payments-core/api/payments-core.api @@ -5047,13 +5047,6 @@ public abstract class com/stripe/android/networking/StripeRequest { protected final fun getQuery ()Ljava/lang/String; } -public final class com/stripe/android/payments/PaymentFlowFailureMessageFactory { - public static final field $stable I - public fun (Landroid/content/Context;)V - public final fun create (Lcom/stripe/android/model/StripeIntent;)Ljava/lang/String; - public final fun create (Lcom/stripe/android/model/StripeIntent;I)Ljava/lang/String; -} - public abstract class com/stripe/android/payments/PaymentFlowResult { public static final field $stable I } @@ -5582,7 +5575,7 @@ public final class com/stripe/android/payments/paymentlauncher/PaymentResult$Fai public fun writeToParcel (Landroid/os/Parcel;I)V } -public class com/stripe/android/payments/paymentlauncher/StripePaymentLauncher : com/stripe/android/payments/core/injection/Injector, com/stripe/android/payments/paymentlauncher/PaymentLauncher { +public final class com/stripe/android/payments/paymentlauncher/StripePaymentLauncher : com/stripe/android/payments/core/injection/Injector, com/stripe/android/payments/paymentlauncher/PaymentLauncher { public static final field $stable I public fun confirm (Lcom/stripe/android/model/ConfirmPaymentIntentParams;)V public fun confirm (Lcom/stripe/android/model/ConfirmSetupIntentParams;)V From 1703bef6d382a02819bebae65cd66be7e6658e81 Mon Sep 17 00:00:00 2001 From: Skyler Reimer Date: Fri, 3 Sep 2021 13:25:00 -0700 Subject: [PATCH 16/16] added some null checks --- .../paymentsheet/PaymentSheetViewModel.kt | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt index d322d5bf7e7..e0446e75786 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -286,14 +286,21 @@ internal class PaymentSheetViewModel @Inject internal constructor( } fun confirmStripeIntent(confirmStripeIntentParams: ConfirmStripeIntentParams) { - when (confirmStripeIntentParams) { - is ConfirmPaymentIntentParams -> { - paymentLauncher?.confirm(confirmStripeIntentParams) - } - is ConfirmSetupIntentParams -> { - paymentLauncher?.confirm(confirmStripeIntentParams) - } - } + runCatching { + requireNotNull(paymentLauncher) + }.fold( + onSuccess = { + when (confirmStripeIntentParams) { + is ConfirmPaymentIntentParams -> { + it.confirm(confirmStripeIntentParams) + } + is ConfirmSetupIntentParams -> { + it.confirm(confirmStripeIntentParams) + } + } + }, + onFailure = ::onFatal + ) } fun registerFromActivity(activityResultCaller: ActivityResultCaller) { @@ -370,7 +377,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( resetViewState( when (paymentResult) { is PaymentResult.Failed -> paymentResult.throwable.message - else -> "" // indicates canceled payment + else -> null // indicates canceled payment } ) },