Skip to content

Make the channel preview deterministic when the last message is deleted - #6577

Merged
andremion merged 3 commits into
developfrom
andrerego/and-1314-deleted-last-message-can-reappear-as-the-channel-preview
Jul 20, 2026
Merged

Make the channel preview deterministic when the last message is deleted#6577
andremion merged 3 commits into
developfrom
andrerego/and-1314-deleted-last-message-can-reappear-as-the-channel-preview

Conversation

@andremion

@andremion andremion commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Goal

The e2e test that covers the channel preview after deleting the last message fails intermittently (3 of the last 200 nightly runs). The investigation showed two problems. First, the preview selection in getLastMessageIncludingDeleted picks the first of the messages that tie on createdAt, so with second-precision timestamps (the mock server) the shown preview depends on whether two messages land in the same second. Second, the test still expects the previous message, an expectation that predates the channel list redesign. Since the redesign, the preview intentionally shows the "Message deleted" placeholder when the newest message is soft-deleted, and current iOS behaves the same (its e2e suite asserts this exact scenario).

Resolves AND-1314

Implementation

  • getLastMessageIncludingDeleted now prefers the later list element when creation times are equal, so the selection is deterministic. Against the real backend, timestamps carry sub-second precision and ties do not occur, so production behavior does not change.
  • The e2e test is renamed to test_channelPreviewShowsMessageDeleted_whenLastMessageIsDeleted and expects the placeholder, mirroring the sibling only-message test and the iOS suite.
  • PreviewMessageData fixture dates are now strictly increasing instead of init-time Date(), so Paparazzi goldens no longer depend on initialization timing. The updated goldens now show message2 as the newest message, which matches the fixture order.
  • New coverage: two ChannelItem snapshots (deleted last message with an older message present, and only message deleted) and three ChannelUtilsTest unit tests, including the tie case.

🎨 UI Changes

No UI changes. The selection change only affects messages with identical creation times, which does not happen against the real backend.

Testing

  1. Run the two channel preview e2e tests: open a channel, let the second user send two messages and delete the last one, go back to the channel list. The preview shows "Message deleted" with the timestamp, both when an older message exists and when the deleted message was the only one.
  2. ./gradlew :stream-chat-android-compose:testDebugUnitTest --tests "*.ChannelUtilsTest" passes.
  3. ./gradlew :stream-chat-android-compose:verifyPaparazziDebug passes.

Local verification: both e2e tests ran 10 times each against the mock server after the fix, 20 of 20 passed. Before the fix, the failure reproduced whenever the two messages crossed a second boundary (verified in 6 of 6 instrumented runs and in all 3 nightly failures).

Summary by CodeRabbit

  • Bug Fixes

    • Channel previews now display “Message deleted” when the latest message has been deleted.
    • Corrected latest-message selection when messages share the same timestamp.
  • Tests

    • Added coverage for deleted-message channel states and timestamp tie-breaking.
    • Added visual previews for channels with deleted latest or only messages.

… preview

The preview selection returned the first of the messages tied on createdAt,
so backends with second-precision timestamps made the deleted-message preview
depend on send timing. Prefer the later list element, which is the newer
message. Also make the preview fixture dates strictly increasing so the
Paparazzi goldens stop depending on initialization timing.
The test expected the previous message, which predates the channel list
redesign and current iOS behavior. It only passed when the mock server's
second-precision timestamps made the two messages tie.
@github-actions

github-actions Bot commented Jul 20, 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.

@andremion andremion added the pr:bug Bug fix label Jul 20, 2026
@andremion

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 20, 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 Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a030a4a1-32a3-4595-b77f-6ce75bf35a21

📥 Commits

Reviewing files that changed from the base of the PR and between f4e7c55 and 006775d.

⛔ Files ignored due to path filters (14)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_deleted_last_message.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_last_message_delivered_status.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_last_message_pending_status.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_last_message_seen_status.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_last_message_sent_status.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_muted_and_pinned_channel.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_muted_and_pinned_channel_mixed_positions.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_muted_and_pinned_channel_trailing_bottom.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_muted_channel.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_muted_channel_trailing_bottom.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_only_deleted_message.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_pinned_channel.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_pinned_channel_trailing_bottom.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_ChannelItemTest_unread_messages.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/ChannelListTests.kt
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/list/ChannelItem.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/ChannelUtils.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/ChannelItemTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/ChannelUtilsTest.kt
  • stream-chat-android-previewdata/src/main/kotlin/io/getstream/chat/android/previewdata/PreviewMessageData.kt

Walkthrough

Channel preview message selection now handles deleted messages and equal timestamps deterministically. Compose previews and snapshots cover deleted-message states, while the end-to-end test expects the “Message deleted” placeholder.

Changes

Deleted message preview behavior

Layer / File(s) Summary
Deterministic last-message selection
stream-chat-android-compose/src/main/java/.../ChannelUtils.kt, stream-chat-android-compose/src/test/.../ChannelUtilsTest.kt
getLastMessageIncludingDeleted now prefers the later list element when creation timestamps match, with coverage for deleted and tied messages.
Deleted-message preview states
stream-chat-android-previewdata/src/main/.../PreviewMessageData.kt, stream-chat-android-compose/src/main/.../ChannelItem.kt, stream-chat-android-compose/src/test/.../ChannelItemTest.kt, stream-chat-android-compose/api/...
Preview timestamps are deterministic, and channel-item previews and snapshots cover deleted-last-message and only-deleted-message states.
End-to-end assertion
stream-chat-android-compose-sample/src/androidTestE2eDebug/.../ChannelListTests.kt
The deletion test now expects the “Message deleted” channel-preview placeholder.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: pr:improvement, pr:test

Suggested reviewers: velikovpetar, gpunto

Poem

A bunny saw messages fade,
And found the placeholder displayed.
Timestamps now hop in line,
Snapshots capture states just fine.
“Message deleted!” carrots cheer—
The channel preview is clear! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: deterministic channel preview behavior when the last message is deleted.
Description check ✅ Passed The description includes the required Goal, Implementation, UI Changes, and Testing sections and is sufficiently detailed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 andrerego/and-1314-deleted-last-message-can-reappear-as-the-channel-preview

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.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.95 MB 5.95 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.21 MB 11.21 MB 0.00 MB 🟢
stream-chat-android-compose 12.69 MB 12.69 MB 0.00 MB 🟢

…w fixtures

The preview fixture dates are now strictly increasing, so the channel list
preview renders message2 as the newest message instead of depending on
initialization timing.
@sonarqubecloud

Copy link
Copy Markdown

@andremion
andremion marked this pull request as ready for review July 20, 2026 10:34
@andremion
andremion requested a review from a team as a code owner July 20, 2026 10:34
@andremion
andremion enabled auto-merge (squash) July 20, 2026 10:42
@andremion
andremion merged commit 0dadef8 into develop Jul 20, 2026
19 checks passed
@andremion
andremion deleted the andrerego/and-1314-deleted-last-message-can-reappear-as-the-channel-preview branch July 20, 2026 11:20
@stream-public-bot stream-public-bot added the released Included in a release label Jul 30, 2026
@stream-public-bot

Copy link
Copy Markdown
Contributor

🚀 Available in v7.7.0

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

Labels

pr:bug Bug fix released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants