From c21d46a66e540a1ece271162b896427685a5dc4f Mon Sep 17 00:00:00 2001 From: VelikovPetar Date: Mon, 4 May 2026 22:47:57 +0200 Subject: [PATCH 1/2] fix: omit non-allowed message.type values on send/update wire payload Co-Authored-By: Claude --- .../chat/android/client/api2/MoshiChatApi.kt | 20 +++++++++-- .../android/client/api2/mapping/DtoMapping.kt | 10 ++++-- .../android/client/api2/MoshiChatApiTest.kt | 35 +++++++++++++++++++ .../client/api2/MoshiChatApiTestArguments.kt | 10 ++++++ .../client/api2/mapping/DtoMappingTest.kt | 10 ++++++ 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt index 2759ad342ea..97e9aa5f2c0 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt @@ -126,6 +126,7 @@ import io.getstream.chat.android.models.Member import io.getstream.chat.android.models.MemberData import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.MessageReminder +import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.Mute import io.getstream.chat.android.models.PendingMessage import io.getstream.chat.android.models.Poll @@ -243,7 +244,7 @@ constructor( channelType = channelType, channelId = channelId, message = SendMessageRequest( - message = with(dtoMapping) { message.toDto() }, + message = with(dtoMapping) { message.toDto(messageType = message.uploadMessageType) }, skip_push = message.skipPushNotification, skip_enrich_url = message.skipEnrichUrl, ), @@ -314,7 +315,7 @@ constructor( return messageApi.updateMessage( messageId = message.id, message = UpdateMessageRequest( - message = with(dtoMapping) { message.toDto() }, + message = with(dtoMapping) { message.toDto(messageType = message.uploadMessageType) }, skip_enrich_url = message.skipEnrichUrl, skip_push = message.skipPushNotification, ), @@ -1774,4 +1775,19 @@ constructor( private fun RetrofitCall.flatMapDomain(transform: DomainMapping.(T) -> Call): Call = flatMap { domainMapping.transform(it) } + + /** + * Value to send for `message.type` on outbound send/update requests. + * + * The backend's UpdateMessage endpoint validates `type` against `oneof='' regular system`, + * so server-assigned types like `reply`, `error`, or `ephemeral` would be rejected with a 400 + * if echoed back. Coerce anything outside the accepted set to the empty string — the field is + * ignored by the backend on update anyway, and on send only `regular` and `system` are + * meaningful for clients to declare. + */ + private val Message.uploadMessageType: String + get() = when (type) { + MessageType.REGULAR, MessageType.SYSTEM -> type + else -> "" + } } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt index dd92f451536..2fab5664f66 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt @@ -43,6 +43,7 @@ import io.getstream.chat.android.models.Member import io.getstream.chat.android.models.MemberData import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.MessageTransformer +import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.Mute import io.getstream.chat.android.models.Reaction import io.getstream.chat.android.models.User @@ -117,8 +118,13 @@ internal class DtoMapping( /** * Transforms [Message] to [UpstreamMessageDto]. + * + * @param messageType Value to use for [UpstreamMessageDto.type]. When `null` (the default), + * the message's own type is used. Callers in the network layer may pass an explicit value to + * satisfy server-side validation — for example, the UpdateMessage endpoint only accepts the + * empty string, [MessageType.REGULAR], or [MessageType.SYSTEM]. */ - internal fun Message.toDto(): UpstreamMessageDto = + internal fun Message.toDto(messageType: String? = null): UpstreamMessageDto = messageTransformer.transform(this) .run { UpstreamMessageDto( @@ -128,7 +134,7 @@ internal class DtoMapping( args = null, html = html, id = id, - type = type, + type = messageType ?: type, mentioned_users = mentionedUsersIds, parent_id = parentId, pin_expires = pinExpires, diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt index bd3674df140..a699a907016 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt @@ -71,12 +71,14 @@ import io.getstream.chat.android.client.api2.model.requests.RejectInviteRequest import io.getstream.chat.android.client.api2.model.requests.ReminderRequest import io.getstream.chat.android.client.api2.model.requests.SendActionRequest import io.getstream.chat.android.client.api2.model.requests.SendEventRequest +import io.getstream.chat.android.client.api2.model.requests.SendMessageRequest import io.getstream.chat.android.client.api2.model.requests.UnblockUserRequest import io.getstream.chat.android.client.api2.model.requests.UpdateChannelPartialRequest import io.getstream.chat.android.client.api2.model.requests.UpdateCooldownRequest import io.getstream.chat.android.client.api2.model.requests.UpdateLiveLocationRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialResponse +import io.getstream.chat.android.client.api2.model.requests.UpdateMessageRequest import io.getstream.chat.android.client.api2.model.requests.UpsertPushPreferencesRequest import io.getstream.chat.android.client.api2.model.requests.UpstreamOptionDto import io.getstream.chat.android.client.api2.model.requests.UpstreamVoteDto @@ -180,6 +182,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock @@ -314,6 +317,38 @@ internal class MoshiChatApiTest { verify(api, times(1)).updateMessage(eq(message.id), any()) } + @ParameterizedTest + @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#uploadMessageTypeInput") + fun testSendMessageCoercesType(inputType: String, expectedWireType: String) = runTest { + val api = mock() + val call = RetroSuccess(MessageResponse(message = Mother.randomDownstreamMessageDto())).toRetrofitCall() + whenever(api.sendMessage(any(), any(), any())).doReturn(call) + val sut = Fixture().withMessageApi(api).get() + val message = randomMessage(type = inputType) + + sut.sendMessage(randomString(), randomString(), message).await() + + val captor = argumentCaptor() + verify(api).sendMessage(any(), any(), captor.capture()) + assertEquals(expectedWireType, captor.firstValue.message.type) + } + + @ParameterizedTest + @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#uploadMessageTypeInput") + fun testUpdateMessageCoercesType(inputType: String, expectedWireType: String) = runTest { + val api = mock() + val call = RetroSuccess(MessageResponse(message = Mother.randomDownstreamMessageDto())).toRetrofitCall() + whenever(api.updateMessage(any(), any())).doReturn(call) + val sut = Fixture().withMessageApi(api).get() + val message = randomMessage(type = inputType) + + sut.updateMessage(message).await() + + val captor = argumentCaptor() + verify(api).updateMessage(eq(message.id), captor.capture()) + assertEquals(expectedWireType, captor.firstValue.message.type) + } + @ParameterizedTest @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#partialUpdateMessageInput") fun testPartialUpdateMessage(call: RetrofitCall, expected: KClass<*>) = runTest { diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt index cf2553f44a2..ed69405f3cb 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt @@ -67,6 +67,7 @@ import io.getstream.chat.android.client.api2.model.response.UsersResponse import io.getstream.chat.android.client.utils.RetroError import io.getstream.chat.android.client.utils.RetroSuccess import io.getstream.chat.android.models.EventType +import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.QueryRemindersResult import io.getstream.chat.android.models.UnreadChannel import io.getstream.chat.android.models.UnreadChannelByType @@ -112,6 +113,15 @@ internal object MoshiChatApiTestArguments { @JvmStatic fun updateMessageInput() = messageResponseArguments() + @JvmStatic + fun uploadMessageTypeInput() = listOf( + Arguments.of(MessageType.REGULAR, MessageType.REGULAR), + Arguments.of(MessageType.SYSTEM, MessageType.SYSTEM), + Arguments.of(MessageType.REPLY, ""), + Arguments.of(MessageType.ERROR, ""), + Arguments.of(MessageType.EPHEMERAL, ""), + ) + @JvmStatic fun partialUpdateMessageInput() = messageResponseArguments() diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt index baedd9a6b3c..5bfc68e848a 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt @@ -203,6 +203,16 @@ internal class DtoMappingTest { verify(messageTransformer, times(1)).transform(message) } + @Test + fun `Message toDto uses messageType parameter when provided`() { + val message = randomMessage(type = "reply") + val mapping = Fixture().get() + + val dto = with(mapping) { message.toDto(messageType = "") } + + dto.type shouldBeEqualTo "" + } + @Test fun `Mute is correctly mapped to Dto`() { val mute = randomMute() From 4151530f9fe567fcc9d3e44f4e61243ba449b36b Mon Sep 17 00:00:00 2001 From: VelikovPetar Date: Tue, 5 May 2026 12:28:24 +0200 Subject: [PATCH 2/2] Fix unable to edit thread replies. --- .../chat/android/client/api2/MoshiChatApi.kt | 20 ++--------- .../android/client/api2/mapping/DtoMapping.kt | 12 +++---- .../android/client/api2/MoshiChatApiTest.kt | 35 ------------------- .../client/api2/MoshiChatApiTestArguments.kt | 10 ------ .../client/api2/mapping/DtoMappingTest.kt | 31 ++++++++++++---- 5 files changed, 32 insertions(+), 76 deletions(-) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt index 97e9aa5f2c0..2759ad342ea 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/MoshiChatApi.kt @@ -126,7 +126,6 @@ import io.getstream.chat.android.models.Member import io.getstream.chat.android.models.MemberData import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.MessageReminder -import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.Mute import io.getstream.chat.android.models.PendingMessage import io.getstream.chat.android.models.Poll @@ -244,7 +243,7 @@ constructor( channelType = channelType, channelId = channelId, message = SendMessageRequest( - message = with(dtoMapping) { message.toDto(messageType = message.uploadMessageType) }, + message = with(dtoMapping) { message.toDto() }, skip_push = message.skipPushNotification, skip_enrich_url = message.skipEnrichUrl, ), @@ -315,7 +314,7 @@ constructor( return messageApi.updateMessage( messageId = message.id, message = UpdateMessageRequest( - message = with(dtoMapping) { message.toDto(messageType = message.uploadMessageType) }, + message = with(dtoMapping) { message.toDto() }, skip_enrich_url = message.skipEnrichUrl, skip_push = message.skipPushNotification, ), @@ -1775,19 +1774,4 @@ constructor( private fun RetrofitCall.flatMapDomain(transform: DomainMapping.(T) -> Call): Call = flatMap { domainMapping.transform(it) } - - /** - * Value to send for `message.type` on outbound send/update requests. - * - * The backend's UpdateMessage endpoint validates `type` against `oneof='' regular system`, - * so server-assigned types like `reply`, `error`, or `ephemeral` would be rejected with a 400 - * if echoed back. Coerce anything outside the accepted set to the empty string — the field is - * ignored by the backend on update anyway, and on send only `regular` and `system` are - * meaningful for clients to declare. - */ - private val Message.uploadMessageType: String - get() = when (type) { - MessageType.REGULAR, MessageType.SYSTEM -> type - else -> "" - } } diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt index 2fab5664f66..05bfc6f1639 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DtoMapping.kt @@ -54,6 +54,8 @@ internal class DtoMapping( private val userTransformer: UserTransformer, ) { + private val supportedUpstreamMessageTypes = setOf(MessageType.REGULAR, MessageType.SYSTEM) + /** * Converts [Attachment] to [AttachmentDto]. */ @@ -118,15 +120,11 @@ internal class DtoMapping( /** * Transforms [Message] to [UpstreamMessageDto]. - * - * @param messageType Value to use for [UpstreamMessageDto.type]. When `null` (the default), - * the message's own type is used. Callers in the network layer may pass an explicit value to - * satisfy server-side validation — for example, the UpdateMessage endpoint only accepts the - * empty string, [MessageType.REGULAR], or [MessageType.SYSTEM]. */ - internal fun Message.toDto(messageType: String? = null): UpstreamMessageDto = + internal fun Message.toDto(): UpstreamMessageDto = messageTransformer.transform(this) .run { + val upstreamType = if (type in supportedUpstreamMessageTypes) type else "" UpstreamMessageDto( attachments = attachments.map { it.toDto() }, cid = cid, @@ -134,7 +132,7 @@ internal class DtoMapping( args = null, html = html, id = id, - type = messageType ?: type, + type = upstreamType, mentioned_users = mentionedUsersIds, parent_id = parentId, pin_expires = pinExpires, diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt index a699a907016..bd3674df140 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTest.kt @@ -71,14 +71,12 @@ import io.getstream.chat.android.client.api2.model.requests.RejectInviteRequest import io.getstream.chat.android.client.api2.model.requests.ReminderRequest import io.getstream.chat.android.client.api2.model.requests.SendActionRequest import io.getstream.chat.android.client.api2.model.requests.SendEventRequest -import io.getstream.chat.android.client.api2.model.requests.SendMessageRequest import io.getstream.chat.android.client.api2.model.requests.UnblockUserRequest import io.getstream.chat.android.client.api2.model.requests.UpdateChannelPartialRequest import io.getstream.chat.android.client.api2.model.requests.UpdateCooldownRequest import io.getstream.chat.android.client.api2.model.requests.UpdateLiveLocationRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialRequest import io.getstream.chat.android.client.api2.model.requests.UpdateMemberPartialResponse -import io.getstream.chat.android.client.api2.model.requests.UpdateMessageRequest import io.getstream.chat.android.client.api2.model.requests.UpsertPushPreferencesRequest import io.getstream.chat.android.client.api2.model.requests.UpstreamOptionDto import io.getstream.chat.android.client.api2.model.requests.UpstreamVoteDto @@ -182,7 +180,6 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull -import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock @@ -317,38 +314,6 @@ internal class MoshiChatApiTest { verify(api, times(1)).updateMessage(eq(message.id), any()) } - @ParameterizedTest - @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#uploadMessageTypeInput") - fun testSendMessageCoercesType(inputType: String, expectedWireType: String) = runTest { - val api = mock() - val call = RetroSuccess(MessageResponse(message = Mother.randomDownstreamMessageDto())).toRetrofitCall() - whenever(api.sendMessage(any(), any(), any())).doReturn(call) - val sut = Fixture().withMessageApi(api).get() - val message = randomMessage(type = inputType) - - sut.sendMessage(randomString(), randomString(), message).await() - - val captor = argumentCaptor() - verify(api).sendMessage(any(), any(), captor.capture()) - assertEquals(expectedWireType, captor.firstValue.message.type) - } - - @ParameterizedTest - @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#uploadMessageTypeInput") - fun testUpdateMessageCoercesType(inputType: String, expectedWireType: String) = runTest { - val api = mock() - val call = RetroSuccess(MessageResponse(message = Mother.randomDownstreamMessageDto())).toRetrofitCall() - whenever(api.updateMessage(any(), any())).doReturn(call) - val sut = Fixture().withMessageApi(api).get() - val message = randomMessage(type = inputType) - - sut.updateMessage(message).await() - - val captor = argumentCaptor() - verify(api).updateMessage(eq(message.id), captor.capture()) - assertEquals(expectedWireType, captor.firstValue.message.type) - } - @ParameterizedTest @MethodSource("io.getstream.chat.android.client.api2.MoshiChatApiTestArguments#partialUpdateMessageInput") fun testPartialUpdateMessage(call: RetrofitCall, expected: KClass<*>) = runTest { diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt index ed69405f3cb..cf2553f44a2 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt @@ -67,7 +67,6 @@ import io.getstream.chat.android.client.api2.model.response.UsersResponse import io.getstream.chat.android.client.utils.RetroError import io.getstream.chat.android.client.utils.RetroSuccess import io.getstream.chat.android.models.EventType -import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.QueryRemindersResult import io.getstream.chat.android.models.UnreadChannel import io.getstream.chat.android.models.UnreadChannelByType @@ -113,15 +112,6 @@ internal object MoshiChatApiTestArguments { @JvmStatic fun updateMessageInput() = messageResponseArguments() - @JvmStatic - fun uploadMessageTypeInput() = listOf( - Arguments.of(MessageType.REGULAR, MessageType.REGULAR), - Arguments.of(MessageType.SYSTEM, MessageType.SYSTEM), - Arguments.of(MessageType.REPLY, ""), - Arguments.of(MessageType.ERROR, ""), - Arguments.of(MessageType.EPHEMERAL, ""), - ) - @JvmStatic fun partialUpdateMessageInput() = messageResponseArguments() diff --git a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt index 5bfc68e848a..cc155118c90 100644 --- a/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt +++ b/stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DtoMappingTest.kt @@ -35,6 +35,7 @@ import io.getstream.chat.android.client.api2.model.dto.UpstreamReactionDto import io.getstream.chat.android.client.api2.model.dto.UpstreamUserDto import io.getstream.chat.android.client.test.randomConnectedEvent import io.getstream.chat.android.models.MessageTransformer +import io.getstream.chat.android.models.MessageType import io.getstream.chat.android.models.NoOpMessageTransformer import io.getstream.chat.android.models.NoOpUserTransformer import io.getstream.chat.android.models.UserTransformer @@ -49,6 +50,9 @@ import io.getstream.chat.android.randomReaction import io.getstream.chat.android.randomUser import org.amshove.kluent.shouldBeEqualTo import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import org.mockito.kotlin.spy import org.mockito.kotlin.times import org.mockito.kotlin.verify @@ -168,7 +172,7 @@ internal class DtoMappingTest { @Test fun `Message is correctly mapped to Dto`() { val messageTransformer = spy(NoOpMessageTransformer) - val message = randomMessage() + val message = randomMessage(type = MessageType.REGULAR) val mapping = Fixture() .withMessageTransformer(messageTransformer) .get() @@ -203,14 +207,15 @@ internal class DtoMappingTest { verify(messageTransformer, times(1)).transform(message) } - @Test - fun `Message toDto uses messageType parameter when provided`() { - val message = randomMessage(type = "reply") + @ParameterizedTest + @MethodSource("messageTypeCoercionInput") + fun `Message toDto coerces type to allowed upstream values`(inputType: String, expectedType: String) { + val message = randomMessage(type = inputType) val mapping = Fixture().get() - val dto = with(mapping) { message.toDto(messageType = "") } + val dto = with(mapping) { message.toDto() } - dto.type shouldBeEqualTo "" + dto.type shouldBeEqualTo expectedType } @Test @@ -323,6 +328,20 @@ internal class DtoMappingTest { dto shouldBeEqualTo expected } + companion object { + @JvmStatic + fun messageTypeCoercionInput(): List = listOf( + Arguments.of(MessageType.REGULAR, MessageType.REGULAR), + Arguments.of(MessageType.SYSTEM, MessageType.SYSTEM), + Arguments.of(MessageType.REPLY, ""), + Arguments.of(MessageType.EPHEMERAL, ""), + Arguments.of(MessageType.ERROR, ""), + Arguments.of(MessageType.FAILED, ""), + Arguments.of("some-unknown-type", ""), + Arguments.of("", ""), + ) + } + internal class Fixture { private var messageTransformer: MessageTransformer = NoOpMessageTransformer