Skip to content

compose: Announce message sender to screen readers#6504

Draft
andremion wants to merge 1 commit into
developfrom
feature/and-1239-message-sender-a11y
Draft

compose: Announce message sender to screen readers#6504
andremion wants to merge 1 commit into
developfrom
feature/and-1239-message-sender-a11y

Conversation

@andremion

@andremion andremion commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Goal

TalkBack does not announce who sent a message, so screen reader users cannot tell the author. The author name is shown only visually, and the visual grouping that hides it on consecutive messages from the same user is a sighted-only concept (design decision DS-035). This change announces the sender on every message for screen readers.

Resolves AND-1239.

Implementation

The sender is announced once per message, on a single content leaf, independent of the visual grouping:

  • Text, emoji, and poll messages prefix the content: "[sender] said, [content]".
  • Attachment messages (single image/video, multiple media, file, voice message, sent giphy) carry the sender on a non-clickable wrapper around the content, so the message row announces "[sender] said, [content]" while the attachment card stays individually focusable.
  • Deleted messages are attributed too.
  • Reply messages announce "replied" instead of "said".

Outgoing messages announce "You said"; incoming messages name the sender. A shared senderAwareContentDescription helper builds the label, and an additive AttachmentState.announceSender flag marks the single attachment that carries the sender. The new strings are translated in all supported locales.

Custom and unsupported attachments are intentionally left to the integrator, since their content is integrator-defined.

Testing

No visual changes (accessibility semantics only). Covered by unit tests in MessageContainerSenderAttributionTest.

Manual: enable TalkBack, open a channel, and focus the message rows:

  1. Outgoing text -> "You said, [text]".
  2. Incoming text -> "[sender] said, [text]".
  3. Single image / video -> "[sender] said, Image attachment / Video attachment".
  4. Multiple images -> "[sender] said, N attachments"; swipe into the grid to focus each tile.
  5. File -> "[sender] said, [filename]".
  6. Voice message -> "[sender] said, Voice message".
  7. Sent giphy -> "[sender] said, [title], GIPHY".
  8. Text + attachment -> both the attachment label and "[sender] said, [text]" are announced.
  9. Poll -> "[sender] said, [poll question]".
  10. Deleted message -> "[sender] said, Message deleted".
  11. Reply -> "[sender] replied, [text]"; the quoted preview stays a separate, tappable stop.

Summary by CodeRabbit

Release Notes

New Features

  • Enhanced screen reader support with sender attribution for messages and attachments.
  • Improved accessibility labels for audio, file, Giphy, and media attachments.
  • Better announcement of deleted messages and replies for screen readers.
  • Added multilingual accessibility strings in Spanish, French, Hindi, Indonesian, Italian, Japanese, and Korean.

Tests

  • Added comprehensive accessibility tests for message sender attribution across various attachment types and scenarios.

Add per-message sender attribution for TalkBack so every message announces who sent it, independent of the visual grouping that hides the author name on consecutive messages from the same user.

The sender is announced once per message:
- Text messages prefix the text with "You said" / "{sender} said".
- Attachment messages (image, video, multiple media, file, voice message, giphy) announce the sender on the attachment label, with the attachment card still individually focusable.
- Poll and deleted messages are attributed too.
- Reply messages announce "replied" instead of "said".

A shared senderAwareContentDescription helper builds the label, and an additive AttachmentState.announceSender flag marks the single attachment that carries the sender. Adds translations for the new strings in all supported locales.
@andremion andremion added the pr:new-feature New feature label Jun 17, 2026
@andremion

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds sender-aware TalkBack accessibility content descriptions across all Compose message UI components. A new MessageSenderDescription.kt helper derives localized "You said / X said / You replied / X replied" strings. AttachmentState gains an announceSender boolean, MessageContent routes it to each attachment type, and all attachment content composables receive outer Box semantics wrappers. Eight locales receive the new strings, and a new UI test suite validates all scenarios.

