From a99222940460a93a16c4097eb23ad82901497a2d Mon Sep 17 00:00:00 2001 From: Jay Newstrom Date: Thu, 18 Apr 2024 11:55:40 -0600 Subject: [PATCH] Make things that do work happen on the work context in view models. (#8297) --- paymentsheet/detekt-baseline.xml | 2 +- .../paymentsheet/utils/CustomerSheetTestRunner.kt | 1 - .../customersheet/CustomerSheetViewModel.kt | 14 +++++++------- .../android/paymentsheet/PaymentSheetViewModel.kt | 6 +++--- .../paymentsheet/viewmodels/BaseSheetViewModel.kt | 6 +++--- .../paymentsheet/PaymentOptionsViewModelTest.kt | 8 +++++++- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/paymentsheet/detekt-baseline.xml b/paymentsheet/detekt-baseline.xml index 68dcf1717d2..ccfec2c7c33 100644 --- a/paymentsheet/detekt-baseline.xml +++ b/paymentsheet/detekt-baseline.xml @@ -16,6 +16,7 @@ LargeClass:CustomerSheetViewModelTest.kt$CustomerSheetViewModelTest LargeClass:DefaultFlowControllerTest.kt$DefaultFlowControllerTest LargeClass:DefaultPaymentSheetLoaderTest.kt$DefaultPaymentSheetLoaderTest + LargeClass:PaymentOptionsViewModelTest.kt$PaymentOptionsViewModelTest LargeClass:PaymentSheetActivityTest.kt$PaymentSheetActivityTest LargeClass:PaymentSheetViewModel.kt$PaymentSheetViewModel : BaseSheetViewModel LargeClass:PaymentSheetViewModelTest.kt$PaymentSheetViewModelTest @@ -35,7 +36,6 @@ LongMethod:USBankAccountForm.kt$@Composable internal fun BillingDetailsForm( instantDebits: Boolean, formArgs: FormArguments, isProcessing: Boolean, isPaymentFlow: Boolean, nameController: TextFieldController, emailController: TextFieldController, phoneController: PhoneNumberController, addressController: AddressController, lastTextFieldIdentifier: IdentifierSpec?, sameAsShippingElement: SameAsShippingElement?, ) LongMethod:USBankAccountForm.kt$@Composable internal fun USBankAccountForm( formArgs: FormArguments, usBankAccountFormArgs: USBankAccountFormArguments, modifier: Modifier = Modifier, ) LongMethod:USBankAccountForm.kt$@Composable private fun AccountDetailsForm( showCheckbox: Boolean, isProcessing: Boolean, bankName: String?, last4: String?, saveForFutureUseElement: SaveForFutureUseElement, onRemoveAccount: () -> Unit, ) - LongMethod:USBankAccountFormViewModelTest.kt$USBankAccountFormViewModelTest$@Test fun `Restores screen state when re-opening screen`() MagicNumber:AutocompleteScreen.kt$0.07f MagicNumber:BaseSheetActivity.kt$BaseSheetActivity$30 MagicNumber:BottomSheet.kt$BottomSheetState$10 diff --git a/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/CustomerSheetTestRunner.kt b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/CustomerSheetTestRunner.kt index c53cd9aeb19..9198d241fa0 100644 --- a/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/CustomerSheetTestRunner.kt +++ b/paymentsheet/src/androidTest/java/com/stripe/android/paymentsheet/utils/CustomerSheetTestRunner.kt @@ -12,7 +12,6 @@ import com.stripe.android.customersheet.CustomerSheetResultCallback import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.link.account.LinkStore import com.stripe.android.paymentsheet.MainActivity -import java.lang.IllegalStateException import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit diff --git a/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheetViewModel.kt index 7cf3af09699..bf1509c038a 100644 --- a/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheetViewModel.kt @@ -158,7 +158,7 @@ internal class CustomerSheetViewModel( configuration.appearance.parseAppearance() if (viewState.value is CustomerSheetViewState.Loading) { - viewModelScope.launch { + viewModelScope.launch(workContext) { loadCustomerSheetState() } } @@ -465,7 +465,7 @@ internal class CustomerSheetViewModel( } private fun onItemRemoved(paymentMethod: PaymentMethod) { - viewModelScope.launch { + viewModelScope.launch(workContext) { val result = removePaymentMethod(paymentMethod) result.fold( @@ -615,7 +615,7 @@ internal class CustomerSheetViewModel( } private fun removePaymentMethodFromState(paymentMethod: PaymentMethod) { - viewModelScope.launch { + viewModelScope.launch(workContext) { delay(PaymentMethodRemovalDelayMillis) val newSavedPaymentMethods = viewState.value.savedPaymentMethods - paymentMethod @@ -725,7 +725,7 @@ internal class CustomerSheetViewModel( private fun createAndAttach( paymentMethodCreateParams: PaymentMethodCreateParams, ) { - viewModelScope.launch { + viewModelScope.launch(workContext) { createPaymentMethod(paymentMethodCreateParams) .onSuccess { paymentMethod -> if (paymentMethod.isUnverifiedUSBankAccount()) { @@ -908,7 +908,7 @@ internal class CustomerSheetViewModel( } private fun attachPaymentMethodToCustomer(paymentMethod: PaymentMethod) { - viewModelScope.launch { + viewModelScope.launch(workContext) { if (awaitCustomerAdapter().canCreateSetupIntents) { attachWithSetupIntent(paymentMethod = paymentMethod) } else { @@ -1098,7 +1098,7 @@ internal class CustomerSheetViewModel( } private fun selectSavedPaymentMethod(savedPaymentSelection: PaymentSelection.Saved?) { - viewModelScope.launch { + viewModelScope.launch(workContext) { awaitCustomerAdapter().setSelectedPaymentOption( savedPaymentSelection?.toPaymentOption() ).onSuccess { @@ -1118,7 +1118,7 @@ internal class CustomerSheetViewModel( } private fun selectGooglePay() { - viewModelScope.launch { + viewModelScope.launch(workContext) { awaitCustomerAdapter().setSelectedPaymentOption(CustomerAdapter.PaymentOption.GooglePay) .onSuccess { confirmPaymentSelection( 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 6f0b98b5a34..be5a4a55c82 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetViewModel.kt @@ -273,7 +273,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( isDeferred = isDeferred, ) - viewModelScope.launch { + viewModelScope.launch(workContext) { loadPaymentSheetState() } } @@ -590,7 +590,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( } private fun confirmPaymentSelection(paymentSelection: PaymentSelection?) { - viewModelScope.launch { + viewModelScope.launch(workContext) { val stripeIntent = awaitStripeIntent() val nextStep = intentConfirmationInterceptor.intercept( @@ -622,7 +622,7 @@ internal class PaymentSheetViewModel @Inject internal constructor( } override fun onPaymentResult(paymentResult: PaymentResult) { - viewModelScope.launch { + viewModelScope.launch(workContext) { val stripeIntent = awaitStripeIntent() processPayment(stripeIntent, paymentResult) } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt index 2042428bade..9643b6a580d 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/viewmodels/BaseSheetViewModel.kt @@ -494,7 +494,7 @@ internal abstract class BaseSheetViewModel( fun removePaymentMethod(paymentMethod: PaymentMethod) { val paymentMethodId = paymentMethod.id ?: return - viewModelScope.launch { + viewModelScope.launch(workContext) { removeDeletedPaymentMethodFromState(paymentMethodId) removePaymentMethodInternal(paymentMethodId) } @@ -597,7 +597,7 @@ internal abstract class BaseSheetViewModel( val result = removePaymentMethodInternal(paymentMethodId) if (result.isSuccess) { - viewModelScope.launch { + viewModelScope.launch(workContext) { onUserBack() delay(PaymentMethodRemovalDelayMillis) removeDeletedPaymentMethodFromState(paymentMethodId = paymentMethodId) @@ -677,7 +677,7 @@ internal abstract class BaseSheetViewModel( abstract val shouldCompleteLinkFlowInline: Boolean private fun payWithLinkInline(userInput: UserInput?) { - viewModelScope.launch { + viewModelScope.launch(workContext) { linkHandler.payWithLinkInline( userInput = userInput, paymentSelection = selection.value, diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentOptionsViewModelTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentOptionsViewModelTest.kt index 24352a05ac1..7512ce4a182 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentOptionsViewModelTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentOptionsViewModelTest.kt @@ -45,6 +45,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.runner.RunWith @@ -70,7 +71,8 @@ internal class PaymentOptionsViewModelTest { private val customerRepository = mock() @Before - fun before() { + @After + fun resetMainDispatcher() { Dispatchers.resetMain() } @@ -180,6 +182,7 @@ internal class PaymentOptionsViewModelTest { ) viewModel.removePaymentMethod(cards[1]) + testDispatcher.scheduler.advanceUntilIdle() assertThat(viewModel.paymentMethods.value) .containsExactly(cards[0], cards[2]) @@ -197,6 +200,7 @@ internal class PaymentOptionsViewModelTest { assertThat(viewModel.selection.value).isEqualTo(selection) viewModel.removePaymentMethod(selection.paymentMethod) + testDispatcher.scheduler.advanceUntilIdle() assertThat(viewModel.selection.value).isNull() } @@ -211,6 +215,7 @@ internal class PaymentOptionsViewModelTest { ) viewModel.removePaymentMethod(paymentMethod) + testDispatcher.scheduler.advanceUntilIdle() assertThat(viewModel.paymentMethods.value).isEmpty() assertThat(viewModel.primaryButtonUiState.value).isNull() @@ -462,6 +467,7 @@ internal class PaymentOptionsViewModelTest { viewModel.paymentOptionResult.test { // Simulate user removing the selected payment method viewModel.removePaymentMethod(selection.paymentMethod) + testDispatcher.scheduler.advanceUntilIdle() viewModel.onUserCancel()