@@ -9,6 +9,10 @@ import com.stripe.android.paymentelement.CheckoutSessionPreview
99import com.stripe.android.paymentelement.confirmation.ConfirmationHandler
1010import com.stripe.android.paymentelement.confirmation.FakeConfirmationHandler
1111import com.stripe.android.paymentelement.confirmation.FakeConfirmationOption
12+ import com.stripe.android.paymentelement.confirmation.MutableConfirmationMetadata
13+ import com.stripe.android.paymentelement.confirmation.intent.CheckoutSessionResponseKey
14+ import com.stripe.android.paymentsheet.repositories.CheckoutSessionResponse
15+ import com.stripe.android.paymentsheet.repositories.CheckoutSessionResponseFactory
1216import kotlinx.coroutines.flow.MutableStateFlow
1317import kotlinx.coroutines.test.TestCoroutineScheduler
1418import kotlinx.coroutines.test.runTest
@@ -18,30 +22,73 @@ import org.junit.Test
1822internal class CheckoutConfirmationResultHandlerTest {
1923
2024 @Test
21- fun `register handles current complete result` () {
22- runScenario(initialResult = succeeded()) {
23- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Completed >()
25+ fun `register handles current complete response before invoking callback` () {
26+ val response = response(status = CheckoutSessionResponse .Status .COMPLETE )
27+
28+ runScenario(initialResult = succeeded(response)) {
29+ val callbackCall = callbackCalls.awaitItem()
30+ assertThat(callbackCall.result).isInstanceOf<CheckoutController .Result .Completed >()
31+ assertThat(callbackCall.succeededCallCount).isEqualTo(1 )
32+ assertThat(callbackCall.succeededResponse).isEqualTo(response)
2433 }
2534 }
2635
2736 @Test
28- fun `succeeded result invokes Completed` () = runScenario {
29- emit(succeeded() )
37+ fun `succeeded with open response passes it to success handler and invokes Completed` () = runScenario {
38+ val response = response(status = CheckoutSessionResponse . Status . OPEN )
3039
31- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Completed >()
40+ emit(succeeded(response))
41+
42+ val callbackCall = callbackCalls.awaitItem()
43+ assertThat(callbackCall.result).isInstanceOf<CheckoutController .Result .Completed >()
44+ assertThat(callbackCall.succeededResponse).isEqualTo(response)
45+ }
46+
47+ @Test
48+ fun `succeeded with unknown response passes it to success handler and invokes Completed` () = runScenario {
49+ val response = response(status = CheckoutSessionResponse .Status .UNKNOWN )
50+
51+ emit(succeeded(response))
52+
53+ val callbackCall = callbackCalls.awaitItem()
54+ assertThat(callbackCall.result).isInstanceOf<CheckoutController .Result .Completed >()
55+ assertThat(callbackCall.succeededResponse).isEqualTo(response)
56+ }
57+
58+ @Test
59+ fun `succeeded with expired response passes it to success handler and invokes Completed` () = runScenario {
60+ val response = response(status = CheckoutSessionResponse .Status .EXPIRED )
61+
62+ emit(succeeded(response))
63+
64+ val callbackCall = callbackCalls.awaitItem()
65+ assertThat(callbackCall.result).isInstanceOf<CheckoutController .Result .Completed >()
66+ assertThat(callbackCall.succeededResponse).isEqualTo(response)
67+ }
68+
69+ @Test
70+ fun `succeeded result without response invokes success handler before Completed` () = runScenario {
71+ emit(ConfirmationHandler .Result .Succeeded (PaymentIntentFixtures .PI_SUCCEEDED ))
72+
73+ val callbackCall = callbackCalls.awaitItem()
74+ assertThat(callbackCall.result).isInstanceOf<CheckoutController .Result .Completed >()
75+ assertThat(callbackCall.succeededCallCount).isEqualTo(1 )
76+ assertThat(callbackCall.succeededResponse).isNull()
3277 }
3378
3479 @Test
3580 fun `each confirmation completion delivers its own callback` () = runScenario {
36- emit(succeeded())
37- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Completed >()
81+ val response = response(status = CheckoutSessionResponse .Status .COMPLETE )
82+
83+ emit(succeeded(response))
84+ assertThat(callbackCalls.awaitItem().result).isInstanceOf<CheckoutController .Result .Completed >()
3885
3986 // A second confirmation returns to Confirming before completing again. The interleaved
4087 // Confirming breaks the state flow's de-duplication, so an identical result still delivers.
4188 emitConfirming()
42- emit(succeeded())
89+ emit(succeeded(response ))
4390
44- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Completed >()
91+ assertThat(callbackCalls.awaitItem().result ).isInstanceOf<CheckoutController .Result .Completed >()
4592 }
4693
4794 @Test
@@ -56,7 +103,7 @@ internal class CheckoutConfirmationResultHandlerTest {
56103 )
57104 )
58105
59- val result = callbackCalls.awaitItem()
106+ val result = callbackCalls.awaitItem().result
60107 assertThat(result).isInstanceOf<CheckoutController .Result .Failed >()
61108 assertThat((result as CheckoutController .Result .Failed ).error).isEqualTo(cause)
62109 }
@@ -69,7 +116,7 @@ internal class CheckoutConfirmationResultHandlerTest {
69116 )
70117 )
71118
72- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Canceled >()
119+ assertThat(callbackCalls.awaitItem().result ).isInstanceOf<CheckoutController .Result .Canceled >()
73120 }
74121
75122 @Test
@@ -104,15 +151,17 @@ internal class CheckoutConfirmationResultHandlerTest {
104151 )
105152 )
106153
107- assertThat(callbackCalls.awaitItem()).isInstanceOf<CheckoutController .Result .Canceled >()
154+ assertThat(callbackCalls.awaitItem().result ).isInstanceOf<CheckoutController .Result .Canceled >()
108155 }
109156
110157 private fun runScenario (
111158 initialResult : ConfirmationHandler .Result ? = null,
112159 hasReloadedFromProcessDeath : Boolean = false,
113160 block : suspend Scenario .() -> Unit ,
114161 ) = runTest {
115- val callbackCalls = Turbine <CheckoutController .Result >()
162+ val callbackCalls = Turbine <CallbackCall >()
163+ var succeededCallCount = 0
164+ var succeededResponse: CheckoutSessionResponse ? = null
116165 val initialConfirmationState: ConfirmationHandler .State =
117166 initialResult?.let (ConfirmationHandler .State ::Complete )
118167 ? : ConfirmationHandler .State .Idle
@@ -122,10 +171,21 @@ internal class CheckoutConfirmationResultHandlerTest {
122171 )
123172 val handler = CheckoutConfirmationResultHandler (
124173 confirmationHandler = confirmationHandler,
125- resultCallback = CheckoutController .ResultCallback (callbackCalls::add),
174+ resultCallback = CheckoutController .ResultCallback { result ->
175+ callbackCalls.add(
176+ CallbackCall (
177+ result = result,
178+ succeededCallCount = succeededCallCount,
179+ succeededResponse = succeededResponse,
180+ )
181+ )
182+ },
126183 viewModelScope = backgroundScope,
127184 )
128- handler.register()
185+ handler.register { response ->
186+ succeededCallCount + = 1
187+ succeededResponse = response
188+ }
129189 testScheduler.runCurrent()
130190
131191 Scenario (
@@ -138,13 +198,29 @@ internal class CheckoutConfirmationResultHandlerTest {
138198 callbackCalls.ensureAllEventsConsumed()
139199 }
140200
141- private fun succeeded (): ConfirmationHandler .Result .Succeeded {
142- return ConfirmationHandler .Result .Succeeded (PaymentIntentFixtures .PI_SUCCEEDED )
201+ private fun response (
202+ status : CheckoutSessionResponse .Status ,
203+ ): CheckoutSessionResponse {
204+ return CheckoutSessionResponseFactory .create(
205+ id = " cs_confirmed" ,
206+ status = status,
207+ )
208+ }
209+
210+ private fun succeeded (
211+ response : CheckoutSessionResponse ,
212+ ): ConfirmationHandler .Result .Succeeded {
213+ return ConfirmationHandler .Result .Succeeded (
214+ intent = PaymentIntentFixtures .PI_SUCCEEDED ,
215+ metadata = MutableConfirmationMetadata ().apply {
216+ set(CheckoutSessionResponseKey , response)
217+ },
218+ )
143219 }
144220
145221 private class Scenario (
146222 val confirmationHandler : FakeConfirmationHandler ,
147- val callbackCalls : Turbine <CheckoutController . Result >,
223+ val callbackCalls : Turbine <CallbackCall >,
148224 val testScheduler : TestCoroutineScheduler ,
149225 ) {
150226 fun emit (result : ConfirmationHandler .Result ) {
@@ -159,4 +235,9 @@ internal class CheckoutConfirmationResultHandlerTest {
159235 }
160236 }
161237
238+ private data class CallbackCall (
239+ val result : CheckoutController .Result ,
240+ val succeededCallCount : Int ,
241+ val succeededResponse : CheckoutSessionResponse ? ,
242+ )
162243}
0 commit comments