Introduce mock SDK timeline items and a live, lorem ipsum based, timeline provider

This commit is contained in:
Stefan Ceriu
2024-06-10 11:58:11 +03:00
committed by Stefan Ceriu
parent 3de18fa88d
commit 2079bf40c6
10 changed files with 246 additions and 36 deletions
+17 -11
View File
@@ -39,16 +39,7 @@ struct RoomProxyMockConfiguration {
var canUserTriggerRoomNotification = false
var canUserJoinCall = true
func makeTimeline() -> TimelineProxyMock {
let timeline = TimelineProxyMock()
timeline.sendMessageEventContentReturnValue = .success(())
let timelineProvider = RoomTimelineProviderMock()
timelineProvider.paginationState = .init(backward: timelineStartReached ? .timelineEndReached : .idle, forward: .timelineEndReached)
timelineProvider.underlyingMembershipChangePublisher = PassthroughSubject().eraseToAnyPublisher()
timeline.underlyingTimelineProvider = timelineProvider
return timeline
}
var shouldUseAutoUpdatingTimeline = false
}
enum RoomProxyMockError: Error {
@@ -71,8 +62,23 @@ extension RoomProxyMock {
hasOngoingCall = configuration.hasOngoingCall
canonicalAlias = configuration.canonicalAlias
timeline = configuration.makeTimeline()
let timeline = TimelineProxyMock()
timeline.sendMessageEventContentReturnValue = .success(())
timeline.paginateBackwardsRequestSizeReturnValue = .success(())
timeline.paginateForwardsRequestSizeReturnValue = .success(())
timeline.sendReadReceiptForTypeReturnValue = .success(())
if configuration.shouldUseAutoUpdatingTimeline {
timeline.underlyingTimelineProvider = AutoUpdatingRoomTimelineProviderMock()
} else {
let timelineProvider = RoomTimelineProviderMock()
timelineProvider.paginationState = .init(backward: configuration.timelineStartReached ? .timelineEndReached : .idle, forward: .timelineEndReached)
timelineProvider.underlyingMembershipChangePublisher = PassthroughSubject().eraseToAnyPublisher()
timeline.underlyingTimelineProvider = timelineProvider
}
self.timeline = timeline
ownUserID = configuration.ownUserID
membership = .joined
@@ -17,7 +17,7 @@
import Foundation
struct RoomTimelineControllerFactoryMockConfiguration {
var timelineController: MockRoomTimelineController?
var timelineController: RoomTimelineControllerProtocol?
}
extension RoomTimelineControllerFactoryMock {
@@ -0,0 +1,48 @@
//
// Copyright 2024 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Combine
import Foundation
import MatrixRustSDK
@MainActor
class AutoUpdatingRoomTimelineProviderMock: RoomTimelineProvider {
private let innerUpdatePublisher: PassthroughSubject<[TimelineDiff], Never>
private let innerPaginationStatePublisher: PassthroughSubject<PaginationState, Never>
private let innerItems: [TimelineItemProxy] = []
init() {
innerUpdatePublisher = .init()
innerPaginationStatePublisher = .init()
super.init(currentItems: [],
isLive: true,
updatePublisher: innerUpdatePublisher.eraseToAnyPublisher(),
paginationStatePublisher: innerPaginationStatePublisher.eraseToAnyPublisher())
Task.detached { [weak self] in
for _ in 0...100 {
try? await Task.sleep(for: .seconds(1))
let diff = TimelineDiffSDKMock()
diff.changeReturnValue = .append
diff.appendReturnValue = [TimelineItemFixtures.messageTimelineItem]
self?.innerUpdatePublisher.send([diff])
}
}
}
}
@@ -0,0 +1,75 @@
//
// Copyright 2024 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Combine
import Foundation
import LoremSwiftum
import MatrixRustSDK
enum TimelineItemFixtures {
static var callInviteTimelineItem: TimelineItem {
let eventTimelineItem = EventTimelineItemSDKMock()
eventTimelineItem.isOwnReturnValue = true
eventTimelineItem.timestampReturnValue = 0
eventTimelineItem.isEditableReturnValue = false
eventTimelineItem.canBeRepliedToReturnValue = false
eventTimelineItem.senderReturnValue = "@bob:matrix.org"
eventTimelineItem.senderProfileReturnValue = .pending
let timelineItemContent = TimelineItemContentSDKMock()
timelineItemContent.kindReturnValue = .callInvite
eventTimelineItem.contentReturnValue = timelineItemContent
let timelineItem = TimelineItemSDKMock()
timelineItem.asEventReturnValue = eventTimelineItem
return timelineItem
}
static var messageTimelineItem: TimelineItem {
let eventTimelineItem = EventTimelineItemSDKMock()
eventTimelineItem.eventIdReturnValue = UUID().uuidString
eventTimelineItem.isOwnReturnValue = true
eventTimelineItem.timestampReturnValue = 0
eventTimelineItem.isEditableReturnValue = false
eventTimelineItem.canBeRepliedToReturnValue = false
eventTimelineItem.senderReturnValue = "@bob:matrix.org"
eventTimelineItem.senderProfileReturnValue = .pending
eventTimelineItem.reactionsReturnValue = []
eventTimelineItem.readReceiptsReturnValue = [:]
let timelineItemContent = TimelineItemContentSDKMock()
timelineItemContent.kindReturnValue = .message
let message = MessageSDKMock()
let textMessageContent = TextMessageContent(body: Lorem.sentences(Int.random(in: 1...5)), formatted: nil)
message.msgtypeReturnValue = .text(content: textMessageContent)
message.isThreadedReturnValue = false
message.isEditedReturnValue = false
timelineItemContent.asMessageReturnValue = message
eventTimelineItem.contentReturnValue = timelineItemContent
let timelineItem = TimelineItemSDKMock()
timelineItem.asEventReturnValue = eventTimelineItem
timelineItem.uniqueIdReturnValue = UUID().uuidString
return timelineItem
}
}
@@ -39,6 +39,8 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate
windowManager.delegate = self
MXLog.configure(logLevel: .debug)
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
AppSettings.configureWithSuiteName("io.element.elementx.uitests")
@@ -599,6 +601,46 @@ class MockScreen: Identifiable {
let coordinator = PollFormScreenCoordinator(parameters: .init(mode: .new))
navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator
case .autoUpdatingTimeline:
let appSettings: AppSettings = ServiceLocator.shared.settings
appSettings.hasRunIdentityConfirmationOnboarding = true
appSettings.hasRunNotificationPermissionsOnboarding = true
appSettings.analyticsConsentState = .optedOut
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
let roomProxy = RoomProxyMock(.init(id: "whatever", name: "okay", shouldUseAutoUpdatingTimeline: true))
clientProxy.roomForIdentifierReturnValue = roomProxy
ServiceLocator.shared.settings.migratedAccounts[clientProxy.userID] = true
let timelineController = RoomTimelineController(roomProxy: roomProxy,
initialFocussedEventID: nil,
timelineItemFactory: RoomTimelineItemFactory(userID: "@alice:matrix.org",
attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()),
stateEventStringBuilder: RoomStateEventStringBuilder(userID: "@alice:matrix.org")),
appSettings: ServiceLocator.shared.settings)
let flowCoordinator = UserSessionFlowCoordinator(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
navigationRootCoordinator: navigationRootCoordinator,
appLockService: AppLockService(keychainController: KeychainControllerMock(),
appSettings: ServiceLocator.shared.settings),
bugReportService: BugReportServiceMock(),
elementCallService: ElementCallServiceMock(),
roomTimelineControllerFactory: RoomTimelineControllerFactoryMock(configuration: .init(timelineController: timelineController)),
appMediator: AppMediatorMock.default,
appSettings: appSettings,
analytics: ServiceLocator.shared.analytics,
notificationManager: NotificationManagerMock(),
isNewLogin: false)
flowCoordinator.start()
retainedState.append(flowCoordinator)
return nil
}
}()
}
@@ -52,6 +52,7 @@ enum UITestsScreenIdentifier: String {
case templateScreen
case userSessionScreen
case userSessionScreenReply
case autoUpdatingTimeline
}
extension UITestsScreenIdentifier: CustomStringConvertible {
+1
View File
@@ -188,6 +188,7 @@ targets:
- package: KeychainAccess
- package: Kingfisher
- package: KZFileWatchers
- package: LoremSwiftum
- package: LRUCache
- package: Mapbox
- package: PostHog