Skip to content

Commit f0930b1

Browse files
committed
parse all error messages
1 parent c988402 commit f0930b1

3 files changed

Lines changed: 60 additions & 10 deletions

File tree

platforms/android/lib/api/lib.api

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,35 @@ public final class com/shopify/checkoutkit/CheckoutError$Companion {
664664
public final fun serializer ()Lkotlinx/serialization/KSerializer;
665665
}
666666

667+
public final class com/shopify/checkoutkit/CheckoutErrorResponse {
668+
public static final field Companion Lcom/shopify/checkoutkit/CheckoutErrorResponse$Companion;
669+
public fun <init> ()V
670+
public final fun component1 ()Ljava/util/List;
671+
public final fun component2 ()Ljava/lang/String;
672+
public final fun copy (Ljava/util/List;Ljava/lang/String;)Lcom/shopify/checkoutkit/CheckoutErrorResponse;
673+
public static synthetic fun copy$default (Lcom/shopify/checkoutkit/CheckoutErrorResponse;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lcom/shopify/checkoutkit/CheckoutErrorResponse;
674+
public fun equals (Ljava/lang/Object;)Z
675+
public final fun getContinueUrl ()Ljava/lang/String;
676+
public final fun getMessages ()Ljava/util/List;
677+
public fun hashCode ()I
678+
public fun toString ()Ljava/lang/String;
679+
}
680+
681+
public final class com/shopify/checkoutkit/CheckoutErrorResponse$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
682+
public static final field INSTANCE Lcom/shopify/checkoutkit/CheckoutErrorResponse$$serializer;
683+
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
684+
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/shopify/checkoutkit/CheckoutErrorResponse;
685+
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
686+
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
687+
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/shopify/checkoutkit/CheckoutErrorResponse;)V
688+
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
689+
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
690+
}
691+
692+
public final class com/shopify/checkoutkit/CheckoutErrorResponse$Companion {
693+
public final fun serializer ()Lkotlinx/serialization/KSerializer;
694+
}
695+
667696
public abstract interface class com/shopify/checkoutkit/CheckoutEventProcessor {
668697
public abstract fun onCheckoutCanceled ()V
669698
public abstract fun onCheckoutCompleted (Lcom/shopify/checkoutkit/lifecycleevents/CheckoutCompletedEvent;)V

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)