mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Finish migration of UnitTests target from XCTestCase to Swift Testing (#5129)
* Initial plan * Migrate 3 test files from XCTest to Swift Testing - MediaUploadPreviewScreenViewModelTests: @MainActor @Suite struct with init(), BundleFinder class for Bundle(for:), mutating test/setup functions, [self] capture replacing [weak self] in closures - NotificationManagerTests: @MainActor @Suite final class with init()/deinit, expectation/fulfillment(of:) replaced with confirmation(...), test_ prefix stripped - NotificationSettingsScreenViewModelTests: @MainActor @Suite struct with init() throws, non-optional stored properties, test prefix stripped Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 3 XCTest files to Swift Testing - NotificationSettingsEditScreenViewModelTests: @MainActor @Suite struct with init() throws, mutating test methods - TimelineViewModelTests: @MainActor @Suite final class with init() async throws + deinit - AttributedStringBuilderTests: @Suite struct with init() async throws All XCT assertions replaced with #expect/#require/Issue.record Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 4 test files from XCTest to Swift Testing - TimelineMediaPreviewViewModelTests: @Suite struct, mutating @Test funcs, testLoadingItem renamed to loadingItem (called internally by other tests) - ServerConfirmationScreenViewModelTests: @Suite final class with init()/deinit - CompletionSuggestionServiceTests: @Suite struct with init() - RoomFlowCoordinatorTests: @Suite final class with deinit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 4 test files from XCTest to Swift Testing - VoiceMessageRecorderTests: @Suite struct with init() async throws, added BundleFinder class for Bundle lookup, migrated all assertions - SpaceScreenViewModelTests: @Suite struct, private mutating setupViewModel, all test funcs mutating, XCTestExpectation → confirmation - RoomNotificationSettingsScreenViewModelTests: @Suite struct with init() throws, cancellable tests marked mutating - JoinRoomScreenViewModelTests: @Suite final class with init()/deinit, XCTestExpectation → confirmation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 6 test files from XCTestCase to Swift Testing Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com> * Fix trailing blank line in RoomPollsHistoryScreenViewModelTests Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com> * Migrate 3 test files from XCTest to Swift Testing - MediaUploadingPreprocessorTests: @Suite final class with init()/deinit, removed executionTimeAllowance, XCTAssertEqual(accuracy:) → abs(Double) - SecurityAndPrivacyScreenViewModelTests: @MainActor @Suite final class, 5 expectation+fulfillment → await confirmation(...) - CreateRoomViewModelTests: @MainActor @Suite final class, 4 expectation+fulfillment → await confirmation(...) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate RoomScreenViewModelTests and RoomDetailsScreenViewModelTests to Swift Testing - Replace XCTest with Testing framework - RoomScreenViewModelTests: final class with init() async throws + deinit - RoomDetailsScreenViewModelTests: struct with init() and mutating funcs - Convert XCT assertions to #expect / Issue.record - Convert XCTestExpectation patterns to confirmation { confirm in } - Strip 'test' prefix from all test function names Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate ComposerToolbarViewModelTests from XCTest to Swift Testing - Replace import XCTest with import Testing - Convert XCTestCase class to @MainActor @Suite final class - Replace setUp()/tearDown() with init()/deinit - Strip 'test' prefix from all 41 test method names and add @Test - Replace XCTAssert* with #expect()/#require() - Replace try XCTUnwrap() with try #require() - Convert expectation+wait patterns to deferFulfillment with PassthroughSubject - Convert isInverted expectation to boolean flag checked after await - Use deferFulfillment on $viewState for state-transition tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address comments with Copilot. * Fix the failing tests. * Fixed flaky tests (#5137) resolved flaky tests * Tweaks and fixes. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com> Co-authored-by: Doug <douglase@element.io> Co-authored-by: Mauro <34335419+Velin92@users.noreply.github.com>
This commit is contained in:
@@ -8,10 +8,12 @@
|
||||
|
||||
import Combine
|
||||
@testable import ElementX
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
|
||||
@Suite
|
||||
@MainActor
|
||||
class ChatsTabFlowCoordinatorTests: XCTestCase {
|
||||
struct ChatsTabFlowCoordinatorTests {
|
||||
var clientProxy: ClientProxyMock!
|
||||
var timelineControllerFactory: TimelineControllerFactoryMock!
|
||||
var chatsTabFlowCoordinator: ChatsTabFlowCoordinator!
|
||||
@@ -22,15 +24,14 @@ class ChatsTabFlowCoordinatorTests: XCTestCase {
|
||||
var cancellables = Set<AnyCancellable>()
|
||||
|
||||
var detailCoordinator: CoordinatorProtocol? {
|
||||
splitCoordinator?.detailCoordinator
|
||||
splitCoordinator.detailCoordinator
|
||||
}
|
||||
|
||||
var detailNavigationStack: NavigationStackCoordinator? {
|
||||
detailCoordinator as? NavigationStackCoordinator
|
||||
}
|
||||
|
||||
override func setUp() async throws {
|
||||
cancellables.removeAll()
|
||||
init() async throws {
|
||||
clientProxy = ClientProxyMock(.init(userID: "hi@bob", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
|
||||
timelineControllerFactory = TimelineControllerFactoryMock(.init())
|
||||
|
||||
@@ -60,224 +61,234 @@ class ChatsTabFlowCoordinatorTests: XCTestCase {
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
func testRoomPresentation() async throws {
|
||||
@Test
|
||||
mutating func roomPresentation() async throws {
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomList, expectedState: .roomList(detailState: nil))
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
XCTAssertNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
#expect(detailCoordinator == nil)
|
||||
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomList, expectedState: .roomList(detailState: nil))
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
XCTAssertNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
#expect(detailCoordinator == nil)
|
||||
|
||||
XCTAssertEqual(notificationManager.removeDeliveredMessageNotificationsForReceivedInvocations, ["1", "1", "2"])
|
||||
#expect(notificationManager.removeDeliveredMessageNotificationsForReceivedInvocations == ["1", "1", "2"])
|
||||
}
|
||||
|
||||
func testRoomAliasPresentation() async throws {
|
||||
@Test
|
||||
mutating func roomAliasPresentation() async throws {
|
||||
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "1", servers: []))
|
||||
|
||||
try await process(route: .roomAlias("#alias:matrix.org"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomList, expectedState: .roomList(detailState: nil))
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
XCTAssertNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
#expect(detailCoordinator == nil)
|
||||
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "2", servers: []))
|
||||
|
||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomList, expectedState: .roomList(detailState: nil))
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
XCTAssertNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
#expect(detailCoordinator == nil)
|
||||
|
||||
XCTAssertEqual(notificationManager.removeDeliveredMessageNotificationsForReceivedInvocations, ["1", "1", "2"])
|
||||
#expect(notificationManager.removeDeliveredMessageNotificationsForReceivedInvocations == ["1", "1", "2"])
|
||||
}
|
||||
|
||||
func testRoomDetailsPresentation() async throws {
|
||||
@Test
|
||||
mutating func roomDetailsPresentation() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomList, expectedState: .roomList(detailState: nil))
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
XCTAssertNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
#expect(detailCoordinator == nil)
|
||||
}
|
||||
|
||||
func testStackUnwinding() async throws {
|
||||
@Test
|
||||
mutating func stackUnwinding() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .room(roomID: "2", via: []), expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testNoOp() async throws {
|
||||
@Test
|
||||
mutating func noOp() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
let unexpectedFulfillment = deferFailure(stateMachineFactory.chatsTabFlowStatePublisher, timeout: 1) { _ in true }
|
||||
let unexpectedFulfillment = deferFailure(stateMachineFactory.chatsTabFlowStatePublisher, timeout: .seconds(1)) { _ in true }
|
||||
chatsTabFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true)
|
||||
try await unexpectedFulfillment.fulfill()
|
||||
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testSwitchToDifferentDetails() async throws {
|
||||
@Test
|
||||
mutating func switchToDifferentDetails() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .roomDetails(roomID: "2"), expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testPushDetails() async throws {
|
||||
@Test
|
||||
mutating func pushDetails() async throws {
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
let unexpectedFulfillment = deferFailure(stateMachineFactory.chatsTabFlowStatePublisher, timeout: 1) { _ in true }
|
||||
let unexpectedFulfillment = deferFailure(stateMachineFactory.chatsTabFlowStatePublisher, timeout: .seconds(1)) { _ in true }
|
||||
chatsTabFlowCoordinator.handleAppRoute(.roomDetails(roomID: "1"), animated: true)
|
||||
try await unexpectedFulfillment.fulfill()
|
||||
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1)
|
||||
XCTAssertTrue(detailNavigationStack?.stackCoordinators.first is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 1)
|
||||
#expect(detailNavigationStack?.stackCoordinators.first is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testReplaceDetailsWithTimeline() async throws {
|
||||
@Test
|
||||
mutating func replaceDetailsWithTimeline() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testUserProfileClearsStack() async throws {
|
||||
@Test
|
||||
mutating func userProfileClearsStack() async throws {
|
||||
try await process(route: .roomDetails(roomID: "1"), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
XCTAssertNil(splitCoordinator?.sheetCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomDetailsScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
#expect(splitCoordinator.sheetCoordinator == nil)
|
||||
|
||||
try await process(route: .userProfile(userID: "alice"), expectedState: .userProfileScreen)
|
||||
XCTAssertNil(detailNavigationStack?.rootCoordinator)
|
||||
guard let sheetStackCoordinator = splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator else {
|
||||
XCTFail("There should be a navigation stack presented as a sheet.")
|
||||
return
|
||||
}
|
||||
XCTAssertTrue(sheetStackCoordinator.rootCoordinator is UserProfileScreenCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator == nil)
|
||||
let sheetStackCoordinator = try #require(splitCoordinator.sheetCoordinator as? NavigationStackCoordinator, "There should be a navigation stack presented as a sheet.")
|
||||
#expect(sheetStackCoordinator.rootCoordinator is UserProfileScreenCoordinator)
|
||||
}
|
||||
|
||||
func testRoomClearsStack() async throws {
|
||||
@Test
|
||||
mutating func roomClearsStack() async throws {
|
||||
try await process(route: .room(roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 0)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
chatsTabFlowCoordinator.handleAppRoute(.childRoom(roomID: "2", via: []), animated: true)
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1)
|
||||
XCTAssertTrue(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 1)
|
||||
#expect(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
|
||||
try await process(route: .room(roomID: "3", via: []), expectedState: .roomList(detailState: .room(roomID: "3")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 0)
|
||||
#expect(detailCoordinator != nil)
|
||||
}
|
||||
|
||||
func testEventRoutes() async throws {
|
||||
@Test
|
||||
mutating func eventRoutes() async throws {
|
||||
// A regular event route should set its room as the root of the stack and focus on the event.
|
||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount, 1)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "1")
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 0)
|
||||
#expect(detailCoordinator != nil)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount == 1)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID == "1")
|
||||
|
||||
// A child event route should push a new room screen onto the stack and focus on the event.
|
||||
chatsTabFlowCoordinator.handleAppRoute(.childEvent(eventID: "2", roomID: "2", via: []), animated: true)
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 1)
|
||||
XCTAssertTrue(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount, 2)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "2")
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 1)
|
||||
#expect(detailNavigationStack?.stackCoordinators.first is RoomScreenCoordinator)
|
||||
#expect(detailCoordinator != nil)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount == 2)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID == "2")
|
||||
|
||||
// A subsequent regular event route should clear the stack and set the new room as the root of the stack.
|
||||
try await process(route: .event(eventID: "3", roomID: "3", via: []), expectedState: .roomList(detailState: .room(roomID: "3")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount, 3)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "3")
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 0)
|
||||
#expect(detailCoordinator != nil)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount == 3)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID == "3")
|
||||
|
||||
// A regular event route for the same room should set a new instance of the room as the root of the stack.
|
||||
try await process(route: .event(eventID: "4", roomID: "3", via: []), expectedState: .roomList(detailState: .room(roomID: "3")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertEqual(detailNavigationStack?.stackCoordinators.count, 0)
|
||||
XCTAssertNotNil(detailCoordinator)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount, 4)
|
||||
XCTAssertEqual(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID, "4",
|
||||
"A new timeline should be created for the same room ID, so that the screen isn't stale while loading.")
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.stackCoordinators.count == 0)
|
||||
#expect(detailCoordinator != nil)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderCallsCount == 4)
|
||||
#expect(timelineControllerFactory.buildTimelineControllerRoomProxyInitialFocussedEventIDTimelineItemFactoryMediaProviderReceivedArguments?.initialFocussedEventID == "4",
|
||||
"A new timeline should be created for the same room ID, so that the screen isn't stale while loading.")
|
||||
}
|
||||
|
||||
func testShareMediaRouteWithRoom() async throws {
|
||||
@Test
|
||||
mutating func shareMediaRouteWithRoom() async throws {
|
||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
|
||||
let sharePayload: ShareExtensionPayload = .mediaFiles(roomID: "2", mediaFiles: [.init(url: .picturesDirectory, suggestedName: nil)])
|
||||
try await process(route: .share(sharePayload),
|
||||
expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertTrue((splitCoordinator?.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is MediaUploadPreviewScreenCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect((splitCoordinator.sheetCoordinator as? NavigationStackCoordinator)?.rootCoordinator is MediaUploadPreviewScreenCoordinator)
|
||||
}
|
||||
|
||||
func testShareTextRouteWithRoom() async throws {
|
||||
@Test
|
||||
mutating func shareTextRouteWithRoom() async throws {
|
||||
try await process(route: .event(eventID: "1", roomID: "1", via: []), expectedState: .roomList(detailState: .room(roomID: "1")))
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
|
||||
let sharePayload: ShareExtensionPayload = .text(roomID: "2", text: "Important text")
|
||||
try await process(route: .share(sharePayload),
|
||||
expectedState: .roomList(detailState: .room(roomID: "2")))
|
||||
|
||||
XCTAssertTrue(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
XCTAssertNil(splitCoordinator?.sheetCoordinator, "The media upload sheet shouldn't be shown when sharing text.")
|
||||
#expect(detailNavigationStack?.rootCoordinator is RoomScreenCoordinator)
|
||||
#expect(splitCoordinator.sheetCoordinator == nil, "The media upload sheet shouldn't be shown when sharing text.")
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func process(route: AppRoute, expectedState: ChatsTabFlowCoordinatorStateMachine.State) async throws {
|
||||
private mutating func process(route: AppRoute, expectedState: ChatsTabFlowCoordinatorStateMachine.State) async throws {
|
||||
// Sometimes the state machine's state changes before the coordinators have updated the stack.
|
||||
let delayedPublisher = stateMachineFactory.chatsTabFlowStatePublisher.delay(for: .milliseconds(100), scheduler: DispatchQueue.main)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user