Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### 🐞 Fixed
- Fix `Throttler` crash in `ChatChannelViewModel.handleMessageAppear()` [#1050](https://github.com/GetStream/stream-chat-swiftui/pull/1050)
- Remove unnecessary channel query call when leaving the channel view in a mid-page [#1050](https://github.com/GetStream/stream-chat-swiftui/pull/1050)
- Fix crash when force unwrapping `messageDisplayInfo` in `ChatChannelView` [#1052](https://github.com/GetStream/stream-chat-swiftui/pull/1052)

# [4.92.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.92.0)
_November 07, 2025_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public struct ChatChannelView<Factory: ViewFactory>: View, KeyboardReadable {
.opacity(0) // Fixes showing accessibility button shape
}
.overlay(
viewModel.reactionsShown ?
viewModel.currentSnapshot != nil && messageDisplayInfo != nil && viewModel.reactionsShown ?
factory.makeReactionsOverlayView(
channel: channel,
currentSnapshot: viewModel.currentSnapshot!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,76 @@ class ChatChannelView_Tests: StreamChatTestCase {
// Then
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
}

// MARK: - Reactions Overlay Tests

func test_chatChannelView_doesNotCrash_whenCurrentSnapshotIsNil_andReactionsShownIsTrue() {
// Given
let controller = ChatChannelController_Mock.mock(
channelQuery: .init(cid: .unique),
channelListQuery: nil,
client: chatClient
)
let mockChannel = ChatChannel.mock(cid: .unique, name: "Test channel")
let message = ChatMessage.mock(
id: .unique,
cid: mockChannel.cid,
text: "Test message",
author: .mock(id: .unique, name: "User")
)
controller.simulateInitial(channel: mockChannel, messages: [message], state: .remoteDataFetched)

let viewModel = ChatChannelViewModel(channelController: controller)

// When
viewModel.currentSnapshot = nil
viewModel.reactionsShown = true

let view = ChatChannelView(
viewFactory: DefaultViewFactory.shared,
viewModel: viewModel,
channelController: controller
)

// Then - Should not crash when rendering
let hostingController = UIHostingController(rootView: view)
XCTAssertNotNil(hostingController.view)
XCTAssertNil(viewModel.currentSnapshot)
XCTAssertTrue(viewModel.reactionsShown)
}

func test_chatChannelView_doesNotCrash_whenMessageDisplayInfoIsNil_andReactionsShownIsTrue() {
// Given
let controller = ChatChannelController_Mock.mock(
channelQuery: .init(cid: .unique),
channelListQuery: nil,
client: chatClient
)
let mockChannel = ChatChannel.mock(cid: .unique, name: "Test channel")
let message = ChatMessage.mock(
id: .unique,
cid: mockChannel.cid,
text: "Test message",
author: .mock(id: .unique, name: "User")
)
controller.simulateInitial(channel: mockChannel, messages: [message], state: .remoteDataFetched)

let viewModel = ChatChannelViewModel(channelController: controller)

// When
viewModel.showReactionOverlay(for: AnyView(EmptyView()))
// messageDisplayInfo remains nil (not set)

let view = ChatChannelView(
viewFactory: DefaultViewFactory.shared,
viewModel: viewModel,
channelController: controller
)

// Then - Should not crash when rendering
let hostingController = UIHostingController(rootView: view)
XCTAssertNotNil(hostingController.view)
XCTAssertNotNil(viewModel.currentSnapshot)
XCTAssertTrue(viewModel.reactionsShown)
}
}
Loading