From c7baecb4e4d36e0b109de23e005abee5ea756957 Mon Sep 17 00:00:00 2001 From: Samer Alabi Date: Fri, 24 May 2024 11:39:08 -0400 Subject: [PATCH 1/3] Add initial `CustomerSheet` end-to-end tests. --- .../android/lpm/TestCardInCustomerSheet.kt | 131 ++++++++++++++++++ .../android/test/core/PlaygroundTestDriver.kt | 82 +++++++++++ .../stripe/android/test/core/ui/Selectors.kt | 12 ++ .../customersheet/ui/CustomerSheetScreen.kt | 8 +- 4 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt new file mode 100644 index 00000000000..effc8fd1d53 --- /dev/null +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt @@ -0,0 +1,131 @@ +package com.stripe.android.lpm + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.stripe.android.BasePlaygroundTest +import com.stripe.android.paymentsheet.PaymentSheet +import com.stripe.android.paymentsheet.example.playground.settings.CollectAddressSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CollectEmailSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CollectNameSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CollectPhoneSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.Country +import com.stripe.android.paymentsheet.example.playground.settings.CountrySettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CustomerSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CustomerSheetPaymentMethodModeDefinition +import com.stripe.android.paymentsheet.example.playground.settings.CustomerType +import com.stripe.android.paymentsheet.example.playground.settings.DefaultBillingAddress +import com.stripe.android.paymentsheet.example.playground.settings.DefaultBillingAddressSettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.PaymentMethodMode +import com.stripe.android.test.core.TestParameters +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +internal class TestCardInCustomerSheet : BasePlaygroundTest() { + @Test + fun testCard() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.US + settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.CreateAndAttach + }, + populateCustomLpmFields = { + populateCardDetails() + }, + ) + } + + @Test + fun testCardWithSetupIntent() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.US + settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.SetupIntent + }, + populateCustomLpmFields = { + populateCardDetails() + }, + ) + } + + @Test + fun testCardWithNonUsMerchant() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.FR + settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.CreateAndAttach + }, + populateCustomLpmFields = { + populateCardDetails() + }, + ) + } + + @Test + fun testCardWithSetupIntentAndNonUsMerchant() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.FR + settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.SetupIntent + }, + populateCustomLpmFields = { + populateCardDetails() + }, + ) + } + + @Test + fun testCardWithBillingDetailsCollection() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create( + paymentMethodCode = "card", + ) { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.US + settings[DefaultBillingAddressSettingsDefinition] = DefaultBillingAddress.Off + settings[CollectNameSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectEmailSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectPhoneSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectAddressSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full + }, + populateCustomLpmFields = { + populateCardDetails() + populateEmail() + populateName("Name on card") + populateAddress() + populatePhoneNumber() + }, + ) + } + + @Test + fun testCardWithBillingDetailsCollectionWithDefaults() { + testDriver.savePaymentMethodInCustomerSheet( + TestParameters.create( + paymentMethodCode = "card", + ) { settings -> + settings[CustomerSettingsDefinition] = CustomerType.NEW + settings[CountrySettingsDefinition] = Country.US + settings[DefaultBillingAddressSettingsDefinition] = DefaultBillingAddress.On + settings[CollectNameSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectEmailSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectPhoneSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + settings[CollectAddressSettingsDefinition] = + PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full + }, + populateCustomLpmFields = { + populateCardDetails() + }, + ) + } +} diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt index 75834d42ad6..9151fb45475 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.test.SemanticsNodeInteraction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.hasTestTag +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onAllNodesWithText @@ -313,6 +314,50 @@ internal class PlaygroundTestDriver( teardown() } + fun savePaymentMethodInCustomerSheet( + testParameters: TestParameters, + values: FieldPopulator.Values = FieldPopulator.Values(), + populateCustomLpmFields: FieldPopulator.() -> Unit = {}, + ): PlaygroundState? { + setup( + testParameters.copyPlaygroundSettings { settings -> + settings.updateConfigurationData { configurationData -> + configurationData.copy( + integrationType = PlaygroundConfigurationData.IntegrationType.CustomerSheet + ) + } + } + ) + + launchCustomerSheet() + + selectors.paymentSelection.click() + + val fieldPopulator = FieldPopulator( + selectors, + testParameters, + populateCustomLpmFields, + {}, + values, + ) + fieldPopulator.populateFields() + + val result = playgroundState + + pressCustomerSheetSave() + + waitForManageSavedPaymentMethods() + + pressCustomerSheetConfirm() + + Espresso.onIdle() + composeTestRule.waitForIdle() + + teardown() + + return result + } + private fun pressMultiStepSelect() { selectors.multiStepSelect.click() waitForNotPlaygroundActivity() @@ -325,6 +370,20 @@ internal class PlaygroundTestDriver( } } + private fun pressCustomerSheetSave() { + Espresso.onIdle() + composeTestRule.waitForIdle() + + selectors.customerSheetSaveButton.click() + } + + private fun pressCustomerSheetConfirm() { + Espresso.onIdle() + composeTestRule.waitForIdle() + + selectors.customerSheetConfirmButton.click() + } + /** * This will open the payment sheet complete flow from the playground with a new or * guest user and complete the confirmation including any browser interactions. @@ -840,6 +899,17 @@ internal class PlaygroundTestDriver( } } + private fun launchCustomerSheet() { + selectors.reload.click() + Espresso.onIdle() + selectors.composeTestRule.waitForIdle() + + selectors.multiStepSelect.waitForEnabled() + selectors.multiStepSelect.click() + + waitForNotPlaygroundActivity() + } + private fun doAuthorization() { selectors.apply { val checkoutMode = @@ -1039,6 +1109,7 @@ internal class PlaygroundTestDriver( internal fun teardown() { application?.unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks) + playgroundState = null currentActivity = null } @@ -1058,6 +1129,17 @@ internal class PlaygroundTestDriver( composeTestRule.waitUntilAtLeastOneExists(hasTestTag(ADD_PAYMENT_METHOD_NODE_TAG), 5000L) } + @OptIn(ExperimentalTestApi::class) + private fun waitForManageSavedPaymentMethods() { + Espresso.onIdle() + composeTestRule.waitForIdle() + + composeTestRule.waitUntilAtLeastOneExists( + hasText("Manage your payment methods"), + DEFAULT_UI_TIMEOUT.inWholeMilliseconds + ) + } + private companion object { const val ADD_PAYMENT_METHOD_NODE_TAG = "${SAVED_PAYMENT_METHOD_CARD_TEST_TAG}_+ Add" const val FINANCIAL_CONNECTIONS_ACTIVITY = diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt index 2b82a6e6a1f..f68f00dffa1 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt @@ -16,6 +16,8 @@ import androidx.test.uiautomator.UiObject import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import com.google.common.truth.Truth.assertThat +import com.stripe.android.customersheet.ui.CUSTOMER_SHEET_CONFIRM_BUTTON_TEST_TAG +import com.stripe.android.customersheet.ui.CUSTOMER_SHEET_SAVE_BUTTON_TEST_TAG import com.stripe.android.model.PaymentMethod.Type.Blik import com.stripe.android.model.PaymentMethod.Type.CashAppPay import com.stripe.android.paymentsheet.example.playground.RELOAD_TEST_TAG @@ -74,6 +76,16 @@ internal class Selectors( } ) + val customerSheetSaveButton = ComposeButton( + composeTestRule, + hasTestTag(CUSTOMER_SHEET_SAVE_BUTTON_TEST_TAG) + ) + + val customerSheetConfirmButton = ComposeButton( + composeTestRule, + hasTestTag(CUSTOMER_SHEET_CONFIRM_BUTTON_TEST_TAG) + ) + val externalPaymentMethodSucceedButton = ComposeButton( composeTestRule, hasTestTag(FawryActivity.COMPLETED_BUTTON_TEST_TAG) diff --git a/paymentsheet/src/main/java/com/stripe/android/customersheet/ui/CustomerSheetScreen.kt b/paymentsheet/src/main/java/com/stripe/android/customersheet/ui/CustomerSheetScreen.kt index 71ce6bcd692..0898fac8077 100644 --- a/paymentsheet/src/main/java/com/stripe/android/customersheet/ui/CustomerSheetScreen.kt +++ b/paymentsheet/src/main/java/com/stripe/android/customersheet/ui/CustomerSheetScreen.kt @@ -1,5 +1,6 @@ package com.stripe.android.customersheet.ui +import androidx.annotation.RestrictTo import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -293,8 +294,11 @@ private fun EditPaymentMethod( } } -internal const val CUSTOMER_SHEET_CONFIRM_BUTTON_TEST_TAG = "CustomerSheetConfirmButton" -internal const val CUSTOMER_SHEET_SAVE_BUTTON_TEST_TAG = "CustomerSheetSaveButton" +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +const val CUSTOMER_SHEET_CONFIRM_BUTTON_TEST_TAG = "CustomerSheetConfirmButton" + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +const val CUSTOMER_SHEET_SAVE_BUTTON_TEST_TAG = "CustomerSheetSaveButton" private class DefaultCardNumberCompletedEventReporter( private val viewActionHandler: (CustomerSheetViewAction) -> Unit From 899250dcba24bbfd370ab0d2cbe296d216b15728 Mon Sep 17 00:00:00 2001 From: Samer Alabi Date: Fri, 24 May 2024 13:08:45 -0400 Subject: [PATCH 2/3] Conditionally click the payment selection if needed. --- .../android/test/core/FieldPopulator.kt | 2 + .../android/test/core/PlaygroundTestDriver.kt | 26 ++++++++----- .../android/test/core/ui/FormElement.kt | 19 +++++++++ .../android/test/core/ui/PaymentSelection.kt | 39 ++++++------------- .../stripe/android/test/core/ui/Selectors.kt | 2 + .../android/paymentsheet/ui/PaymentElement.kt | 6 +++ 6 files changed, 58 insertions(+), 36 deletions(-) create mode 100644 paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/FormElement.kt diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/FieldPopulator.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/FieldPopulator.kt index 7cf389adb45..746351600e2 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/FieldPopulator.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/FieldPopulator.kt @@ -43,6 +43,8 @@ internal class FieldPopulator( } fun populateFields() { + selectors.formElement.waitFor() + populateCustomLpmFields() selectors.composeTestRule.waitForIdle() diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt index 9151fb45475..52ef4f23389 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt @@ -196,7 +196,7 @@ internal class PlaygroundTestDriver( // and click the payment method. addPaymentMethodNode().performClick() } - selectors.paymentSelection.click() + clickPaymentSelection() val fieldPopulator = FieldPopulator( selectors, @@ -252,7 +252,7 @@ internal class PlaygroundTestDriver( // and click the payment method. addPaymentMethodNode().performClick() } - selectors.paymentSelection.click() + clickPaymentSelection() val fieldPopulator = FieldPopulator( selectors, @@ -331,7 +331,7 @@ internal class PlaygroundTestDriver( launchCustomerSheet() - selectors.paymentSelection.click() + clickPaymentSelection() val fieldPopulator = FieldPopulator( selectors, @@ -399,7 +399,7 @@ internal class PlaygroundTestDriver( setup(testParameters) launchComplete() - selectors.paymentSelection.click() + clickPaymentSelection() FieldPopulator( selectors, @@ -452,7 +452,7 @@ internal class PlaygroundTestDriver( waitForAddPaymentMethodNode() addPaymentMethodNode().performClick() - selectors.paymentSelection.click() + clickPaymentSelection() FieldPopulator( selectors, @@ -574,7 +574,7 @@ internal class PlaygroundTestDriver( private fun confirmExternalPaymentMethod( button: ComposeButton, ) { - selectors.paymentSelection.click() + clickPaymentSelection() pressBuy() @@ -635,7 +635,7 @@ internal class PlaygroundTestDriver( setup(testParameters) launchComplete() - selectors.paymentSelection.click() + clickPaymentSelection() FieldPopulator( selectors = selectors, @@ -691,7 +691,7 @@ internal class PlaygroundTestDriver( // and click the payment method. addPaymentMethodNode().performClick() } - selectors.paymentSelection.click() + clickPaymentSelection() FieldPopulator( selectors = selectors, @@ -776,7 +776,7 @@ internal class PlaygroundTestDriver( internal fun pressSelection() { composeTestRule.waitForIdle() - selectors.paymentSelection.click() + clickPaymentSelection() } internal fun scrollToBottom() { @@ -798,6 +798,14 @@ internal class PlaygroundTestDriver( .performClick() } + private fun clickPaymentSelection() { + selectors.formElement.waitFor() + selectors.paymentSelection.click() + + Espresso.onIdle() + composeTestRule.waitForIdle() + } + /** * Here we wait for an activity different from the playground to be in view. We * don't specifically look for PaymentSheetActivity or PaymentOptionsActivity because diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/FormElement.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/FormElement.kt new file mode 100644 index 00000000000..cce63dfd35a --- /dev/null +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/FormElement.kt @@ -0,0 +1,19 @@ +package com.stripe.android.test.core.ui + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.hasTestTag +import androidx.compose.ui.test.junit4.ComposeTestRule +import com.stripe.android.paymentsheet.ui.FORM_ELEMENT_TEST_TAG +import com.stripe.android.test.core.DEFAULT_UI_TIMEOUT + +class FormElement( + private val composeTestRule: ComposeTestRule +) { + @OptIn(ExperimentalTestApi::class) + fun waitFor() { + composeTestRule.waitUntilExactlyOneExists( + hasTestTag(FORM_ELEMENT_TEST_TAG), + DEFAULT_UI_TIMEOUT.inWholeMilliseconds + ) + } +} diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/PaymentSelection.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/PaymentSelection.kt index c5ef59b7ab1..f801571f82d 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/PaymentSelection.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/PaymentSelection.kt @@ -1,44 +1,29 @@ package com.stripe.android.test.core.ui -import androidx.compose.ui.test.ComposeTimeoutException import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsEnabled import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.junit4.ComposeTestRule -import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollToNode -import androidx.test.platform.app.InstrumentationRegistry import com.stripe.android.paymentsheet.ui.TEST_TAG_LIST -import com.stripe.android.test.core.DEFAULT_UI_TIMEOUT class PaymentSelection(val composeTestRule: ComposeTestRule, val paymentMethodCode: String) { fun click() { - val resource = InstrumentationRegistry.getInstrumentation().targetContext.resources + if (composeTestRule.onAllNodes(hasTestTag(TEST_TAG_LIST)).fetchSemanticsNodes().isNotEmpty()) { + val paymentMethodMatcher = hasTestTag(TEST_TAG_LIST + paymentMethodCode) - try { - // If we don't find the node, it means that there's only one payment method available - // and we don't show the payment method carousel as a result. - composeTestRule.waitUntil(timeoutMillis = DEFAULT_UI_TIMEOUT.inWholeMilliseconds) { - composeTestRule - .onAllNodesWithTag(TEST_TAG_LIST) - .fetchSemanticsNodes().size == 1 - } - } catch (_: ComposeTimeoutException) { - return - } - - val paymentMethodMatcher = hasTestTag(TEST_TAG_LIST + paymentMethodCode) - composeTestRule.onNodeWithTag(TEST_TAG_LIST, true) - .performScrollToNode(paymentMethodMatcher) - composeTestRule.waitForIdle() - composeTestRule - .onNode(paymentMethodMatcher) - .assertIsDisplayed() - .assertIsEnabled() - .performClick() + composeTestRule.onNodeWithTag(TEST_TAG_LIST, true) + .performScrollToNode(paymentMethodMatcher) + composeTestRule.waitForIdle() + composeTestRule + .onNode(paymentMethodMatcher) + .assertIsDisplayed() + .assertIsEnabled() + .performClick() - composeTestRule.waitForIdle() + composeTestRule.waitForIdle() + } } } diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt index f68f00dffa1..718620ecd44 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/ui/Selectors.kt @@ -61,6 +61,8 @@ internal class Selectors( testParameters.paymentMethodCode ) + val formElement = FormElement(composeTestRule) + val mandateText = composeTestRule.onNodeWithTag(MANDATE_TEST_TAG) val buyButton = BuyButton( diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentElement.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentElement.kt index c64c00a3769..e527436fb07 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentElement.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentElement.kt @@ -1,5 +1,6 @@ package com.stripe.android.paymentsheet.ui +import androidx.annotation.RestrictTo import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -13,6 +14,7 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -116,6 +118,7 @@ internal fun FormElement( Box( modifier = Modifier + .testTag(FORM_ELEMENT_TEST_TAG) .pointerInput("AddPaymentMethod") { awaitEachGesture { val gesture = awaitPointerEvent() @@ -184,3 +187,6 @@ internal fun LinkElement( } } } + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +const val FORM_ELEMENT_TEST_TAG = "FORM_ELEMENT_UI" From 169b31eed6c9171cb51506d8f520b38ef878a399 Mon Sep 17 00:00:00 2001 From: Samer Alabi Date: Fri, 24 May 2024 14:48:30 -0400 Subject: [PATCH 3/3] Remove `SetupIntent` tests & move `CustomerAdapter` to own flow. --- .../android/lpm/TestCardInCustomerSheet.kt | 87 ------------------- .../android/test/core/PlaygroundTestDriver.kt | 3 - .../PaymentSheetPlaygroundActivity.kt | 13 +-- .../PaymentSheetPlaygroundViewModel.kt | 33 +++---- .../example/playground/PlaygroundState.kt | 2 - 5 files changed, 26 insertions(+), 112 deletions(-) diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt index effc8fd1d53..d96c897a08e 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestCardInCustomerSheet.kt @@ -2,18 +2,11 @@ package com.stripe.android.lpm import androidx.test.ext.junit.runners.AndroidJUnit4 import com.stripe.android.BasePlaygroundTest -import com.stripe.android.paymentsheet.PaymentSheet -import com.stripe.android.paymentsheet.example.playground.settings.CollectAddressSettingsDefinition -import com.stripe.android.paymentsheet.example.playground.settings.CollectEmailSettingsDefinition -import com.stripe.android.paymentsheet.example.playground.settings.CollectNameSettingsDefinition -import com.stripe.android.paymentsheet.example.playground.settings.CollectPhoneSettingsDefinition import com.stripe.android.paymentsheet.example.playground.settings.Country import com.stripe.android.paymentsheet.example.playground.settings.CountrySettingsDefinition import com.stripe.android.paymentsheet.example.playground.settings.CustomerSettingsDefinition import com.stripe.android.paymentsheet.example.playground.settings.CustomerSheetPaymentMethodModeDefinition import com.stripe.android.paymentsheet.example.playground.settings.CustomerType -import com.stripe.android.paymentsheet.example.playground.settings.DefaultBillingAddress -import com.stripe.android.paymentsheet.example.playground.settings.DefaultBillingAddressSettingsDefinition import com.stripe.android.paymentsheet.example.playground.settings.PaymentMethodMode import com.stripe.android.test.core.TestParameters import org.junit.Test @@ -35,20 +28,6 @@ internal class TestCardInCustomerSheet : BasePlaygroundTest() { ) } - @Test - fun testCardWithSetupIntent() { - testDriver.savePaymentMethodInCustomerSheet( - TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> - settings[CustomerSettingsDefinition] = CustomerType.NEW - settings[CountrySettingsDefinition] = Country.US - settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.SetupIntent - }, - populateCustomLpmFields = { - populateCardDetails() - }, - ) - } - @Test fun testCardWithNonUsMerchant() { testDriver.savePaymentMethodInCustomerSheet( @@ -62,70 +41,4 @@ internal class TestCardInCustomerSheet : BasePlaygroundTest() { }, ) } - - @Test - fun testCardWithSetupIntentAndNonUsMerchant() { - testDriver.savePaymentMethodInCustomerSheet( - TestParameters.create(paymentMethodCode = "card").copyPlaygroundSettings { settings -> - settings[CustomerSettingsDefinition] = CustomerType.NEW - settings[CountrySettingsDefinition] = Country.FR - settings[CustomerSheetPaymentMethodModeDefinition] = PaymentMethodMode.SetupIntent - }, - populateCustomLpmFields = { - populateCardDetails() - }, - ) - } - - @Test - fun testCardWithBillingDetailsCollection() { - testDriver.savePaymentMethodInCustomerSheet( - TestParameters.create( - paymentMethodCode = "card", - ) { settings -> - settings[CustomerSettingsDefinition] = CustomerType.NEW - settings[CountrySettingsDefinition] = Country.US - settings[DefaultBillingAddressSettingsDefinition] = DefaultBillingAddress.Off - settings[CollectNameSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectEmailSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectPhoneSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectAddressSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full - }, - populateCustomLpmFields = { - populateCardDetails() - populateEmail() - populateName("Name on card") - populateAddress() - populatePhoneNumber() - }, - ) - } - - @Test - fun testCardWithBillingDetailsCollectionWithDefaults() { - testDriver.savePaymentMethodInCustomerSheet( - TestParameters.create( - paymentMethodCode = "card", - ) { settings -> - settings[CustomerSettingsDefinition] = CustomerType.NEW - settings[CountrySettingsDefinition] = Country.US - settings[DefaultBillingAddressSettingsDefinition] = DefaultBillingAddress.On - settings[CollectNameSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectEmailSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectPhoneSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always - settings[CollectAddressSettingsDefinition] = - PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full - }, - populateCustomLpmFields = { - populateCardDetails() - }, - ) - } } diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt index 52ef4f23389..8a72c1156a8 100644 --- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/PlaygroundTestDriver.kt @@ -1139,9 +1139,6 @@ internal class PlaygroundTestDriver( @OptIn(ExperimentalTestApi::class) private fun waitForManageSavedPaymentMethods() { - Espresso.onIdle() - composeTestRule.waitForIdle() - composeTestRule.waitUntilAtLeastOneExists( hasText("Manage your payment methods"), DEFAULT_UI_TIMEOUT.inWholeMilliseconds diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index cbe796b3559..9897dcb637f 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -106,13 +106,16 @@ internal class PaymentSheetPlaygroundActivity : AppCompatActivity(), ExternalPay val localPlaygroundSettings = playgroundSettings ?: return@setContent val playgroundState by viewModel.state.collectAsState() + val customerAdapter by viewModel.customerAdapter.collectAsState() val customerSheet = playgroundState?.asCustomerState()?.let { customerPlaygroundState -> - rememberCustomerSheet( - configuration = customerPlaygroundState.customerSheetConfiguration(), - customerAdapter = customerPlaygroundState.adapter, - callback = viewModel::onCustomerSheetCallback - ) + customerAdapter?.let { adapter -> + rememberCustomerSheet( + configuration = customerPlaygroundState.customerSheetConfiguration(), + customerAdapter = adapter, + callback = viewModel::onCustomerSheetCallback + ) + } } PlaygroundTheme( diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundViewModel.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundViewModel.kt index f4922d6ae43..a0492d77eeb 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundViewModel.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundViewModel.kt @@ -48,6 +48,7 @@ import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import java.io.IOException +@OptIn(ExperimentalCustomerSheetApi::class) internal class PaymentSheetPlaygroundViewModel( application: Application, launchUri: Uri?, @@ -61,6 +62,7 @@ internal class PaymentSheetPlaygroundViewModel( val state = MutableStateFlow(null) val flowControllerState = MutableStateFlow(null) val customerSheetState = MutableStateFlow(null) + val customerAdapter = MutableStateFlow(null) init { viewModelScope.launch(Dispatchers.IO) { @@ -76,6 +78,7 @@ internal class PaymentSheetPlaygroundViewModel( state.value = null flowControllerState.value = null customerSheetState.value = null + customerAdapter.value = null if (playgroundSettings.configurationData.value.integrationType.isPaymentFlow()) { prepareCheckout(playgroundSettings) @@ -149,23 +152,23 @@ internal class PaymentSheetPlaygroundViewModel( snapshot.saveToSharedPreferences(getApplication()) - state.value = PlaygroundState.Customer( - snapshot = snapshot, - adapter = CustomerAdapter.create( - context = getApplication(), - customerEphemeralKeyProvider = { - fetchEphemeralKey(snapshot) - }, - setupIntentClientSecretProvider = if ( - snapshot[CustomerSheetPaymentMethodModeDefinition] == PaymentMethodMode.SetupIntent - ) { - { customerId -> createSetupIntentClientSecret(snapshot, customerId) } - } else { - null - } - ) + val adapter = CustomerAdapter.create( + context = getApplication(), + customerEphemeralKeyProvider = { + fetchEphemeralKey(snapshot) + }, + setupIntentClientSecretProvider = if ( + snapshot[CustomerSheetPaymentMethodModeDefinition] == PaymentMethodMode.SetupIntent + ) { + { customerId -> createSetupIntentClientSecret(snapshot, customerId) } + } else { + null + } ) + customerSheetState.value = CustomerSheetState() + customerAdapter.value = adapter + state.value = PlaygroundState.Customer(snapshot = snapshot) } } diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PlaygroundState.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PlaygroundState.kt index 9a06ad7b868..9b0b1e10b48 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PlaygroundState.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PlaygroundState.kt @@ -1,7 +1,6 @@ package com.stripe.android.paymentsheet.example.playground import androidx.compose.runtime.Stable -import com.stripe.android.customersheet.CustomerAdapter import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.paymentsheet.PaymentSheet @@ -50,7 +49,6 @@ internal sealed interface PlaygroundState { @OptIn(ExperimentalCustomerSheetApi::class) data class Customer( private val snapshot: PlaygroundSettings.Snapshot, - val adapter: CustomerAdapter, ) : PlaygroundState { override val integrationType = snapshot.configurationData.integrationType override val countryCode = snapshot[CountrySettingsDefinition]