fix: prevent crash when Google Pay is presented after activity is backgrounded#2414
fix: prevent crash when Google Pay is presented after activity is backgrounded#2414simpson-peter wants to merge 1 commit into
Conversation
|
|
jaynewstrom-stripe
left a comment
There was a problem hiding this comment.
Thanks for this fix! The lifecycle check makes sense. I'd suggest adding an automated test to cover this behavior. Here's what I'd recommend:
1. Make onGooglePayReady testable
Change the visibility of onGooglePayReady from private to @VisibleForTesting internal:
import androidx.annotation.VisibleForTesting
@VisibleForTesting
internal fun onGooglePayReady(isReady: Boolean) {2. Add test file
Create android/src/test/java/com/reactnativestripesdk/GooglePayLauncherManagerTest.kt:
package com.reactnativestripesdk
import androidx.lifecycle.Lifecycle
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.WritableMap
import com.reactnativestripesdk.utils.GooglePayErrorType
import com.reactnativestripesdk.utils.readableMapOf
import com.stripe.android.googlepaylauncher.GooglePayLauncher
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.android.controller.ActivityController
import androidx.fragment.app.FragmentActivity
@RunWith(RobolectricTestRunner::class)
class GooglePayLauncherManagerTest {
private lateinit var activityController: ActivityController<FragmentActivity>
private lateinit var context: ReactApplicationContext
private var callbackResult: GooglePayLauncher.Result? = null
private var callbackError: WritableMap? = null
private val callback: (GooglePayLauncher.Result?, WritableMap?) -> Unit = { result, error ->
callbackResult = result
callbackError = error
}
@Before
fun setup() {
activityController = Robolectric.buildActivity(FragmentActivity::class.java)
callbackResult = null
callbackError = null
}
private fun createManager(activity: FragmentActivity): GooglePayLauncherManager {
context = mock(ReactApplicationContext::class.java)
org.mockito.Mockito.`when`(context.currentActivity).thenReturn(activity)
val googlePayParams = readableMapOf(
"testEnv" to true,
"merchantCountryCode" to "US",
"merchantName" to "Test",
"currencyCode" to "USD",
)
return GooglePayLauncherManager(
context = context,
clientSecret = "pi_test_secret",
mode = GooglePayLauncherManager.Mode.ForPayment,
googlePayParams = googlePayParams,
callback = callback,
)
}
@Test
fun onGooglePayReady_whenLifecycleNotStarted_callsCallbackWithCanceledError() {
val activity = activityController.create().get()
// Activity is in CREATED state, not STARTED
val manager = createManager(activity)
manager.onGooglePayReady(true)
assertNull(callbackResult)
assertNotNull(callbackError)
val errorMap = callbackError!!.getMap("error")
assertNotNull(errorMap)
assertEquals(GooglePayErrorType.Canceled.toString(), errorMap!!.getString("code"))
assertEquals("Google Pay has been canceled", errorMap.getString("message"))
}
@Test
fun onGooglePayReady_whenNotReady_callsCallbackWithFailedError() {
val activity = activityController.create().start().get()
val manager = createManager(activity)
manager.onGooglePayReady(false)
assertNull(callbackResult)
assertNotNull(callbackError)
val errorMap = callbackError!!.getMap("error")
assertNotNull(errorMap)
assertEquals(GooglePayErrorType.Failed.toString(), errorMap!!.getString("code"))
}
}The key test (onGooglePayReady_whenLifecycleNotStarted_callsCallbackWithCanceledError) verifies that when the activity is in CREATED state (simulating being backgrounded), the callback receives a canceled error instead of crashing.
Summary
This PR adds a lifecycle check to
GooglePayLauncherManager.onGooglePayReadywhich surfaces an error if the lifecycle is not at leastSTARTED.I have read through the contribution guidelines and done my best to adhere to them. Please let me know if there are any changes to this PR that you would like to see with respect to the guidelines. Thank you for your time.
Motivation
I have been encountering a crash via the flutter-stripe package which occurs when a google pay transaction is initiated and then the app is briefly (~1 second) backgrounded. I have manually confirmed that this change prevents the crash in the described situation.
Testing
Documentation
Select one: