Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
toluo-stripe committed Feb 7, 2025
1 parent 6479718 commit 36040cb
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ private fun MenuAndLoader(
) {
if (isUpdating) {
CircularProgressIndicator(
modifier = Modifier.size(24.dp),
modifier = Modifier
.testTag(WALLET_PAYMENT_DETAIL_ITEM_LOADING_INDICATOR)
.size(24.dp),
strokeWidth = 2.dp
)
} else {
Expand Down Expand Up @@ -262,3 +264,4 @@ private fun RowScope.BankAccountInfo(

internal const val WALLET_PAYMENT_DETAIL_ITEM_RADIO_BUTTON = "wallet_payment_detail_item_radio_button"
internal const val WALLET_PAYMENT_DETAIL_ITEM_MENU_BUTTON = "wallet_payment_detail_item_menu_button"
internal const val WALLET_PAYMENT_DETAIL_ITEM_LOADING_INDICATOR = "wallet_payment_detail_item_loading_indicator"
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,21 @@ import com.stripe.android.link.ui.PrimaryButtonState
import com.stripe.android.link.ui.PrimaryButtonTag
import com.stripe.android.model.CardBrand
import com.stripe.android.model.ConsumerPaymentDetails
import com.stripe.android.model.ConsumerPaymentDetailsUpdateParams
import com.stripe.android.model.CvcCheck
import com.stripe.android.testing.CoroutineTestRule
import com.stripe.android.testing.FakeLogger
import com.stripe.android.ui.core.elements.CvcController
import com.stripe.android.uicore.elements.DateConfig
import com.stripe.android.uicore.elements.SimpleTextFieldController
import com.stripe.android.uicore.utils.stateFlowOf
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.time.Duration.Companion.seconds
import com.stripe.android.link.confirmation.Result as LinkConfirmationResult

@RunWith(AndroidJUnit4::class)
Expand Down Expand Up @@ -480,6 +483,47 @@ internal class WalletScreenTest {
onWalletPaymentMethodMenu().assertIsDisplayed()
}

@Test
fun `pay method row is loading when card is being updated`() = runTest(dispatcher) {
val validCard = TestFactory.CONSUMER_PAYMENT_DETAILS_CARD.copy(
expiryYear = 2099,
cvcCheck = CvcCheck.Pass
)
val linkAccountManager = object : FakeLinkAccountManager() {
override suspend fun updatePaymentDetails(
updateParams: ConsumerPaymentDetailsUpdateParams
): Result<ConsumerPaymentDetails> {
delay(1.seconds)
return super.updatePaymentDetails(updateParams)
}
}
linkAccountManager.listPaymentDetailsResult = Result.success(
ConsumerPaymentDetails(paymentDetails = listOf(validCard))
)
val viewModel = createViewModel(linkAccountManager)
composeTestRule.setContent {
WalletScreen(
viewModel = viewModel,
showBottomSheetContent = {},
hideBottomSheetContent = {}
)
}
composeTestRule.waitForIdle()

onWalletPayButton().assertIsEnabled()

viewModel.onSetDefaultClicked(validCard)
composeTestRule.waitForIdle()

onWalletPaymentMethodRowLoadingIndicator().assertIsDisplayed()
onWalletPayButton().assertIsNotEnabled()

dispatcher.scheduler.advanceTimeBy(1.1.seconds)

onWalletPaymentMethodRowLoadingIndicator().assertDoesNotExist()
onWalletPayButton().assertExists()
}

@Test
fun `wallet menu is dismissed on cancel clicked`() = runTest(dispatcher) {
testMenu(
Expand Down Expand Up @@ -653,6 +697,9 @@ internal class WalletScreenTest {
private fun onWalletPaymentMethodRowMenuButton() =
composeTestRule.onAllNodes(hasTestTag(WALLET_PAYMENT_DETAIL_ITEM_MENU_BUTTON), useUnmergedTree = true)

private fun onWalletPaymentMethodRowLoadingIndicator() =
composeTestRule.onNodeWithTag(WALLET_PAYMENT_DETAIL_ITEM_LOADING_INDICATOR, useUnmergedTree = true)

private fun onWalletPaymentMethodMenu() =
composeTestRule.onNodeWithTag(WALLET_SCREEN_MENU_SHEET_TAG, useUnmergedTree = true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ class WalletUiStateTest {
assertThat(state.primaryButtonState).isEqualTo(PrimaryButtonState.Enabled)
}

@Test
fun testDisabledButtonStateWhenCardIsBeingUpdated() {
val state = walletUiState(
selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS_CARD,
cardBeingUpdated = "id"
)

assertThat(state.primaryButtonState).isEqualTo(PrimaryButtonState.Disabled)
}

private fun walletUiState(
paymentDetailsList: List<ConsumerPaymentDetails.PaymentDetails> =
TestFactory.CONSUMER_PAYMENT_DETAILS.paymentDetails,
Expand All @@ -155,7 +165,8 @@ class WalletUiStateTest {
isProcessing: Boolean = false,
primaryButtonLabel: ResolvableString = LINK_WALLET_PRIMARY_BUTTON_LABEL,
expiryDateInput: FormFieldEntry = FormFieldEntry(null),
cvcInput: FormFieldEntry = FormFieldEntry(null)
cvcInput: FormFieldEntry = FormFieldEntry(null),
cardBeingUpdated: String? = null
): WalletUiState {
return WalletUiState(
paymentDetailsList = paymentDetailsList,
Expand All @@ -164,7 +175,8 @@ class WalletUiStateTest {
isProcessing = isProcessing,
primaryButtonLabel = primaryButtonLabel,
expiryDateInput = expiryDateInput,
cvcInput = cvcInput
cvcInput = cvcInput,
cardBeingUpdated = cardBeingUpdated
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.stripe.android.model.ConsumerPaymentDetailsUpdateParams
import com.stripe.android.testing.CoroutineTestRule
import com.stripe.android.testing.FakeLogger
import com.stripe.android.uicore.forms.FormFieldEntry
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
Expand All @@ -24,6 +25,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import kotlin.Result
import kotlin.time.Duration.Companion.seconds
import com.stripe.android.link.confirmation.Result as LinkConfirmationResult

@RunWith(RobolectricTestRunner::class)
Expand Down Expand Up @@ -373,7 +375,14 @@ class WalletViewModelTest {
fun `onSetDefaultClicked updates payment method as default successfully`() = runTest(dispatcher) {
val card1 = TestFactory.CONSUMER_PAYMENT_DETAILS_CARD.copy(id = "card1", isDefault = false)
val card2 = TestFactory.CONSUMER_PAYMENT_DETAILS_CARD.copy(id = "card2", isDefault = true)
val linkAccountManager = WalletLinkAccountManager()
val linkAccountManager = object : WalletLinkAccountManager() {
override suspend fun updatePaymentDetails(
updateParams: ConsumerPaymentDetailsUpdateParams
): Result<ConsumerPaymentDetails> {
delay(1.seconds)
return super.updatePaymentDetails(updateParams)
}
}
linkAccountManager.listPaymentDetailsResult = Result.success(
ConsumerPaymentDetails(paymentDetails = listOf(card1, card2))
)
Expand All @@ -392,17 +401,21 @@ class WalletViewModelTest {

viewModel.onSetDefaultClicked(card1)

assertThat(viewModel.uiState.value.cardBeingUpdated).isEqualTo(card1.id)

dispatcher.scheduler.advanceTimeBy(1.1.seconds)

assertThat(linkAccountManager.updatePaymentDetailsCalls).containsExactly(
ConsumerPaymentDetailsUpdateParams(
id = "card1",
isDefault = true,
cardPaymentMethodCreateParamsMap = null
)
)

assertThat(viewModel.uiState.value.paymentDetailsList).containsExactly(updatedCard1, updatedCard2)
assertThat(linkAccountManager.listPaymentDetailsCalls.size).isEqualTo(2)
assertThat(viewModel.uiState.value.isProcessing).isFalse()
assertThat(viewModel.uiState.value.cardBeingUpdated).isNull()
assertThat(viewModel.uiState.value.alertMessage).isNull()
}

Expand All @@ -425,6 +438,7 @@ class WalletViewModelTest {
viewModel.onSetDefaultClicked(card)

assertThat(viewModel.uiState.value.isProcessing).isFalse()
assertThat(viewModel.uiState.value.cardBeingUpdated).isNull()
assertThat(viewModel.uiState.value.alertMessage).isEqualTo(error.stripeErrorMessage())
assertThat(logger.errorLogs).contains("WalletViewModel: Failed to set payment method as default" to error)
}
Expand Down Expand Up @@ -499,7 +513,7 @@ class WalletViewModelTest {
}
}

private class WalletLinkAccountManager : FakeLinkAccountManager() {
private open class WalletLinkAccountManager : FakeLinkAccountManager() {
val listPaymentDetailsCalls = arrayListOf<Set<String>>()
val updatePaymentDetailsCalls = arrayListOf<ConsumerPaymentDetailsUpdateParams>()
val deletePaymentDetailsCalls = arrayListOf<String>()
Expand Down

0 comments on commit 36040cb

Please sign in to comment.