Changes

Sender-Aware TalkBack Accessibility

Layer / File(s) Summary
senderAwareContentDescription helper and localized strings
src/main/java/.../ui/util/MessageSenderDescription.kt, src/main/res/values/strings.xml, src/main/res/values-es/strings.xml, src/main/res/values-fr/strings.xml, src/main/res/values-hi/strings.xml, src/main/res/values-in/strings.xml, src/main/res/values-it/strings.xml, src/main/res/values-ja/strings.xml, src/main/res/values-ko/strings.xml
Introduces senderAwareContentDescription selecting among four localized string templates (self/other × message/reply) and an AttachmentState.senderAwareDescription extension that gates sender prefixing behind announceSender; adds the four new string keys in all supported locales.
AttachmentState public API extension
src/main/java/.../state/messages/attachments/AttachmentState.kt, api/stream-chat-android-compose.api
Extends AttachmentState data class with announceSender: Boolean = false, updating the binary API surface (constructor, copy, component5, getAnnounceSender).
MessageContent sender-announcement routing
src/main/java/.../ui/components/messages/MessageContent.kt
Adds a private SenderAttachment enum, computes the attachment category per message, and sets announceSender on media/file/giphy/audio AttachmentState via .copy(...); applies sender-aware semantics to the deleted-message Text.
MessageText and PollMessageContent sender semantics
src/main/java/.../ui/components/messages/MessageText.kt, src/main/java/.../ui/components/messages/PollMessageContent.kt
MessageText computes senderAwareText and attaches it via semantics { contentDescription } on both ClickableText and Text branches; PollMessageContent applies the same pattern to the poll name Text.
Attachment content composables: semantics wrappers
src/main/java/.../ui/attachments/content/AudioRecordAttachmentContent.kt, .../FileAttachmentContent.kt, .../GiphyAttachmentContent.kt, .../MediaAttachmentContent.kt
Each composable gains a non-clickable outer Box with Modifier.semantics { contentDescription; isTraversalGroup = true } driven by senderAwareDescription; click/interaction handlers are relocated to inner containers for Giphy.
MessageContainerSenderAttributionTest UI test suite
src/test/kotlin/.../ui/messages/list/MessageContainerSenderAttributionTest.kt
New Compose UI test class covering outgoing, incoming, single/multiple image, file, giphy, text+attachment combined, reply, and deleted message TalkBack content description assertions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GetStream/stream-chat-android#6440: Modifies the same attachment content composables (FileAttachmentContent, MediaAttachmentContent) with overlapping TalkBack label changes including onClickLabel, heading semantics, and pluralization patterns.
  • GetStream/stream-chat-android#6483: Modifies GiphyAttachmentContent accessibility behavior including StreamAsyncImage contentDescription semantics, directly overlapping with this PR's Giphy wrapper refactor.
  • GetStream/stream-chat-android#6498: Updates TalkBack semantics in MediaAttachmentContent and related Giphy preview composables, overlapping with the sender-aware description wrappers added here.

Suggested labels

released

Suggested reviewers

  • VelikovPetar

Poem

🐰 Hop hop, the screen reader speaks!
"You said hello" — no more hide-and-seek.
A sender named, a reply proclaimed,
Each Box and semantics carefully framed.
TalkBack rejoices, every voice reclaimed! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: announcing message senders to screen readers for accessibility.
Description check ✅ Passed The description covers all key template sections: Goal, Implementation, and Testing. It provides clear context, implementation details, and manual testing instructions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/and-1239-message-sender-a11y

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt (1)

111-119: ⚡ Quick win

Move modifier from the inner Column to the outer Box.

Lines 111-119 currently apply the public modifier to a nested node; applying it at the wrapper level avoids inconsistent padding/background/semantics behavior.

