Skip to content

Commit

Permalink
Update DefaultEmbeddedSelectionChooser to keep the previousConfigurat…
Browse files Browse the repository at this point in the history
…ion. (#10028)
  • Loading branch information
jaynewstrom-stripe authored Jan 29, 2025
1 parent 70cf2cd commit 40f6ce8
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

package com.stripe.android.paymentelement.embedded

import com.stripe.android.common.model.asCommonConfiguration
import androidx.lifecycle.SavedStateHandle
import com.stripe.android.common.model.CommonConfiguration
import com.stripe.android.common.model.containsVolatileDifferences
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.model.PaymentMethod
import com.stripe.android.paymentelement.EmbeddedPaymentElement
import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi
import com.stripe.android.paymentsheet.model.PaymentSelection
import javax.inject.Inject
Expand All @@ -18,29 +18,35 @@ internal fun interface EmbeddedSelectionChooser {
paymentMethods: List<PaymentMethod>?,
previousSelection: PaymentSelection?,
newSelection: PaymentSelection?,
previousConfiguration: EmbeddedPaymentElement.Configuration?,
newConfiguration: EmbeddedPaymentElement.Configuration,
newConfiguration: CommonConfiguration,
): PaymentSelection?
}

internal class DefaultEmbeddedSelectionChooser @Inject constructor() : EmbeddedSelectionChooser {
internal class DefaultEmbeddedSelectionChooser @Inject constructor(
private val savedStateHandle: SavedStateHandle,
) : EmbeddedSelectionChooser {
private var previousConfiguration: CommonConfiguration?
get() = savedStateHandle[PREVIOUS_CONFIGURATION_KEY]
set(value) = savedStateHandle.set(PREVIOUS_CONFIGURATION_KEY, value)

override fun choose(
paymentMethodMetadata: PaymentMethodMetadata,
paymentMethods: List<PaymentMethod>?,
previousSelection: PaymentSelection?,
newSelection: PaymentSelection?,
previousConfiguration: EmbeddedPaymentElement.Configuration?,
newConfiguration: EmbeddedPaymentElement.Configuration,
newConfiguration: CommonConfiguration,
): PaymentSelection? {
return previousSelection?.takeIf { selection ->
val result = previousSelection?.takeIf { selection ->
canUseSelection(
paymentMethodMetadata = paymentMethodMetadata,
paymentMethods = paymentMethods,
selection = selection,
) && previousConfiguration?.asCommonConfiguration()?.containsVolatileDifferences(
newConfiguration.asCommonConfiguration()
) != true
) && previousConfiguration?.containsVolatileDifferences(newConfiguration) != true
} ?: newSelection

previousConfiguration = newConfiguration

return result
}

private fun canUseSelection(
Expand Down Expand Up @@ -72,4 +78,8 @@ internal class DefaultEmbeddedSelectionChooser @Inject constructor() : EmbeddedS
}
}
}

