Introduce a StartChatFlowCoordinator instead of handing a navigation stack to the Screen Coordinator. (#4674)

* Introduce a basic StartChatFlowCoordinator.

* Move the rest of the start chat flow from the screen coordinator into the flow coordinator.

* Add a UI test for the entire start chat flow.

* Refactor CreateRoom… to CreateRoomScreen…
This commit is contained in:
Doug
2025-10-30 16:12:56 +00:00
committed by GitHub
parent 401ff49882
commit 933891614c
68 changed files with 764 additions and 789 deletions
@@ -13,38 +13,28 @@ import XCTest
@MainActor
class CreateRoomScreenViewModelTests: XCTestCase {
var viewModel: CreateRoomViewModelProtocol!
var viewModel: CreateRoomScreenViewModelProtocol!
var clientProxy: ClientProxyMock!
var userSession: UserSessionMock!
private let usersSubject = CurrentValueSubject<[UserProfileProxy], Never>([])
var context: CreateRoomViewModel.Context {
var context: CreateRoomScreenViewModel.Context {
viewModel.context
}
override func setUpWithError() throws {
clientProxy = ClientProxyMock(.init(userIDServerName: "matrix.org", userID: "@a:b.com"))
clientProxy.roomForIdentifierClosure = { roomID in .joined(JoinedRoomProxyMock(.init(id: roomID))) }
userSession = UserSessionMock(.init(clientProxy: clientProxy))
let parameters = CreateRoomFlowParameters()
ServiceLocator.shared.settings.knockingEnabled = true
let viewModel = CreateRoomViewModel(userSession: userSession,
createRoomParameters: .init(parameters),
selectedUsers: [.mockAlice, .mockBob, .mockCharlie],
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
appSettings: ServiceLocator.shared.settings)
let viewModel = CreateRoomScreenViewModel(userSession: userSession,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
appSettings: ServiceLocator.shared.settings)
self.viewModel = viewModel
}
func testDeselectUser() {
XCTAssertFalse(context.viewState.selectedUsers.isEmpty)
XCTAssertEqual(context.viewState.selectedUsers.count, 3)
XCTAssertEqual(context.viewState.selectedUsers.first?.userID, UserProfileProxy.mockAlice.userID)
context.send(viewAction: .deselectUser(.mockAlice))
XCTAssertNotEqual(context.viewState.selectedUsers.first?.userID, UserProfileProxy.mockAlice.userID)
}
func testDefaultSecurity() {
XCTAssertTrue(context.viewState.bindings.isRoomPrivate)
}
@@ -65,7 +55,7 @@ class CreateRoomScreenViewModelTests: XCTestCase {
// When creating the room.
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLAliasLocalPartReturnValue = .success("1")
let deferred = deferFulfillment(viewModel.actions) { action in
guard case .openRoom("1") = action else { return false }
guard case .createdRoom(let roomProxy) = action, roomProxy.id == "1" else { return false }
return true
}
context.send(viewAction: .createRoom)
@@ -21,7 +21,10 @@ class InviteUsersScreenViewModelTests: XCTestCase {
}
func testSelectUser() {
setupWithRoomType(roomType: .draft)
let roomProxy = JoinedRoomProxyMock(.init(name: "newroom", members: []))
roomProxy.inviteUserIDReturnValue = .success(())
setupViewModel(roomProxy: roomProxy, isSkippable: true)
XCTAssertTrue(context.viewState.selectedUsers.isEmpty)
context.send(viewAction: .toggleUser(.mockAlice))
XCTAssertTrue(context.viewState.selectedUsers.count == 1)
@@ -29,7 +32,10 @@ class InviteUsersScreenViewModelTests: XCTestCase {
}
func testReselectUser() {
setupWithRoomType(roomType: .draft)
let roomProxy = JoinedRoomProxyMock(.init(name: "newroom", members: []))
roomProxy.inviteUserIDReturnValue = .success(())
setupViewModel(roomProxy: roomProxy, isSkippable: true)
XCTAssertTrue(context.viewState.selectedUsers.isEmpty)
context.send(viewAction: .toggleUser(.mockAlice))
XCTAssertEqual(context.viewState.selectedUsers.count, 1)
@@ -39,7 +45,10 @@ class InviteUsersScreenViewModelTests: XCTestCase {
}
func testDeselectUser() {
setupWithRoomType(roomType: .draft)
let roomProxy = JoinedRoomProxyMock(.init(name: "newroom", members: []))
roomProxy.inviteUserIDReturnValue = .success(())
setupViewModel(roomProxy: roomProxy, isSkippable: true)
XCTAssertTrue(context.viewState.selectedUsers.isEmpty)
context.send(viewAction: .toggleUser(.mockAlice))
XCTAssertEqual(context.viewState.selectedUsers.count, 1)
@@ -52,7 +61,7 @@ class InviteUsersScreenViewModelTests: XCTestCase {
let mockedMembers: [RoomMemberProxyMock] = [.mockAlice, .mockBob]
let roomProxy = JoinedRoomProxyMock(.init(name: "test", members: mockedMembers))
roomProxy.inviteUserIDReturnValue = .success(())
setupWithRoomType(roomType: .room(roomProxy: roomProxy))
setupViewModel(roomProxy: roomProxy, isSkippable: false)
let deferredState = deferFulfillment(viewModel.context.$viewState) { state in
state.isUserSelected(.mockAlice)
@@ -66,8 +75,6 @@ class InviteUsersScreenViewModelTests: XCTestCase {
switch action {
case .dismiss:
return true
default:
return false
}
}
@@ -77,12 +84,12 @@ class InviteUsersScreenViewModelTests: XCTestCase {
XCTAssertEqual(roomProxy.inviteUserIDReceivedInvocations, [RoomMemberProxyMock.mockAlice.userID])
}
private func setupWithRoomType(roomType: InviteUsersScreenRoomType) {
private func setupViewModel(roomProxy: JoinedRoomProxyProtocol, isSkippable: Bool) {
userDiscoveryService = UserDiscoveryServiceMock()
userDiscoveryService.searchProfilesWithReturnValue = .success([])
let viewModel = InviteUsersScreenViewModel(userSession: UserSessionMock(.init()),
selectedUsers: nil,
roomType: roomType,
roomProxy: roomProxy,
isSkippable: isSkippable,
userDiscoveryService: userDiscoveryService,
userIndicatorController: UserIndicatorControllerMock(),
appSettings: ServiceLocator.shared.settings)
@@ -56,7 +56,7 @@ class StartChatScreenViewModelTests: XCTestCase {
try await deferredViewState.fulfill()
let deferredAction = deferFulfillment(viewModel.actions) { action in
action == .showRoom(withIdentifier: "id")
action == .showRoom(roomID: "id")
}
context.send(viewAction: .joinRoomByAddress)
try await deferredAction.fulfill()