Skip to content

Commit

Permalink
Add & clean up test utilities for confirmation (#9683)
Browse files Browse the repository at this point in the history
  • Loading branch information
samer-stripe authored Nov 20, 2024
1 parent 736ffc4 commit 7b8f59a
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,112 @@
package com.stripe.android.paymentelement.confirmation

import android.os.Parcelable
import androidx.activity.result.ActivityResultCallback
import androidx.lifecycle.SavedStateHandle
import com.google.common.truth.Truth.assertThat
import com.stripe.android.isInstanceOf
import com.stripe.android.model.StripeIntent
import com.stripe.android.paymentelement.confirmation.ConfirmationMediator.Parameters
import com.stripe.android.paymentelement.confirmation.epms.ExternalPaymentMethodConfirmationOption
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.android.utils.DummyActivityResultCaller
import kotlinx.coroutines.test.runTest
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

internal fun <
TConfirmationOption : ConfirmationHandler.Option,
TLauncher,
TLauncherArgs,
TLauncherResult : Parcelable
> runLaunchTest(
definition: ConfirmationDefinition<TConfirmationOption, TLauncher, TLauncherArgs, TLauncherResult>,
confirmationOption: ConfirmationHandler.Option,
intent: StripeIntent,
) = runTest {
val savedStateHandle = SavedStateHandle()
val mediator = ConfirmationMediator(savedStateHandle, definition)

DummyActivityResultCaller.test {
mediator.register(
activityResultCaller = activityResultCaller,
onResult = {}
)

val action = mediator.action(
option = confirmationOption,
intent = intent,
)

assertThat(action).isInstanceOf<ConfirmationMediator.Action.Launch>()

val launchAction = action.asLaunch()

launchAction.launch()

val parameters = savedStateHandle
.get<Parameters<ExternalPaymentMethodConfirmationOption>>("ExternalPaymentMethodParameters")

assertThat(parameters?.confirmationOption).isEqualTo(confirmationOption)
assertThat(parameters?.intent).isEqualTo(intent)
assertThat(parameters?.deferredIntentConfirmationType).isNull()

assertThat(awaitRegisterCall()).isNotNull()
assertThat(awaitLaunchCall()).isNotNull()
}
}

internal fun <
TConfirmationOption : ConfirmationHandler.Option,
TLauncher,
TLauncherArgs,
TLauncherResult : Parcelable
> runResultTest(
definition: ConfirmationDefinition<TConfirmationOption, TLauncher, TLauncherArgs, TLauncherResult>,
confirmationOption: ConfirmationHandler.Option,
intent: StripeIntent,
) = runTest {
val countDownLatch = CountDownLatch(1)

val savedStateHandle = SavedStateHandle().apply {
set(
"${definition.key}Parameters",
Parameters(
confirmationOption = confirmationOption,
intent = intent,
deferredIntentConfirmationType = null,
)
)
}

DummyActivityResultCaller.test {
val mediator = ConfirmationMediator(savedStateHandle, definition)

var result: ConfirmationHandler.Result? = null

mediator.register(
activityResultCaller = activityResultCaller,
onResult = {
result = it

countDownLatch.countDown()
}
)

val call = awaitRegisterCall()

call.callback.asCallbackFor<PaymentResult>().onActivityResult(PaymentResult.Completed)

assertThat(countDownLatch.await(5, TimeUnit.SECONDS)).isTrue()

assertThat(result).isInstanceOf<ConfirmationHandler.Result.Succeeded>()

val successResult = result.asSucceeded()

assertThat(successResult.intent).isEqualTo(intent)
}
}

internal fun ConfirmationHandler.Result?.asSucceeded(): ConfirmationHandler.Result.Succeeded {
return this as ConfirmationHandler.Result.Succeeded
}
Expand All @@ -25,3 +132,8 @@ internal fun <T> ConfirmationDefinition.ConfirmationAction<T>.asLaunch():
internal fun ConfirmationMediator.Action.asLaunch(): ConfirmationMediator.Action.Launch {
return this as ConfirmationMediator.Action.Launch
}

internal fun <T> ActivityResultCallback<*>.asCallbackFor(): ActivityResultCallback<T> {
@Suppress("UNCHECKED_CAST")
return this as ActivityResultCallback<T>
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.stripe.android.model.PaymentMethod
import com.stripe.android.paymentelement.confirmation.ConfirmationDefinition
import com.stripe.android.paymentelement.confirmation.ConfirmationHandler
import com.stripe.android.paymentelement.confirmation.FakeConfirmationOption
import com.stripe.android.paymentelement.confirmation.asCallbackFor
import com.stripe.android.paymentelement.confirmation.asCanceled
import com.stripe.android.paymentelement.confirmation.asFail
import com.stripe.android.paymentelement.confirmation.asFailed
Expand Down Expand Up @@ -71,7 +72,7 @@ class ExternalPaymentMethodConfirmationDefinitionTest {

assertThat(call.callback).isInstanceOf<ActivityResultCallback<PaymentResult>>()

val callback = call.callback.asExternalPaymentMethodCallback()
val callback = call.callback.asCallbackFor<PaymentResult>()

assertThat(externalPaymentMethodContract.errorReporter).isEqualTo(errorReporter)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,103 +1,33 @@
package com.stripe.android.paymentelement.confirmation.epms

import androidx.lifecycle.SavedStateHandle
import com.google.common.truth.Truth.assertThat
import com.stripe.android.isInstanceOf
import com.stripe.android.model.Address
import com.stripe.android.model.PaymentMethod
import com.stripe.android.paymentelement.confirmation.ConfirmationHandler
import com.stripe.android.paymentelement.confirmation.ConfirmationMediator
import com.stripe.android.paymentelement.confirmation.ConfirmationMediator.Parameters
import com.stripe.android.paymentelement.confirmation.asLaunch
import com.stripe.android.paymentelement.confirmation.asSucceeded
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.android.paymentelement.confirmation.runLaunchTest
import com.stripe.android.paymentelement.confirmation.runResultTest
import com.stripe.android.paymentsheet.ExternalPaymentMethodConfirmHandler
import com.stripe.android.testing.FakeErrorReporter
import com.stripe.android.testing.PaymentIntentFactory
import com.stripe.android.utils.DummyActivityResultCaller
import kotlinx.coroutines.test.runTest
import org.junit.Test
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

class ExternalPaymentMethodConfirmationFlowTest {
@Test
fun `on launch, should persist parameters & launch using launcher as expected`() = runTest {
val savedStateHandle = SavedStateHandle()
val mediator = createExternalPaymentMethodConfirmationMediator(savedStateHandle)

DummyActivityResultCaller.test {
mediator.register(
activityResultCaller = activityResultCaller,
onResult = {}
)

val action = mediator.action(
option = EPM_CONFIRMATION_OPTION,
intent = PAYMENT_INTENT,
)

assertThat(action).isInstanceOf<ConfirmationMediator.Action.Launch>()

val launchAction = action.asLaunch()

launchAction.launch()

val parameters = savedStateHandle
.get<Parameters<ExternalPaymentMethodConfirmationOption>>("ExternalPaymentMethodParameters")

assertThat(parameters?.confirmationOption).isEqualTo(EPM_CONFIRMATION_OPTION)
assertThat(parameters?.intent).isEqualTo(PAYMENT_INTENT)
assertThat(parameters?.deferredIntentConfirmationType).isNull()

assertThat(awaitRegisterCall()).isNotNull()
assertThat(awaitLaunchCall()).isNotNull()
}
}

@Test
fun `on result, should return confirmation result as expected`() = runTest {
val countDownLatch = CountDownLatch(1)

val savedStateHandle = SavedStateHandle().apply {
set(
"ExternalPaymentMethodParameters",
Parameters(
confirmationOption = EPM_CONFIRMATION_OPTION,
intent = PAYMENT_INTENT,
deferredIntentConfirmationType = null,
)
)
}

DummyActivityResultCaller.test {
val mediator = createExternalPaymentMethodConfirmationMediator(savedStateHandle)
var result: ConfirmationHandler.Result? = null

mediator.register(
activityResultCaller = activityResultCaller,
onResult = {
result = it
fun `on launch, should persist parameters & launch using launcher as expected`() = runLaunchTest(
confirmationOption = EPM_CONFIRMATION_OPTION,
intent = PAYMENT_INTENT,
definition = ExternalPaymentMethodConfirmationDefinition(
externalPaymentMethodConfirmHandlerProvider = {
ExternalPaymentMethodConfirmHandler { _, _ ->
error("Not implemented!")
}
)

val call = awaitRegisterCall()

call.callback.asExternalPaymentMethodCallback().onActivityResult(PaymentResult.Completed)

countDownLatch.await(5, TimeUnit.SECONDS)

assertThat(result).isInstanceOf<ConfirmationHandler.Result.Succeeded>()

val successResult = result.asSucceeded()

assertThat(successResult.intent).isEqualTo(PAYMENT_INTENT)
}
}
},
errorReporter = FakeErrorReporter()
),
)

private fun createExternalPaymentMethodConfirmationMediator(
savedStateHandle: SavedStateHandle = SavedStateHandle()
) = ConfirmationMediator(
@Test
fun `on result, should return confirmation result as expected`() = runResultTest(
confirmationOption = EPM_CONFIRMATION_OPTION,
intent = PAYMENT_INTENT,
definition = ExternalPaymentMethodConfirmationDefinition(
externalPaymentMethodConfirmHandlerProvider = {
ExternalPaymentMethodConfirmHandler { _, _ ->
Expand All @@ -106,7 +36,6 @@ class ExternalPaymentMethodConfirmationFlowTest {
},
errorReporter = FakeErrorReporter()
),
savedStateHandle = savedStateHandle
)

private companion object {
Expand Down

This file was deleted.

0 comments on commit 7b8f59a

Please sign in to comment.