diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentelement/embedded/EmbeddedContent.kt b/paymentsheet/src/main/java/com/stripe/android/paymentelement/embedded/EmbeddedContent.kt index a2efc3c33bf..e7bb1ba59b2 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentelement/embedded/EmbeddedContent.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentelement/embedded/EmbeddedContent.kt @@ -10,8 +10,8 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import com.stripe.android.core.strings.ResolvableString import com.stripe.android.paymentsheet.ui.Mandate +import com.stripe.android.paymentsheet.verticalmode.PaymentMethodEmbeddedLayoutUI import com.stripe.android.paymentsheet.verticalmode.PaymentMethodVerticalLayoutInteractor -import com.stripe.android.paymentsheet.verticalmode.PaymentMethodVerticalLayoutUI import com.stripe.android.uicore.strings.resolve @Immutable @@ -33,7 +33,7 @@ internal data class EmbeddedContent( @Composable private fun EmbeddedVerticalList() { - PaymentMethodVerticalLayoutUI( + PaymentMethodEmbeddedLayoutUI( interactor = interactor, modifier = Modifier.padding(bottom = 8.dp), ) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVEmbeddedLayoutUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVEmbeddedLayoutUI.kt new file mode 100644 index 00000000000..996bf453fea --- /dev/null +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVEmbeddedLayoutUI.kt @@ -0,0 +1,210 @@ +package com.stripe.android.paymentsheet.verticalmode + +import androidx.annotation.RestrictTo +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi +import com.stripe.android.paymentsheet.DisplayableSavedPaymentMethod +import com.stripe.android.paymentsheet.PaymentSheet.Appearance.Embedded +import com.stripe.android.paymentsheet.analytics.code +import com.stripe.android.paymentsheet.model.PaymentSelection +import com.stripe.android.paymentsheet.model.isSaved +import com.stripe.android.uicore.image.StripeImageLoader +import com.stripe.android.uicore.utils.collectAsState +import org.jetbrains.annotations.VisibleForTesting + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +const val TEST_TAG_PAYMENT_METHOD_EMBEDDED_LAYOUT = "TEST_TAG_PAYMENT_METHOD_EMBEDDED_LAYOUT" + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +@Composable +internal fun PaymentMethodEmbeddedLayoutUI( + interactor: PaymentMethodVerticalLayoutInteractor, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + val imageLoader = remember { + StripeImageLoader(context.applicationContext) + } + + val state by interactor.state.collectAsState() + + PaymentMethodEmbeddedLayoutUI( + paymentMethods = state.displayablePaymentMethods, + displayedSavedPaymentMethod = state.displayedSavedPaymentMethod, + savedPaymentMethodAction = state.availableSavedPaymentMethodAction, + selection = state.selection, + isEnabled = !state.isProcessing, + onViewMorePaymentMethods = { + interactor.handleViewAction( + PaymentMethodVerticalLayoutInteractor.ViewAction.TransitionToManageSavedPaymentMethods + ) + }, + onEditPaymentMethod = { + interactor.handleViewAction( + PaymentMethodVerticalLayoutInteractor.ViewAction.EditPaymentMethod(it) + ) + }, + onSelectSavedPaymentMethod = { + interactor.handleViewAction( + PaymentMethodVerticalLayoutInteractor.ViewAction.SavedPaymentMethodSelected(it.paymentMethod) + ) + }, + onManageOneSavedPaymentMethod = { + interactor.handleViewAction( + PaymentMethodVerticalLayoutInteractor.ViewAction.OnManageOneSavedPaymentMethod(it) + ) + }, + imageLoader = imageLoader, + modifier = modifier + .testTag(TEST_TAG_PAYMENT_METHOD_EMBEDDED_LAYOUT), + rowStyle = state.rowType + ) +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +@VisibleForTesting +@Composable +internal fun PaymentMethodEmbeddedLayoutUI( + paymentMethods: List, + displayedSavedPaymentMethod: DisplayableSavedPaymentMethod?, + savedPaymentMethodAction: PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction, + selection: PaymentSelection?, + isEnabled: Boolean, + onViewMorePaymentMethods: () -> Unit, + onManageOneSavedPaymentMethod: (DisplayableSavedPaymentMethod) -> Unit, + onEditPaymentMethod: (DisplayableSavedPaymentMethod) -> Unit, + onSelectSavedPaymentMethod: (DisplayableSavedPaymentMethod) -> Unit, + imageLoader: StripeImageLoader, + rowStyle: Embedded.RowStyle, + modifier: Modifier = Modifier, +) { + val arrangement = if (rowStyle is Embedded.RowStyle.FloatingButton) { + Arrangement.spacedBy(rowStyle.spacingDp.dp) + } else { + Arrangement.Top + } + Column(modifier = modifier, verticalArrangement = arrangement) { + if (rowStyle.topSeparatorEnabled()) OptionalEmbeddedDivider(rowStyle) + if (displayedSavedPaymentMethod != null) { + SavedPaymentMethodRowButton( + displayableSavedPaymentMethod = displayedSavedPaymentMethod, + isEnabled = isEnabled, + isSelected = selection?.isSaved == true, + trailingContent = { + SavedPaymentMethodTrailingContent( + displayedSavedPaymentMethod = displayedSavedPaymentMethod, + savedPaymentMethodAction = savedPaymentMethodAction, + onViewMorePaymentMethods = onViewMorePaymentMethods, + onEditPaymentMethod = onEditPaymentMethod, + onManageOneSavedPaymentMethod = { onManageOneSavedPaymentMethod(displayedSavedPaymentMethod) }, + ) + }, + onClick = { onSelectSavedPaymentMethod(displayedSavedPaymentMethod) }, + rowStyle = rowStyle + ) + } + + OptionalEmbeddedDivider(rowStyle) + + val selectedIndex = remember(selection, paymentMethods) { + if (selection == null || selection.isSaved) { + -1 + } else { + val code = selection.code() + paymentMethods.indexOfFirst { it.code == code } + } + } + + paymentMethods.forEachIndexed { index, item -> + NewPaymentMethodRowButton( + isEnabled = isEnabled, + isSelected = index == selectedIndex, + displayablePaymentMethod = item, + imageLoader = imageLoader, + rowStyle = rowStyle + ) + + if (index != paymentMethods.lastIndex) { + OptionalEmbeddedDivider(rowStyle) + } else if (rowStyle.bottomSeparatorEnabled()) { + OptionalEmbeddedDivider(rowStyle) + } + } + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +@Composable +private fun OptionalEmbeddedDivider(rowStyle: Embedded.RowStyle) { + if (rowStyle !is Embedded.RowStyle.FloatingButton) { + val color = Color(rowStyle.separatorColor()) + val thickness = rowStyle.separatorThickness() + val modifier = if (rowStyle is Embedded.RowStyle.FlatWithRadio) { + Modifier.padding(start = rowStyle.separatorInsets() + 32.dp, end = rowStyle.separatorInsets()) + } else { + Modifier.padding(horizontal = rowStyle.separatorInsets()) + } + Divider( + color = color, + thickness = thickness, + modifier = modifier + ) + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +private fun Embedded.RowStyle.bottomSeparatorEnabled(): Boolean { + return when (this) { + is Embedded.RowStyle.FloatingButton -> false + is Embedded.RowStyle.FlatWithRadio -> this.bottomSeparatorEnabled + is Embedded.RowStyle.FlatWithCheckmark -> this.bottomSeparatorEnabled + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +private fun Embedded.RowStyle.topSeparatorEnabled(): Boolean { + return when (this) { + is Embedded.RowStyle.FloatingButton -> false + is Embedded.RowStyle.FlatWithRadio -> this.topSeparatorEnabled + is Embedded.RowStyle.FlatWithCheckmark -> this.topSeparatorEnabled + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +private fun Embedded.RowStyle.separatorThickness(): Dp { + return when (this) { + is Embedded.RowStyle.FloatingButton -> 0.dp + is Embedded.RowStyle.FlatWithRadio -> this.separatorThicknessDp.dp + is Embedded.RowStyle.FlatWithCheckmark -> this.separatorThicknessDp.dp + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +private fun Embedded.RowStyle.separatorColor(): Int { + return when (this) { + is Embedded.RowStyle.FloatingButton -> 0 + is Embedded.RowStyle.FlatWithRadio -> this.separatorColor + is Embedded.RowStyle.FlatWithCheckmark -> this.separatorColor + } +} + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +private fun Embedded.RowStyle.separatorInsets(): Dp { + return when (this) { + is Embedded.RowStyle.FloatingButton -> 0.dp + is Embedded.RowStyle.FlatWithRadio -> this.separatorInsetsDp.dp + is Embedded.RowStyle.FlatWithCheckmark -> this.separatorInsetsDp.dp + } +} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUI.kt index ce98fca0928..8667db72907 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUI.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi import com.stripe.android.paymentsheet.DisplayableSavedPaymentMethod -import com.stripe.android.paymentsheet.PaymentSheet.Appearance.Embedded import com.stripe.android.paymentsheet.R import com.stripe.android.paymentsheet.analytics.code import com.stripe.android.paymentsheet.model.PaymentSelection @@ -39,7 +38,6 @@ internal const val TEST_TAG_VIEW_MORE = "TEST_TAG_VIEW_MORE" internal const val TEST_TAG_EDIT_SAVED_CARD = "TEST_TAG_VERTICAL_MODE_SAVED_PM_EDIT" internal const val TEST_TAG_SAVED_TEXT = "TEST_TAG_SAVED_TEXT" -@OptIn(ExperimentalEmbeddedPaymentElementApi::class) @Composable internal fun PaymentMethodVerticalLayoutUI( interactor: PaymentMethodVerticalLayoutInteractor, @@ -80,8 +78,7 @@ internal fun PaymentMethodVerticalLayoutUI( }, imageLoader = imageLoader, modifier = modifier - .testTag(TEST_TAG_PAYMENT_METHOD_VERTICAL_LAYOUT), - rowStyle = state.rowType + .testTag(TEST_TAG_PAYMENT_METHOD_VERTICAL_LAYOUT) ) } @@ -99,7 +96,6 @@ internal fun PaymentMethodVerticalLayoutUI( onEditPaymentMethod: (DisplayableSavedPaymentMethod) -> Unit, onSelectSavedPaymentMethod: (DisplayableSavedPaymentMethod) -> Unit, imageLoader: StripeImageLoader, - rowStyle: Embedded.RowStyle = Embedded.RowStyle.FloatingButton.default, modifier: Modifier = Modifier, ) { Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(12.dp)) { @@ -127,7 +123,6 @@ internal fun PaymentMethodVerticalLayoutUI( ) }, onClick = { onSelectSavedPaymentMethod(displayedSavedPaymentMethod) }, - rowStyle = rowStyle ) Text(stringResource(id = R.string.stripe_paymentsheet_new_pm), style = textStyle, color = textColor) } @@ -146,13 +141,12 @@ internal fun PaymentMethodVerticalLayoutUI( selectedIndex = selectedIndex, isEnabled = isEnabled, imageLoader = imageLoader, - rowStyle = rowStyle ) } } @Composable -private fun SavedPaymentMethodTrailingContent( +internal fun SavedPaymentMethodTrailingContent( displayedSavedPaymentMethod: DisplayableSavedPaymentMethod, savedPaymentMethodAction: PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction, onViewMorePaymentMethods: () -> Unit, diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUIScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUIScreenshotTest.kt new file mode 100644 index 00000000000..9cfabb337b1 --- /dev/null +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUIScreenshotTest.kt @@ -0,0 +1,181 @@ +package com.stripe.android.paymentsheet.verticalmode + +import android.graphics.Color +import androidx.compose.ui.graphics.toArgb +import com.stripe.android.model.PaymentMethodFixtures +import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi +import com.stripe.android.paymentsheet.DisplayableSavedPaymentMethod +import com.stripe.android.paymentsheet.PaymentSheet +import com.stripe.android.paymentsheet.model.PaymentSelection +import com.stripe.android.screenshottesting.PaparazziRule +import com.stripe.android.uicore.StripeThemeDefaults +import com.stripe.android.utils.MockPaymentMethodsFactory +import com.stripe.android.utils.screenshots.PaymentSheetAppearance +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.mock + +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +class PaymentMethodEmbeddedLayoutUIScreenshotTest { + @get:Rule + val paparazziRule = PaparazziRule(PaymentSheetAppearance.entries) + + private val paymentMethods: List by lazy { + MockPaymentMethodsFactory.create().map { + it.asDisplayablePaymentMethod( + customerSavedPaymentMethods = emptyList(), + incentive = null, + onClick = {}, + ) + } + } + + private val savedPaymentMethod: DisplayableSavedPaymentMethod = PaymentMethodFixtures.displayableCard() + + @Test + fun testFloatingButton() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.default + ) + } + } + + @Test + fun testFlatWitRadio() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.defaultLight + ) + } + } + + @Test + fun testFlatWithCheckmark() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.defaultLight + ) + } + } + + @Test + fun testSeparatorColorAndInsets() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark( + separatorThicknessDp = 5f, + separatorColor = Color.CYAN, + separatorInsetsDp = 40f, + topSeparatorEnabled = true, + bottomSeparatorEnabled = true, + checkmarkColor = StripeThemeDefaults.colorsLight.materialColors.primary.toArgb(), + checkmarkInsetDp = StripeThemeDefaults.embeddedCommon.checkmarkInsetDp, + additionalInsetsDp = StripeThemeDefaults.embeddedCommon.additionalInsetsDp + ) + ) + } + } + + @Test + fun testBottomSeparatorOnly() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark( + separatorThicknessDp = StripeThemeDefaults.flat.separatorThickness, + separatorColor = StripeThemeDefaults.colorsLight.componentBorder.toArgb(), + separatorInsetsDp = StripeThemeDefaults.flat.separatorInsets, + topSeparatorEnabled = false, + bottomSeparatorEnabled = true, + checkmarkColor = StripeThemeDefaults.colorsLight.materialColors.primary.toArgb(), + checkmarkInsetDp = StripeThemeDefaults.embeddedCommon.checkmarkInsetDp, + additionalInsetsDp = StripeThemeDefaults.embeddedCommon.additionalInsetsDp + ) + ) + } + } + + @Test + fun testTopSeparatorOnly() { + paparazziRule.snapshot { + PaymentMethodEmbeddedLayoutUI( + paymentMethods = paymentMethods, + displayedSavedPaymentMethod = savedPaymentMethod, + savedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + selection = PaymentSelection.Saved(savedPaymentMethod.paymentMethod), + isEnabled = true, + onEditPaymentMethod = {}, + onViewMorePaymentMethods = {}, + onSelectSavedPaymentMethod = {}, + onManageOneSavedPaymentMethod = {}, + imageLoader = mock(), + rowStyle = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark( + separatorThicknessDp = StripeThemeDefaults.flat.separatorThickness, + separatorColor = StripeThemeDefaults.colorsLight.componentBorder.toArgb(), + separatorInsetsDp = StripeThemeDefaults.flat.separatorInsets, + topSeparatorEnabled = true, + bottomSeparatorEnabled = false, + checkmarkColor = StripeThemeDefaults.colorsLight.materialColors.primary.toArgb(), + checkmarkInsetDp = StripeThemeDefaults.embeddedCommon.checkmarkInsetDp, + additionalInsetsDp = StripeThemeDefaults.embeddedCommon.additionalInsetsDp + ) + ) + } + } +} diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUITest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUITest.kt new file mode 100644 index 00000000000..af75a2d6067 --- /dev/null +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodEmbeddedLayoutUITest.kt @@ -0,0 +1,318 @@ +package com.stripe.android.paymentsheet.verticalmode + +import android.os.Build +import androidx.compose.foundation.layout.padding +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assert +import androidx.compose.ui.test.assertAll +import androidx.compose.ui.test.isSelected +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onChildren +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.compose.ui.unit.dp +import com.google.common.truth.Truth.assertThat +import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory +import com.stripe.android.lpmfoundations.paymentmethod.definitions.CardDefinition +import com.stripe.android.model.PaymentIntentFixtures +import com.stripe.android.model.PaymentMethodFixtures +import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi +import com.stripe.android.paymentsheet.PaymentSheet.Appearance.Embedded +import com.stripe.android.paymentsheet.ViewActionRecorder +import com.stripe.android.paymentsheet.forms.FormFieldValues +import com.stripe.android.paymentsheet.model.PaymentSelection +import com.stripe.android.paymentsheet.ui.transformToPaymentSelection +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.Q]) +@OptIn(ExperimentalEmbeddedPaymentElementApi::class) +class PaymentMethodEmbeddedLayoutUITest { + @get:Rule + val composeRule = createComposeRule() + + @Test + fun clickingOnViewMore_transitionsToManageScreen() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = emptyList(), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat(viewActionRecorder.viewActions).isEmpty() + composeRule.onNodeWithTag(TEST_TAG_VIEW_MORE).performClick() + viewActionRecorder.consume( + PaymentMethodVerticalLayoutInteractor.ViewAction.TransitionToManageSavedPaymentMethods + ) + assertThat(viewActionRecorder.viewActions).isEmpty() + } + + @Test + fun oneSavedPm_canBeRemoved_buttonIsEdit_callsOnManageOneSavedPm() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = emptyList(), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ONE, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat(viewActionRecorder.viewActions).isEmpty() + composeRule.onNodeWithTag(TEST_TAG_EDIT_SAVED_CARD).performClick() + viewActionRecorder.consume( + PaymentMethodVerticalLayoutInteractor.ViewAction.OnManageOneSavedPaymentMethod( + PaymentMethodFixtures.displayableCard() + ) + ) + assertThat(viewActionRecorder.viewActions).isEmpty() + } + + @Test + fun oneSavedPm_canBeModified_buttonIsEdit_editsPaymentMethod() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = emptyList(), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.EDIT_CARD_BRAND, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat(viewActionRecorder.viewActions).isEmpty() + composeRule.onNodeWithTag(TEST_TAG_EDIT_SAVED_CARD).performClick() + viewActionRecorder.consume( + PaymentMethodVerticalLayoutInteractor.ViewAction.EditPaymentMethod( + PaymentMethodFixtures.displayableCard() + ) + ) + assertThat(viewActionRecorder.viewActions).isEmpty() + } + + @Test + fun oneSavedPm_cannotBeEdited_noSavedPaymentMethodButton() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = emptyList(), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.NONE, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + composeRule.onNodeWithTag( + TEST_TAG_SAVED_PAYMENT_METHOD_ROW_BUTTON + "_${PaymentMethodFixtures.displayableCard().paymentMethod.id}" + ).assertExists() + + composeRule.onNodeWithTag(TEST_TAG_EDIT_SAVED_CARD).assertDoesNotExist() + composeRule.onNodeWithTag(TEST_TAG_VIEW_MORE).assertDoesNotExist() + } + + @Test + fun clickingOnNewPaymentMethod_callsOnClick() { + var onClickCalled = false + runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = listOf( + CardDefinition.uiDefinitionFactory().supportedPaymentMethod(CardDefinition, emptyList())!! + .asDisplayablePaymentMethod( + customerSavedPaymentMethods = emptyList(), + incentive = null, + onClick = { onClickCalled = true }, + ), + ), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = null, + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat(onClickCalled).isFalse() + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_card").performClick() + assertThat(onClickCalled).isTrue() + assertThat(viewActionRecorder.viewActions).isEmpty() + } + } + + @Test + fun clickingSavedPaymentMethod_callsSelectSavedPaymentMethod() { + val savedPaymentMethod = PaymentMethodFixtures.displayableCard() + runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = emptyList(), + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = savedPaymentMethod, + availableSavedPaymentMethodAction = PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.NONE, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat(viewActionRecorder.viewActions).isEmpty() + composeRule.onNodeWithTag( + TEST_TAG_SAVED_PAYMENT_METHOD_ROW_BUTTON + "_${savedPaymentMethod.paymentMethod.id}" + ).performClick() + viewActionRecorder.consume( + PaymentMethodVerticalLayoutInteractor.ViewAction.SavedPaymentMethodSelected( + savedPaymentMethod.paymentMethod + ) + ) + assertThat(viewActionRecorder.viewActions).isEmpty() + } + } + + @Test + fun allPaymentMethodsAreShown() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = PaymentMethodMetadataFactory.create( + PaymentIntentFixtures.PI_WITH_PAYMENT_METHOD!!.copy( + paymentMethodTypes = listOf("card", "cashapp", "klarna") + ) + ).sortedSupportedPaymentMethods().map { + it.asDisplayablePaymentMethod( + customerSavedPaymentMethods = emptyList(), + incentive = null, + onClick = {}, + ) + }, + isProcessing = false, + selection = null, + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat( + composeRule.onNodeWithTag(TEST_TAG_PAYMENT_METHOD_EMBEDDED_LAYOUT) + .onChildren().fetchSemanticsNodes().size + ).isEqualTo(4) + + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_card").assertExists() + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_cashapp").assertExists() + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_klarna").assertExists() + + composeRule.onNodeWithTag( + TEST_TAG_SAVED_PAYMENT_METHOD_ROW_BUTTON + "_${PaymentMethodFixtures.displayableCard().paymentMethod.id}" + ).assertExists() + } + + @Test + fun savedPaymentMethodIsSelected_whenSelectionIsSavedPm() = runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = PaymentMethodMetadataFactory.create( + PaymentIntentFixtures.PI_WITH_PAYMENT_METHOD!!.copy( + paymentMethodTypes = listOf("card", "cashapp", "klarna") + ) + ).sortedSupportedPaymentMethods().map { + it.asDisplayablePaymentMethod( + customerSavedPaymentMethods = emptyList(), + incentive = null, + onClick = {}, + ) + }, + isProcessing = false, + selection = PaymentSelection.Saved(PaymentMethodFixtures.displayableCard().paymentMethod), + displayedSavedPaymentMethod = PaymentMethodFixtures.displayableCard(), + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + composeRule.onNodeWithTag( + TEST_TAG_SAVED_PAYMENT_METHOD_ROW_BUTTON + "_${PaymentMethodFixtures.displayableCard().paymentMethod.id}" + ).assertExists() + .assert(isSelected()) + + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_card") + .assertExists() + .onChildren().assertAll(isSelected().not()) + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_cashapp") + .assertExists() + .onChildren().assertAll(isSelected().not()) + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_klarna") + .assertExists() + .onChildren().assertAll(isSelected().not()) + } + + @Test + fun correctLPMIsSelected() { + val paymentMethodMetadata = PaymentMethodMetadataFactory.create( + PaymentIntentFixtures.PI_WITH_PAYMENT_METHOD!!.copy( + paymentMethodTypes = listOf("card", "cashapp", "klarna") + ) + ) + val supportedPaymentMethods = paymentMethodMetadata.sortedSupportedPaymentMethods() + val selection = FormFieldValues( + userRequestedReuse = PaymentSelection.CustomerRequestedSave.NoRequest, + ).transformToPaymentSelection( + paymentMethod = supportedPaymentMethods[1], + paymentMethodMetadata = paymentMethodMetadata, + ) + runScenario( + PaymentMethodVerticalLayoutInteractor.State( + displayablePaymentMethods = supportedPaymentMethods.map { + it.asDisplayablePaymentMethod( + customerSavedPaymentMethods = emptyList(), + incentive = null, + onClick = {}, + ) + }, + isProcessing = false, + selection = selection, + displayedSavedPaymentMethod = null, + availableSavedPaymentMethodAction = + PaymentMethodVerticalLayoutInteractor.SavedPaymentMethodAction.MANAGE_ALL, + rowType = Embedded.RowStyle.FloatingButton.default + ) + ) { + assertThat( + composeRule.onNodeWithTag(TEST_TAG_PAYMENT_METHOD_EMBEDDED_LAYOUT) + .onChildren().fetchSemanticsNodes().size + ).isEqualTo(3) + + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_card") + .assertExists() + .onChildren().assertAll(isSelected().not()) + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_cashapp") + .assertExists() + .assert(isSelected()) + composeRule.onNodeWithTag(TEST_TAG_NEW_PAYMENT_METHOD_ROW_BUTTON + "_klarna") + .assertExists() + .onChildren().assertAll(isSelected().not()) + } + } + + private fun runScenario( + initialState: PaymentMethodVerticalLayoutInteractor.State, + block: Scenario.() -> Unit + ) { + val viewActionRecorder = ViewActionRecorder() + val interactor = FakePaymentMethodVerticalLayoutInteractor( + initialState = initialState, + viewActionRecorder = viewActionRecorder, + ) + + composeRule.setContent { + PaymentMethodEmbeddedLayoutUI(interactor, Modifier.padding(horizontal = 20.dp)) + } + + Scenario(viewActionRecorder).apply(block) + } + + private data class Scenario( + val viewActionRecorder: ViewActionRecorder, + ) +} diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUIScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUIScreenshotTest.kt index a1a393973d3..a0ef71dab1e 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUIScreenshotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/PaymentMethodVerticalLayoutUIScreenshotTest.kt @@ -1,7 +1,6 @@ package com.stripe.android.paymentsheet.verticalmode import com.stripe.android.model.PaymentMethodFixtures -import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi import com.stripe.android.paymentsheet.DisplayableSavedPaymentMethod import com.stripe.android.paymentsheet.model.PaymentSelection import com.stripe.android.screenshottesting.PaparazziRule @@ -11,7 +10,6 @@ import org.junit.Rule import org.junit.Test import org.mockito.kotlin.mock -@OptIn(ExperimentalEmbeddedPaymentElementApi::class) internal class PaymentMethodVerticalLayoutUIScreenshotTest { @get:Rule val paparazziRule = PaparazziRule(PaymentSheetAppearance.entries) diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CrazyAppearance].png new file mode 100644 index 00000000000..4e5862a3fba Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CustomAppearance].png new file mode 100644 index 00000000000..54bd16d6f06 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[DefaultAppearance].png new file mode 100644 index 00000000000..1b4a21c9e2b Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testBottomSeparatorOnly[DefaultAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CrazyAppearance].png new file mode 100644 index 00000000000..027076e1857 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CustomAppearance].png new file mode 100644 index 00000000000..2bb99d56abe Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[DefaultAppearance].png new file mode 100644 index 00000000000..d1d7274dba8 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWitRadio[DefaultAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CrazyAppearance].png new file mode 100644 index 00000000000..355a17d6cfe Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CustomAppearance].png new file mode 100644 index 00000000000..e8a3b4b03e4 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[DefaultAppearance].png new file mode 100644 index 00000000000..9fb93c2eec2 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFlatWithCheckmark[DefaultAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CrazyAppearance].png new file mode 100644 index 00000000000..a111b4d4187 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CustomAppearance].png new file mode 100644 index 00000000000..40dcb2e13eb Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[DefaultAppearance].png new file mode 100644 index 00000000000..2fd8a2ac424 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testFloatingButton[DefaultAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CrazyAppearance].png new file mode 100644 index 00000000000..ab1092d48aa Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CustomAppearance].png new file mode 100644 index 00000000000..1b0cc9a8ff0 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[DefaultAppearance].png new file mode 100644 index 00000000000..2e0c76232aa Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testSeparatorColorAndInsets[DefaultAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CrazyAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CrazyAppearance].png new file mode 100644 index 00000000000..db6e806fa66 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CrazyAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CustomAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CustomAppearance].png new file mode 100644 index 00000000000..70979b9e44e Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[CustomAppearance].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[DefaultAppearance].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[DefaultAppearance].png new file mode 100644 index 00000000000..99335e7f1be Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.paymentsheet.verticalmode_PaymentMethodEmbeddedLayoutUIScreenshotTest_testTopSeparatorOnly[DefaultAppearance].png differ