companion object {
const val PREVIOUS_CONFIGURATION_KEY = "DefaultEmbeddedSelectionChooser_PREVIOUS_CONFIGURATION_KEY"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import com.stripe.android.cards.CardAccountRangeRepository
import com.stripe.android.cards.DefaultCardAccountRangeRepositoryFactory
import com.stripe.android.common.model.asCommonConfiguration
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.utils.RealUserFacingLogger
import com.stripe.android.core.utils.UserFacingLogger
Expand Down Expand Up @@ -126,7 +127,6 @@ internal class SharedPaymentElementViewModel @Inject constructor(
intentConfiguration: PaymentSheet.IntentConfiguration,
configuration: EmbeddedPaymentElement.Configuration,
) {
val previousConfiguration = confirmationStateHolder.state?.configuration
confirmationStateHolder.state = EmbeddedConfirmationStateHolder.State(
paymentMethodMetadata = state.paymentMethodMetadata,
selection = state.paymentSelection,
Expand All @@ -142,8 +142,7 @@ internal class SharedPaymentElementViewModel @Inject constructor(
paymentMethods = state.customer?.paymentMethods,
previousSelection = selectionHolder.selection.value,
newSelection = state.paymentSelection,
previousConfiguration = previousConfiguration,
newConfiguration = configuration,
newConfiguration = configuration.asCommonConfiguration(),
)
)
embeddedContentHelper.dataLoaded(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.stripe.android.paymentelement.embedded

import androidx.lifecycle.SavedStateHandle
import com.google.common.truth.Truth.assertThat
import com.stripe.android.common.model.CommonConfiguration
import com.stripe.android.common.model.asCommonConfiguration
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.model.PaymentMethodCreateParamsFixtures
import com.stripe.android.model.PaymentMethodFixtures
import com.stripe.android.paymentelement.EmbeddedPaymentElement
import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi
import com.stripe.android.paymentelement.embedded.DefaultEmbeddedSelectionChooser.Companion.PREVIOUS_CONFIGURATION_KEY
import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.model.PaymentSelection
import com.stripe.android.testing.PaymentMethodFactory
Expand All @@ -16,15 +20,18 @@ import com.stripe.android.ui.core.R as StripeUiCoreR

@OptIn(ExperimentalEmbeddedPaymentElementApi::class)
internal class DefaultEmbeddedSelectionChooserTest {
private val defaultConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.")
.build()
.asCommonConfiguration()

@Test
fun `Uses new payment selection if there's no existing one`() = runScenario {
val selection = chooser.choose(
paymentMethodMetadata = PaymentMethodMetadataFactory.create(isGooglePayReady = true),
paymentMethods = null,
previousSelection = null,
newSelection = PaymentSelection.GooglePay,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(PaymentSelection.GooglePay)
}
Expand All @@ -51,8 +58,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3) + paymentMethod,
previousSelection = previousSelection,
newSelection = newSelection,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(previousSelection)
}
Expand All @@ -67,8 +73,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3) + paymentMethod,
previousSelection = previousSelection,
newSelection = PaymentSelection.GooglePay,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(previousSelection)
}
Expand All @@ -82,8 +87,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3) + PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD,
previousSelection = previousSelection,
newSelection = null,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isNull()
}
Expand All @@ -101,8 +105,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3),
previousSelection = previousSelection,
newSelection = null,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isNull()
}
Expand All @@ -120,8 +123,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3),
previousSelection = previousSelection,
newSelection = PaymentSelection.GooglePay,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(previousSelection)
}
Expand All @@ -138,8 +140,7 @@ internal class DefaultEmbeddedSelectionChooserTest {
paymentMethods = PaymentMethodFixtures.createCards(3),
previousSelection = previousSelection,
newSelection = null,
previousConfiguration = null,
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isNull()
}
Expand All @@ -150,14 +151,13 @@ internal class DefaultEmbeddedSelectionChooserTest {
val paymentMethod = PaymentMethodFixtures.createCard()
val newSelection = PaymentSelection.Saved(paymentMethod)

savedStateHandle[PREVIOUS_CONFIGURATION_KEY] = defaultConfiguration.copy(merchantDisplayName = "Hi")
val selection = chooser.choose(
paymentMethodMetadata = PaymentMethodMetadataFactory.create(isGooglePayReady = true),
paymentMethods = PaymentMethodFixtures.createCards(3) + paymentMethod,
previousSelection = previousSelection,
newSelection = newSelection,
previousConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.")
.embeddedViewDisplaysMandateText(false).build(),
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(previousSelection)
}
Expand All @@ -168,25 +168,50 @@ internal class DefaultEmbeddedSelectionChooserTest {
val paymentMethod = PaymentMethodFixtures.createCard()
val newSelection = PaymentSelection.Saved(paymentMethod)

savedStateHandle[PREVIOUS_CONFIGURATION_KEY] = defaultConfiguration.copy(
defaultBillingDetails = PaymentSheet.BillingDetails(email = "[email protected]")
)
val selection = chooser.choose(
paymentMethodMetadata = PaymentMethodMetadataFactory.create(isGooglePayReady = true),
paymentMethods = PaymentMethodFixtures.createCards(3) + paymentMethod,
previousSelection = previousSelection,
newSelection = newSelection,
previousConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.")
.defaultBillingDetails(PaymentSheet.BillingDetails(email = "[email protected]")).build(),
newConfiguration = EmbeddedPaymentElement.Configuration.Builder("Example, Inc.").build(),
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(newSelection)
}

@Test
fun `previousConfig is set when calling choose`() = runScenario {
val previousSelection = PaymentSelection.GooglePay
val paymentMethod = PaymentMethodFixtures.createCard()
val newSelection = PaymentSelection.Saved(paymentMethod)

assertThat(savedStateHandle.get<CommonConfiguration>(PREVIOUS_CONFIGURATION_KEY)).isNull()
val selection = chooser.choose(
paymentMethodMetadata = PaymentMethodMetadataFactory.create(isGooglePayReady = true),
paymentMethods = PaymentMethodFixtures.createCards(3) + paymentMethod,
previousSelection = previousSelection,
newSelection = newSelection,
newConfiguration = defaultConfiguration,
)
assertThat(selection).isEqualTo(previousSelection)
assertThat(savedStateHandle.get<CommonConfiguration>(PREVIOUS_CONFIGURATION_KEY))
.isEqualTo(defaultConfiguration)
}

private fun runScenario(
block: Scenario.() -> Unit,
) {
Scenario(DefaultEmbeddedSelectionChooser()).block()
val savedStateHandle = SavedStateHandle()
Scenario(
chooser = DefaultEmbeddedSelectionChooser(savedStateHandle),
savedStateHandle = savedStateHandle,
).block()
}

private class Scenario(
val chooser: EmbeddedSelectionChooser,
val savedStateHandle: SavedStateHandle,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ internal class SharedPaymentElementViewModelTest {
configurationHandler = configurationHandler,
paymentOptionDisplayDataFactory = paymentOptionDisplayDataFactory,
selectionHolder = selectionHolder,
selectionChooser = { _, _, _, newSelection, _, _ ->
selectionChooser = { _, _, _, newSelection, _ ->
newSelection
},
customerStateHolder = customerStateHolder,
Expand Down

0 comments on commit 40f6ce8

Please sign in to comment.