mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Move MockTimelineController signalling to a new SignallingTimelineItemProviderMock
This allows for testing more of a flows and using a real TimelineController in a lot of the UI tests
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Copyright 2025 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
// periphery:ignore:all
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
/// A ``TimelineItemProviderMock`` subclass that optionally listens for ``UITestsSignalling`` signals
|
||||
/// to drive pagination and incoming message simulation.
|
||||
@MainActor
|
||||
class SignallingTimelineItemProviderMock: TimelineItemProviderMock {
|
||||
private let stateSubject: CurrentValueSubject<([TimelineItemProxy], TimelinePaginationState), Never>
|
||||
|
||||
/// An array of item arrays that will be prepended in order on each paginate signal.
|
||||
var backPaginationResponses: [[TimelineItemProxy]] = []
|
||||
/// An array of items that will be appended in order on each incoming message signal.
|
||||
var incomingItems: [TimelineItemProxy] = []
|
||||
|
||||
private var client: UITestsSignalling.Client?
|
||||
private var signalCancellable: AnyCancellable?
|
||||
|
||||
init(itemProxies: [TimelineItemProxy] = [],
|
||||
paginationState: TimelinePaginationState = .init(backward: .idle, forward: .endReached),
|
||||
listenForSignals: Bool = false) {
|
||||
stateSubject = CurrentValueSubject((itemProxies, paginationState))
|
||||
|
||||
super.init()
|
||||
|
||||
self.itemProxies = itemProxies
|
||||
|
||||
underlyingPaginationState = paginationState
|
||||
underlyingKind = .live
|
||||
underlyingUpdatePublisher = stateSubject.eraseToAnyPublisher()
|
||||
underlyingMembershipChangePublisher = Empty().eraseToAnyPublisher()
|
||||
|
||||
guard listenForSignals else { return }
|
||||
|
||||
do {
|
||||
let client = try UITestsSignalling.Client(mode: .app)
|
||||
signalCancellable = client.signals.sink { [weak self] signal in
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else { return }
|
||||
do {
|
||||
try self.handleSignal(signal)
|
||||
} catch {
|
||||
MXLog.error(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.client = client
|
||||
} catch {
|
||||
fatalError("Failure setting up signalling: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func handleSignal(_ signal: UITestsSignal) throws {
|
||||
switch signal {
|
||||
case .timeline(.paginate):
|
||||
try simulateBackPagination()
|
||||
case .timeline(.incomingMessage):
|
||||
try simulateIncomingItem()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func simulateIncomingItem() throws {
|
||||
guard !incomingItems.isEmpty else { return }
|
||||
let item = incomingItems.removeFirst()
|
||||
let (items, paginationState) = stateSubject.value
|
||||
let newItems = items + [item]
|
||||
itemProxies = newItems
|
||||
stateSubject.send((newItems, paginationState))
|
||||
try client?.send(.success)
|
||||
}
|
||||
|
||||
func inject(_ proxies: [TimelineItemProxy]) {
|
||||
let (items, paginationState) = stateSubject.value
|
||||
let newItems = items + proxies
|
||||
itemProxies = newItems
|
||||
stateSubject.send((newItems, paginationState))
|
||||
}
|
||||
|
||||
func replaceLastItem(with proxy: TimelineItemProxy) {
|
||||
var (items, paginationState) = stateSubject.value
|
||||
guard !items.isEmpty else { return }
|
||||
items[items.index(before: items.endIndex)] = proxy
|
||||
itemProxies = items
|
||||
stateSubject.send((items, paginationState))
|
||||
}
|
||||
|
||||
private func simulateBackPagination() throws {
|
||||
let (items, _) = stateSubject.value
|
||||
|
||||
guard !backPaginationResponses.isEmpty else {
|
||||
let newState = TimelinePaginationState(backward: .endReached, forward: .endReached)
|
||||
underlyingPaginationState = newState
|
||||
stateSubject.send((items, newState))
|
||||
return
|
||||
}
|
||||
|
||||
let newItems = backPaginationResponses.removeFirst()
|
||||
let newPaginationState = TimelinePaginationState(backward: backPaginationResponses.isEmpty ? .endReached : .idle,
|
||||
forward: .endReached)
|
||||
itemProxies = newItems + items
|
||||
underlyingPaginationState = newPaginationState
|
||||
stateSubject.send((newItems + items, newPaginationState))
|
||||
try client?.send(.success)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user