mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Various UI test fixes (#370)
* Increase integration tests time limits again as they're still ocasionally failing * Fixed NavigationRootCoordinator name in logs * Refactor UI tests hierarchy and introduce new userFlowScreen * Introduce a RoomTimelineControllerFactory so that it can be mocked in the UserFlow UI tests * Start using a mock timeline controller for the UserSession flows * Remove the WeakDictionary dependency and replce it with a plain NSMapTable in the BackgroundTaskService * Allow multiple UITests screenshots per screen * Prevent the view hierarchy changing when taking screenshots * Add UserSessionScreen UI tests * Fix label triaging workflow project identifier as per vector-im/element-ios/pull/7150 * Fix settings screen tests * Fix roomPlainNoAvatar and roomEncryptedWithAvatar UI tests * Fix modal server selection screen UI tests * Fix bug report and login screen UI tests * Fix text typing missing characters on UI tests * Fix sliding sync configuration on integration tests * Stop crashing if not finding a particular room through the MockClientProxy
This commit is contained in:
@@ -20,7 +20,7 @@ import UIKit
|
||||
/// /// UIKitBackgroundTaskService is a concrete implementation of BackgroundTaskServiceProtocol using a given `ApplicationProtocol` instance.
|
||||
class UIKitBackgroundTaskService: BackgroundTaskServiceProtocol {
|
||||
private let applicationBlock: () -> ApplicationProtocol?
|
||||
private var reusableTasks: WeakDictionary<String, UIKitBackgroundTask> = WeakDictionary()
|
||||
private var reusableTasks = NSMapTable<NSString, UIKitBackgroundTask>(keyOptions: .strongMemory, valueOptions: .weakMemory)
|
||||
|
||||
private var application: ApplicationProtocol? {
|
||||
applicationBlock()
|
||||
@@ -50,7 +50,7 @@ class UIKitBackgroundTaskService: BackgroundTaskServiceProtocol {
|
||||
var result: BackgroundTaskProtocol?
|
||||
|
||||
if isReusable {
|
||||
if let oldTask = reusableTasks[name], oldTask.isRunning {
|
||||
if let oldTask = reusableTasks.object(forKey: name as NSString), oldTask.isRunning {
|
||||
oldTask.reuse()
|
||||
result = oldTask
|
||||
} else {
|
||||
@@ -59,11 +59,11 @@ class UIKitBackgroundTaskService: BackgroundTaskServiceProtocol {
|
||||
application: application,
|
||||
expirationHandler: { [weak self] task in
|
||||
guard let self else { return }
|
||||
self.reusableTasks[task.name] = nil
|
||||
self.reusableTasks.removeObject(forKey: task.name as NSString)
|
||||
expirationHandler?()
|
||||
}) {
|
||||
created = true
|
||||
reusableTasks[name] = newTask
|
||||
reusableTasks.setObject(newTask, forKey: name as NSString)
|
||||
result = newTask
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,12 @@ class MockClientProxy: ClientProxyProtocol {
|
||||
func restartSync() { }
|
||||
|
||||
func roomForIdentifier(_ identifier: String) async -> RoomProxyProtocol? {
|
||||
nil
|
||||
guard let room = roomSummaryProvider?.roomListPublisher.value.first(where: { $0.id == identifier }),
|
||||
let displayName = room.asFilled?.name else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return MockRoomProxy(displayName: displayName)
|
||||
}
|
||||
|
||||
func loadUserDisplayName() async -> Result<String, ClientProxyError> {
|
||||
|
||||
@@ -55,7 +55,7 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
isDirect: true,
|
||||
avatarURLString: nil,
|
||||
lastMessage: AttributedString("Prosciutto beef ribs pancetta filet mignon kevin hamburger, chuck ham venison picanha. Beef ribs chislic turkey biltong tenderloin."),
|
||||
lastMessageTimestamp: .now,
|
||||
lastMessageTimestamp: .distantPast,
|
||||
unreadNotificationCount: 4)),
|
||||
.filled(details: RoomSummaryDetails(id: "2",
|
||||
name: "Second room",
|
||||
@@ -69,7 +69,7 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
isDirect: true,
|
||||
avatarURLString: nil,
|
||||
lastMessage: try? AttributedString(markdown: "**@mock:client.com**: T-bone beef ribs bacon"),
|
||||
lastMessageTimestamp: .now,
|
||||
lastMessageTimestamp: .distantPast,
|
||||
unreadNotificationCount: 0)),
|
||||
.empty(id: "3")
|
||||
]
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2022 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 Foundation
|
||||
|
||||
struct MockRoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
|
||||
func buildRoomTimelineController(userId: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol) -> RoomTimelineControllerProtocol {
|
||||
let timelineController = MockRoomTimelineController()
|
||||
timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk
|
||||
return timelineController
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -32,19 +32,20 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
let roomId: String
|
||||
let callbacks = PassthroughSubject<RoomTimelineControllerCallback, Never>()
|
||||
|
||||
private(set) var timelineItems = [RoomTimelineItemProtocol]()
|
||||
|
||||
var roomId: String {
|
||||
roomProxy.id
|
||||
}
|
||||
|
||||
init(userId: String,
|
||||
roomId: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
timelineProvider: RoomTimelineProviderProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
roomProxy: RoomProxyProtocol) {
|
||||
mediaProvider: MediaProviderProtocol) {
|
||||
self.userId = userId
|
||||
self.roomId = roomId
|
||||
self.timelineProvider = timelineProvider
|
||||
self.timelineItemFactory = timelineItemFactory
|
||||
self.mediaProvider = mediaProvider
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2022 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 Foundation
|
||||
|
||||
struct RoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol {
|
||||
func buildRoomTimelineController(userId: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol) -> RoomTimelineControllerProtocol {
|
||||
RoomTimelineController(userId: userId,
|
||||
roomProxy: roomProxy,
|
||||
timelineProvider: RoomTimelineProvider(roomProxy: roomProxy),
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: mediaProvider)
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2022 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 Foundation
|
||||
|
||||
@MainActor
|
||||
protocol RoomTimelineControllerFactoryProtocol {
|
||||
func buildRoomTimelineController(userId: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
timelineItemFactory: RoomTimelineItemFactoryProtocol,
|
||||
mediaProvider: MediaProviderProtocol) -> RoomTimelineControllerProtocol
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let navigationSplitCoordinator: NavigationSplitCoordinator
|
||||
private let bugReportService: BugReportServiceProtocol
|
||||
private let roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol
|
||||
private let emojiProvider: EmojiProviderProtocol = EmojiProvider()
|
||||
|
||||
private let sidebarNavigationStackCoordinator: NavigationStackCoordinator
|
||||
@@ -33,11 +34,15 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
|
||||
var callback: ((UserSessionFlowCoordinatorAction) -> Void)?
|
||||
|
||||
init(userSession: UserSessionProtocol, navigationSplitCoordinator: NavigationSplitCoordinator, bugReportService: BugReportServiceProtocol) {
|
||||
init(userSession: UserSessionProtocol,
|
||||
navigationSplitCoordinator: NavigationSplitCoordinator,
|
||||
bugReportService: BugReportServiceProtocol,
|
||||
roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol) {
|
||||
stateMachine = UserSessionFlowCoordinatorStateMachine()
|
||||
self.userSession = userSession
|
||||
self.navigationSplitCoordinator = navigationSplitCoordinator
|
||||
self.bugReportService = bugReportService
|
||||
self.roomTimelineControllerFactory = roomTimelineControllerFactory
|
||||
|
||||
sidebarNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
|
||||
detailNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
|
||||
@@ -150,13 +155,11 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
roomProxy: roomProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder())
|
||||
|
||||
let timelineController = RoomTimelineController(userId: userId,
|
||||
roomId: roomIdentifier,
|
||||
timelineProvider: RoomTimelineProvider(roomProxy: roomProxy),
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
roomProxy: roomProxy)
|
||||
|
||||
let timelineController = roomTimelineControllerFactory.buildRoomTimelineController(userId: userId,
|
||||
roomProxy: roomProxy,
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let parameters = RoomScreenCoordinatorParameters(navigationStackCoordinator: detailNavigationStackCoordinator,
|
||||
timelineController: timelineController,
|
||||
|
||||
Reference in New Issue
Block a user