Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MOBILESDK-2681] [MOBILESDK-2682] Default Payment Method Label #9824

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,12 @@ internal class ElementsSessionJsonParser(
val customerSession = parseCustomerSession(json.optJSONObject(FIELD_CUSTOMER_SESSION))
?: return null

val defaultPaymentMethod = json.optString(FIELD_DEFAULT_PAYMENT_METHOD).takeIf {
it.isNotBlank()
val defaultPaymentMethod = if (FeatureFlags.defaultPaymentMethod.isEnabled) {
json.optString(FIELD_DEFAULT_PAYMENT_METHOD).takeIf {
it.isNotBlank()
}
} else {
null
}

return ElementsSession.Customer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ class ElementsSessionJsonParserTest {
isEnabled = false,
)

@get:Rule
val defaultPaymentMethodFeatureFlagRule = FeatureFlagTestRule(
featureFlag = FeatureFlags.defaultPaymentMethod,
isEnabled = true,
)

@Test
fun parsePaymentIntent_shouldCreateObjectWithOrderedPaymentMethods() {
val elementsSession = ElementsSessionJsonParser(
Expand Down Expand Up @@ -515,6 +521,55 @@ class ElementsSessionJsonParserTest {
assertThat(session?.externalPaymentMethodData).contains(venmo)
}

private val elementsSessionExpectedCustomerSession = ElementsSession.Customer.Session(
id = "cuss_123",
apiKey = "ek_test_1234",
apiKeyExpiry = 1713890664,
customerId = "cus_1",
liveMode = false,
components = ElementsSession.Customer.Components(
mobilePaymentElement = ElementsSession.Customer.Components.MobilePaymentElement.Enabled(
isPaymentMethodSaveEnabled = false,
isPaymentMethodRemoveEnabled = true,
canRemoveLastPaymentMethod = true,
allowRedisplayOverride = PaymentMethod.AllowRedisplay.LIMITED,
),
customerSheet = ElementsSession.Customer.Components.CustomerSheet.Enabled(
isPaymentMethodRemoveEnabled = true,
canRemoveLastPaymentMethod = true,
),
)
)

private val elementsSessionExpectedPaymentMethods = listOf(
PaymentMethod(
id = "pm_123",
customerId = "cus_1",
type = PaymentMethod.Type.Card,
code = "card",
created = 1550757934255,
liveMode = false,
billingDetails = null,
card = PaymentMethod.Card(
brand = CardBrand.Visa,
last4 = "4242",
expiryMonth = 8,
expiryYear = 2032,
country = "US",
funding = "credit",
fingerprint = "fingerprint123",
checks = PaymentMethod.Card.Checks(
addressLine1Check = "unchecked",
cvcCheck = "unchecked",
addressPostalCodeCheck = null,
),
threeDSecureUsage = PaymentMethod.Card.ThreeDSecureUsage(
isSupported = true
)
)
)
)

@Test
fun `ElementsSession has expected customer session information in the response`() {
val parser = ElementsSessionJsonParser(
Expand All @@ -531,54 +586,34 @@ class ElementsSessionJsonParserTest {

assertThat(elementsSession?.customer).isEqualTo(
ElementsSession.Customer(
session = ElementsSession.Customer.Session(
id = "cuss_123",
apiKey = "ek_test_1234",
apiKeyExpiry = 1713890664,
customerId = "cus_1",
liveMode = false,
components = ElementsSession.Customer.Components(
mobilePaymentElement = ElementsSession.Customer.Components.MobilePaymentElement.Enabled(
isPaymentMethodSaveEnabled = false,
isPaymentMethodRemoveEnabled = true,
canRemoveLastPaymentMethod = true,
allowRedisplayOverride = PaymentMethod.AllowRedisplay.LIMITED,
),
customerSheet = ElementsSession.Customer.Components.CustomerSheet.Enabled(
isPaymentMethodRemoveEnabled = true,
canRemoveLastPaymentMethod = true,
),
)
),
session = elementsSessionExpectedCustomerSession,
defaultPaymentMethod = "pm_123",
paymentMethods = listOf(
PaymentMethod(
id = "pm_123",
customerId = "cus_1",
type = PaymentMethod.Type.Card,
code = "card",
created = 1550757934255,
liveMode = false,
billingDetails = null,
card = PaymentMethod.Card(
brand = CardBrand.Visa,
last4 = "4242",
expiryMonth = 8,
expiryYear = 2032,
country = "US",
funding = "credit",
fingerprint = "fingerprint123",
checks = PaymentMethod.Card.Checks(
addressLine1Check = "unchecked",
cvcCheck = "unchecked",
addressPostalCodeCheck = null,
),
threeDSecureUsage = PaymentMethod.Card.ThreeDSecureUsage(
isSupported = true
)
)
)
)
paymentMethods = elementsSessionExpectedPaymentMethods
)
)
}

@Test
fun `ElementsSession has expected customer session information in the response when default disabled`() {
defaultPaymentMethodFeatureFlagRule.setEnabled(false)

val parser = ElementsSessionJsonParser(
ElementsSessionParams.PaymentIntentType(
clientSecret = "secret",
customerSessionClientSecret = "customer_session_client_secret",
externalPaymentMethods = emptyList(),
),
isLiveMode = false,
)

val intent = createPaymentIntentWithCustomerSession()
val elementsSession = parser.parse(intent)

assertThat(elementsSession?.customer).isEqualTo(
ElementsSession.Customer(
session = elementsSessionExpectedCustomerSession,
defaultPaymentMethod = null,
paymentMethods = elementsSessionExpectedPaymentMethods
)
)
}
Expand Down Expand Up @@ -694,34 +729,7 @@ class ElementsSessionJsonParserTest {
)
),
defaultPaymentMethod = "pm_123",
paymentMethods = listOf(
PaymentMethod(
id = "pm_123",
customerId = "cus_1",
type = PaymentMethod.Type.Card,
code = "card",
created = 1550757934255,
liveMode = false,
billingDetails = null,
card = PaymentMethod.Card(
brand = CardBrand.Visa,
last4 = "4242",
expiryMonth = 8,
expiryYear = 2032,
country = "US",
funding = "credit",
fingerprint = "fingerprint123",
checks = PaymentMethod.Card.Checks(
addressLine1Check = "unchecked",
cvcCheck = "unchecked",
addressPostalCodeCheck = null,
),
threeDSecureUsage = PaymentMethod.Card.ThreeDSecureUsage(
isSupported = true
)
)
)
)
paymentMethods = elementsSessionExpectedPaymentMethods
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ internal class PlaygroundSettings private constructor(
CardBrandAcceptanceSettingsDefinition,
FeatureFlagSettingsDefinition(FeatureFlags.useNewUpdateCardScreen),
FeatureFlagSettingsDefinition(FeatureFlags.instantDebitsIncentives),
FeatureFlagSettingsDefinition(FeatureFlags.defaultPaymentMethod),
)

private val nonUiSettingDefinitions: List<PlaygroundSettingDefinition<*>> = listOf(
Expand Down
7 changes: 7 additions & 0 deletions paymentsheet/api/paymentsheet.api
Original file line number Diff line number Diff line change
Expand Up @@ -2469,6 +2469,13 @@ public final class com/stripe/android/paymentsheet/state/PaymentSheetState$Loadi
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/paymentsheet/ui/ComposableSingletons$DefaultPaymentMethodLabelKt {
public static final field INSTANCE Lcom/stripe/android/paymentsheet/ui/ComposableSingletons$DefaultPaymentMethodLabelKt;
public static field lambda-1 Lkotlin/jvm/functions/Function2;
public fun <init> ()V
public final fun getLambda-1$paymentsheet_release ()Lkotlin/jvm/functions/Function2;
}

public final class com/stripe/android/paymentsheet/ui/ComposableSingletons$EditPaymentMethodKt {
public static final field INSTANCE Lcom/stripe/android/paymentsheet/ui/ComposableSingletons$EditPaymentMethodKt;
public static field lambda-1 Lkotlin/jvm/functions/Function2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.stripe.android.paymentsheet.ui

import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.stripe.android.paymentsheet.R
import com.stripe.android.uicore.DefaultStripeTheme
import com.stripe.android.uicore.stripeColors

@Composable
internal fun DefaultPaymentMethodLabel(
modifier: Modifier,
) {
Text(
modifier = modifier
.testTag(
TEST_TAG_DEFAULT_PAYMENT_METHOD_LABEL
),
text = stringResource(id = R.string.stripe_wallet_default),
style = MaterialTheme.typography.caption.copy(fontWeight = FontWeight.Medium),
color = MaterialTheme.stripeColors.placeholderText,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}

@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview
private fun DefaultPaymentMethodLabelPreview() {
DefaultStripeTheme {
Row(
modifier = Modifier.background(color = MaterialTheme.stripeColors.component)
) {
DefaultPaymentMethodLabel(
modifier = Modifier
)
}
}
}

internal const val TEST_TAG_DEFAULT_PAYMENT_METHOD_LABEL = "default_payment_method_label"
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.stripe.android.paymentsheet.ui

import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stripe.android.screenshottesting.FontSize
import com.stripe.android.screenshottesting.PaparazziRule
import com.stripe.android.screenshottesting.SystemAppearance
import com.stripe.android.utils.screenshots.PaymentSheetAppearance
import org.junit.Rule
import org.junit.Test

internal class DefaultPaymentMethodLabelScreenshotTest {

@get:Rule
val paparazziRule = PaparazziRule(
SystemAppearance.entries,
PaymentSheetAppearance.entries,
FontSize.entries,
)

@Test
fun testDefaultPaymentMethodLabel() {
paparazziRule.snapshot {
DefaultPaymentMethodLabel(
modifier = Modifier
.padding(horizontal = 4.dp, vertical = 4.dp)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.stripe.android.paymentsheet.ui

import android.os.Build
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.dp
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.S])
internal class DefaultPaymentMethodLabelTest {

@get:Rule
val composeRule = createComposeRule()

@Test
fun testDefaultPaymentMethodLabel() {
composeRule.setContent {
DefaultPaymentMethodLabel(
modifier = Modifier
.padding(horizontal = 4.dp, vertical = 4.dp)
)
}

assertThat(composeRule.onRoot().fetchSemanticsNode().children).isNotEmpty()
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ object FeatureFlags {
val nativeLinkEnabled = FeatureFlag("Native Link")
val useNewUpdateCardScreen = FeatureFlag("Enable new update card screen")
val instantDebitsIncentives = FeatureFlag("Instant Bank Payments Incentives")
val defaultPaymentMethod = FeatureFlag("Default Payment Method")
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
Expand Down
Loading