Suggested refactor
-    Box(
-        modifier = Modifier.semantics {
+    Box(
+        modifier = modifier.semantics {
             contentDescription = rowDescription
             isTraversalGroup = true
         },
     ) {
         Column(
-            modifier = modifier
+            modifier = Modifier
                 .combinedClickable(

Based on learnings: "In Compose UI components within the stream-chat-android-compose module, always apply modifiers to the outermost composable in the hierarchy."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt`
around lines 111 - 119, The modifier parameter is currently applied to the
nested Column composable instead of the outer Box wrapper. Move the modifier =
modifier assignment from the Column (which is inside the Box with semantics) to
the Box itself, and remove it from the Column. This ensures the modifier is
applied at the outermost composable level in the hierarchy, which provides
consistent behavior for padding, background, and semantics properties.

Source: Learnings

stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/AudioRecordAttachmentContent.kt (1)

112-120: ⚡ Quick win

Apply the incoming modifier to the outermost wrapper.

Lines 112-120 place modifier on the inner Column; moving it to the outer Box keeps behavior consistent with module conventions for Compose containers.

Suggested refactor
-    Box(
-        modifier = Modifier.semantics {
+    Box(
+        modifier = modifier.semantics {
             contentDescription = rowDescription
             isTraversalGroup = true
         },
     ) {
         Column(
-            modifier = modifier.applyIf(!shouldBeFullSize) { padding(MessageStyling.messageSectionPadding) },
+            modifier = Modifier.applyIf(!shouldBeFullSize) { padding(MessageStyling.messageSectionPadding) },
             verticalArrangement = Arrangement.spacedBy(MessageStyling.sectionsDistance),
         ) {

Based on learnings: "In Compose UI components within the stream-chat-android-compose module, always apply modifiers to the outermost composable in the hierarchy."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/AudioRecordAttachmentContent.kt`
around lines 112 - 120, The modifier parameter is currently being applied to the
inner Column composable instead of the outermost Box wrapper. Move the modifier
application from the Column (which currently has the applyIf logic with
MessageStyling.messageSectionPadding) to the outer Box composable to align with
module conventions. The Column should be updated to remove the modifier
parameter entirely, while the Box should receive the same modifier with the
conditional padding logic preserved.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt`:
- Line 121: The `@Suppress`("LongMethod") annotation on line 121 lacks
documentation and violates the coding guideline that suppressions must be
explicitly documented. Either remove this suppression and refactor the method
into smaller helper functions to reduce its length, or keep the suppression but
add a documented comment explaining the rationale for why this specific method
needs to be long and cannot be reasonably broken down, potentially with tracking
context or issue references.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageContent.kt`:
- Around line 148-153: The senderAwareContentDescription function call when
building deletedDescription is missing the isReply parameter, which causes
deleted replies to announce incorrectly as "said" instead of "replied". Locate
where deletedDescription is assigned using senderAwareContentDescription and add
the isReply state as a parameter to this function call, ensuring it matches how
isReply is passed to other senderAwareContentDescription calls for non-deleted
messages in the same composable.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/PollMessageContent.kt`:
- Around line 221-226: The senderAwareContentDescription function call in the
poll message announcement block is missing the isReply parameter, which causes
reply context to be lost in accessibility announcements. Add the isReply
parameter to the senderAwareContentDescription function call alongside the
existing isMine, senderName, and content parameters to ensure that poll replies
are properly announced as "replied" rather than just "said" for screen reader
users.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/list/MessageContainerSenderAttributionTest.kt`:
- Around line 71-72: The test assertions use hardcoded English accessibility
strings like "You said, Hello" in onNodeWithContentDescription calls, which
makes the tests fragile to locale changes and copy updates. Replace all
instances of hardcoded accessibility strings (at lines 71-72, 88-89, 99-100,
113-114, 126-127, 139-140, and 219-220) with dynamically loaded strings from
stringResource IDs. This will require fetching the actual string resources used
in the composable being tested and using those values in the assertions instead
of hardcoding them, ensuring the tests remain stable as translations and copy
text evolve.

---

Nitpick comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/AudioRecordAttachmentContent.kt`:
- Around line 112-120: The modifier parameter is currently being applied to the
inner Column composable instead of the outermost Box wrapper. Move the modifier
application from the Column (which currently has the applyIf logic with
MessageStyling.messageSectionPadding) to the outer Box composable to align with
module conventions. The Column should be updated to remove the modifier
parameter entirely, while the Box should receive the same modifier with the
conditional padding logic preserved.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt`:
- Around line 111-119: The modifier parameter is currently applied to the nested
Column composable instead of the outer Box wrapper. Move the modifier = modifier
assignment from the Column (which is inside the Box with semantics) to the Box
itself, and remove it from the Column. This ensures the modifier is applied at
the outermost composable level in the hierarchy, which provides consistent
behavior for padding, background, and semantics properties.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0e6f3660-f564-4687-824c-593c0a0fb934

📥 Commits

Reviewing files that changed from the base of the PR and between 73f5f7e and eeca0cd.

📒 Files selected for processing (19)
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/state/messages/attachments/AttachmentState.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/AudioRecordAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/FileAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/GiphyAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageText.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/PollMessageContent.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/MessageSenderDescription.kt
  • stream-chat-android-compose/src/main/res/values-es/strings.xml
  • stream-chat-android-compose/src/main/res/values-fr/strings.xml
  • stream-chat-android-compose/src/main/res/values-hi/strings.xml
  • stream-chat-android-compose/src/main/res/values-in/strings.xml
  • stream-chat-android-compose/src/main/res/values-it/strings.xml
  • stream-chat-android-compose/src/main/res/values-ja/strings.xml
  • stream-chat-android-compose/src/main/res/values-ko/strings.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/list/MessageContainerSenderAttributionTest.kt

* By default it is used to display a play button over video previews.
*/
@OptIn(ExperimentalFoundationApi::class)
@Suppress("LongMethod")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document or remove the new LongMethod suppression.

Line 121 introduces @Suppress("LongMethod") without rationale. Please either extract helper blocks and drop the suppression, or add a short documented reason (ideally with tracking context).

As per coding guidelines: "**/*.kt: Use @OptIn annotations explicitly in Kotlin code; avoid suppressions unless documented."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/content/MediaAttachmentContent.kt`
at line 121, The `@Suppress`("LongMethod") annotation on line 121 lacks
documentation and violates the coding guideline that suppressions must be
explicitly documented. Either remove this suppression and refactor the method
into smaller helper functions to reduce its length, or keep the suppression but
add a documented comment explaining the rationale for why this specific method
needs to be long and cannot be reasonably broken down, potentially with tracking
context or issue references.

Source: Coding guidelines

Comment on lines +148 to 153
val isMine = currentUser?.id == message.user.id
val contentColor = MessageStyling.textColor(outgoing = isMine)
val deletedText = stringResource(id = R.string.stream_compose_message_deleted)
// Attribute the sender on deleted messages too, so every message announces who sent it (DS-035).
val deletedDescription = senderAwareContentDescription(isMine, message.user.name, deletedText)
Row(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass reply state into deleted-message sender description.

Line 152 builds deletedDescription without isReply, so deleted replies are announced as “said” instead of “replied”.

Suggested fix
-    val deletedDescription = senderAwareContentDescription(isMine, message.user.name, deletedText)
+    val deletedDescription = senderAwareContentDescription(
+        isMine = isMine,
+        senderName = message.user.name,
+        content = deletedText,
+        isReply = message.replyTo != null,
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val isMine = currentUser?.id == message.user.id
val contentColor = MessageStyling.textColor(outgoing = isMine)
val deletedText = stringResource(id = R.string.stream_compose_message_deleted)
// Attribute the sender on deleted messages too, so every message announces who sent it (DS-035).
val deletedDescription = senderAwareContentDescription(isMine, message.user.name, deletedText)
Row(
val isMine = currentUser?.id == message.user.id
val contentColor = MessageStyling.textColor(outgoing = isMine)
val deletedText = stringResource(id = R.string.stream_compose_message_deleted)
// Attribute the sender on deleted messages too, so every message announces who sent it (DS-035).
val deletedDescription = senderAwareContentDescription(
isMine = isMine,
senderName = message.user.name,
content = deletedText,
isReply = message.replyTo != null,
)
Row(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/MessageContent.kt`
around lines 148 - 153, The senderAwareContentDescription function call when
building deletedDescription is missing the isReply parameter, which causes
deleted replies to announce incorrectly as "said" instead of "replied". Locate
where deletedDescription is assigned using senderAwareContentDescription and add
the isReply state as a parameter to this function call, ensuring it matches how
isReply is passed to other senderAwareContentDescription calls for non-deleted
messages in the same composable.

Comment on lines +221 to +226
// Announce the sender on the poll name so screen readers attribute every message (DS-035).
val senderAwareName = senderAwareContentDescription(
isMine = isMine,
senderName = message.user.name,
content = poll.name,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include reply context in poll sender announcement.

Lines 222-226 don’t pass isReply, so poll replies are announced with “said” instead of “replied”.

Suggested fix
     val senderAwareName = senderAwareContentDescription(
         isMine = isMine,
         senderName = message.user.name,
         content = poll.name,
+        isReply = message.replyTo != null,
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Announce the sender on the poll name so screen readers attribute every message (DS-035).
val senderAwareName = senderAwareContentDescription(
isMine = isMine,
senderName = message.user.name,
content = poll.name,
)
// Announce the sender on the poll name so screen readers attribute every message (DS-035).
val senderAwareName = senderAwareContentDescription(
isMine = isMine,
senderName = message.user.name,
content = poll.name,
isReply = message.replyTo != null,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/PollMessageContent.kt`
around lines 221 - 226, The senderAwareContentDescription function call in the
poll message announcement block is missing the isReply parameter, which causes
reply context to be lost in accessibility announcements. Add the isReply
parameter to the senderAwareContentDescription function call alongside the
existing isMine, senderName, and content parameters to ensure that poll replies
are properly announced as "replied" rather than just "said" for screen reader
users.

Comment on lines +71 to +72
.onNodeWithContentDescription("You said, Hello")
.assertExists()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid hardcoded English accessibility strings in assertions.

These checks are locale- and wording-fragile. Build expected labels from stringResource IDs (or set test locale explicitly) so this suite stays stable as translations/copy evolve.

Proposed test hardening
+import androidx.test.core.app.ApplicationProvider
+import android.content.Context
+import io.getstream.chat.android.compose.R
...
 internal class MessageContainerSenderAttributionTest : MockedChatClientTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
...
-        composeTestRule
-            .onNodeWithContentDescription("You said, Hello")
-            .assertExists()
+        val expected = context.getString(R.string.stream_compose_message_sender_self, "Hello")
+        composeTestRule.onNodeWithContentDescription(expected).assertExists()

Also applies to: 88-89, 99-100, 113-114, 126-127, 139-140, 219-220

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/list/MessageContainerSenderAttributionTest.kt`
around lines 71 - 72, The test assertions use hardcoded English accessibility
strings like "You said, Hello" in onNodeWithContentDescription calls, which
makes the tests fragile to locale changes and copy updates. Replace all
instances of hardcoded accessibility strings (at lines 71-72, 88-89, 99-100,
113-114, 126-127, 139-140, and 219-220) with dynamically loaded strings from
stringResource IDs. This will require fetching the actual string resources used
in the composable being tested and using those values in the assertions instead
of hardcoding them, ensuring the tests remain stable as translations and copy
text evolve.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.90 MB 5.90 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.14 MB 11.14 MB 0.00 MB 🟢
stream-chat-android-compose 12.58 MB 12.59 MB 0.01 MB 🟢

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant