Skip to content

Commit 60bf0d1

Browse files
committed
parse all error messages
1 parent c988402 commit 60bf0d1

2 files changed

Lines changed: 31 additions & 10 deletions

File tree

platforms/android/lib/src/main/java/com/shopify/checkoutkit/CheckoutProtocol.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import android.net.Uri
2626
import android.os.Looper
2727
import androidx.core.net.toUri
2828
import com.shopify.checkoutkit.ShopifyCheckoutKit.log
29+
import kotlinx.serialization.SerialName
2930
import kotlinx.serialization.Serializable
3031
import kotlinx.serialization.json.Json
3132
import kotlinx.serialization.json.JsonElement
@@ -67,14 +68,14 @@ public object CheckoutProtocol {
6768
public val lineItemsChange: NotificationDescriptor<Checkout> = checkoutDescriptor("ec.line_items.change")
6869
internal val buyerChange: NotificationDescriptor<Checkout> = checkoutDescriptor("ec.buyer.change")
6970
public val totalsChange: NotificationDescriptor<Checkout> = checkoutDescriptor("ec.totals.change")
70-
public val error: NotificationDescriptor<CheckoutError> = NotificationDescriptor(
71+
public val error: NotificationDescriptor<CheckoutErrorResponse> = NotificationDescriptor(
7172
method = "ec.error",
7273
decode = { params ->
73-
params?.jsonObject?.get("messages")?.let {
74+
params?.let {
7475
try {
75-
json.decodeFromJsonElement<List<CheckoutError>>(it).firstOrNull()
76+
json.decodeFromJsonElement<CheckoutErrorResponse>(it)
7677
} catch (e: Exception) {
77-
log.d(BaseWebView.ECP_LOG_TAG, "Failed to decode ec.error messages: $e raw=$it")
78+
log.d(BaseWebView.ECP_LOG_TAG, "Failed to decode ec.error params: $e raw=$it")
7879
null
7980
}
8081
}
@@ -320,7 +321,20 @@ internal sealed class WindowOpenResult {
320321
data class Rejected(val reason: String? = null) : WindowOpenResult()
321322
}
322323

323-
/** Payload delivered with the [CheckoutProtocol.error] notification. */
324+
/**
325+
* Payload delivered with the [CheckoutProtocol.error] notification.
326+
*
327+
* Mirrors the UCP `ec.error` params shape — a session-fatal envelope carrying the full
328+
* list of error [messages] (consumers should iterate, not assume a single message) and
329+
* an optional [continueUrl] for buyer handoff or session recovery.
330+
*/
331+
@Serializable
332+
public data class CheckoutErrorResponse internal constructor(
333+
public val messages: List<CheckoutError> = emptyList(),
334+
@SerialName("continue_url") public val continueUrl: String? = null,
335+
)
336+
337+
/** A single error message inside a [CheckoutErrorResponse]. */
324338
@Serializable
325339
public data class CheckoutError internal constructor(
326340
public val code: String? = null,

platforms/android/lib/src/test/java/com/shopify/checkoutkit/CheckoutProtocolTest.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,25 @@ class CheckoutProtocolTest {
135135

136136
@Test
137137
fun `process dispatches ec error to registered handler with decoded payload`() {
138-
var received: CheckoutError? = null
138+
var received: CheckoutErrorResponse? = null
139139
val client = CheckoutProtocol.Client()
140140
.on(CheckoutProtocol.error) { received = it }
141141

142142
val errorMsg = """{"jsonrpc":"2.0","method":"ec.error","params":""" +
143-
"""{"messages":[{"code":"unknown_error","content":"fail","severity":"unrecoverable"}]}}"""
143+
"""{"messages":[""" +
144+
"""{"code":"unknown_error","content":"fail","severity":"unrecoverable"},""" +
145+
"""{"code":"session_expired","content":"expired","severity":"recoverable"}""" +
146+
"""],"continue_url":"https://example.com/retry"}}"""
144147
client.process(errorMsg)
145148
shadowOf(Looper.getMainLooper()).runToEndOfTasks()
146149

147-
assertThat(received?.code).isEqualTo("unknown_error")
148-
assertThat(received?.content).isEqualTo("fail")
149-
assertThat(received?.severity).isEqualTo("unrecoverable")
150+
assertThat(received?.messages).hasSize(2)
151+
assertThat(received?.messages?.get(0)?.code).isEqualTo("unknown_error")
152+
assertThat(received?.messages?.get(0)?.content).isEqualTo("fail")
153+
assertThat(received?.messages?.get(0)?.severity).isEqualTo("unrecoverable")
154+
assertThat(received?.messages?.get(1)?.code).isEqualTo("session_expired")
155+
assertThat(received?.messages?.get(1)?.severity).isEqualTo("recoverable")
156+
assertThat(received?.continueUrl).isEqualTo("https://example.com/retry")
150157
}
151158

152159
@Test

0 commit comments

Comments
 (0)