diff --git a/UnitTests/Sources/SearchScreenViewModelTests.swift b/UnitTests/Sources/SearchScreenViewModelTests.swift index a2e5c7a82..80a90eba8 100644 --- a/UnitTests/Sources/SearchScreenViewModelTests.swift +++ b/UnitTests/Sources/SearchScreenViewModelTests.swift @@ -12,15 +12,30 @@ import Testing @MainActor struct SearchScreenViewModelTests { let viewModel: SearchScreenViewModelProtocol + let searchService: SearchServiceProxyMock + let userIndicatorController: UserIndicatorControllerMock + /// Fires with the query each time the (async, debounced) message search runs. + let setQuerySubject = PassthroughSubject() + /// Fires each time an indicator is submitted. + let submitIndicatorSubject = PassthroughSubject() + var context: SearchScreenViewModelType.Context { viewModel.context } init() { - let searchService = SearchServiceProxyMock() + searchService = SearchServiceProxyMock() searchService.underlyingResultsPublisher = CurrentValueSubject<[SearchServiceResult], Never>([]).asCurrentValuePublisher() searchService.underlyingPaginationStatePublisher = CurrentValueSubject(.idle(endReached: true)).asCurrentValuePublisher() - searchService.setQueryReturnValue = .success(()) + searchService.setQueryClosure = { [setQuerySubject] query in + setQuerySubject.send(query) + return .success(()) + } + + userIndicatorController = UserIndicatorControllerMock() + userIndicatorController.submitIndicatorDelayClosure = { [submitIndicatorSubject] _, _ in + submitIndicatorSubject.send(()) + } let clientProxy = ClientProxyMock(.init()) clientProxy.searchService = searchService @@ -28,7 +43,7 @@ struct SearchScreenViewModelTests { viewModel = SearchScreenViewModel(roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms))), clientProxy: clientProxy, mediaProvider: MediaProviderMock(.init()), - userIndicatorController: UserIndicatorControllerMock()) + userIndicatorController: userIndicatorController) } @Test @@ -36,6 +51,31 @@ struct SearchScreenViewModelTests { let deferred = deferFulfillment(context.observe(\.viewState.rooms)) { $0.count == 1 } context.searchQuery = "Second" try await deferred.fulfill() + + // The rooms tab must not trigger the slow message search. + #expect(!searchService.setQueryCalled) + } + + @Test + func messageSearch() async throws { + let deferred = deferFulfillment(setQuerySubject) { $0 == "Foundation" } + context.searchMode = .messages + context.searchQuery = "Foundation" + try await deferred.fulfill() + + #expect(searchService.setQueryReceivedQuery == "Foundation") + } + + @Test + func messageSearchFailureShowsErrorIndicator() async throws { + searchService.setQueryClosure = { _ in .failure(.sdkError(SearchScreenViewModelTestsError.failed)) } + + let deferred = deferFulfillment(submitIndicatorSubject) { _ in true } + context.searchMode = .messages + context.searchQuery = "Foundation" + try await deferred.fulfill() + + #expect(userIndicatorController.submitIndicatorDelayCalled) } @Test @@ -70,3 +110,7 @@ struct SearchScreenViewModelTests { try await deferred.fulfill() } } + +private enum SearchScreenViewModelTestsError: Error { + case failed +}