From 3ff257c0750fa42e934f1167192b413ecee6113b Mon Sep 17 00:00:00 2001 From: David Langley Date: Wed, 12 Jul 2023 18:59:46 +0100 Subject: [PATCH] deferFulfillment all the things (#1306) --- .../Sources/BugReportViewModelTests.swift | 39 +++++------ .../Sources/InviteUsersViewModelTests.swift | 16 ++++- .../Sources/InvitesScreenViewModelTests.swift | 5 +- .../RoomDetailsEditScreenViewModelTests.swift | 6 +- .../Sources/RoomDetailsViewModelTests.swift | 66 ++++++++++--------- .../RoomMemberDetailsViewModelTests.swift | 51 +++++++------- 6 files changed, 101 insertions(+), 82 deletions(-) diff --git a/UnitTests/Sources/BugReportViewModelTests.swift b/UnitTests/Sources/BugReportViewModelTests.swift index c9ccf4547c..2885fc996f 100644 --- a/UnitTests/Sources/BugReportViewModelTests.swift +++ b/UnitTests/Sources/BugReportViewModelTests.swift @@ -71,17 +71,17 @@ class BugReportViewModelTests: XCTestCase { deviceID: nil, screenshot: nil, isModallyPresented: false) let context = viewModel.context + let deferred = deferFulfillment(viewModel.actions.collect(2).first()) context.send(viewAction: .submit) + let actions = try await deferred.fulfill() - _ = await viewModel - .actions - .values - .first { - guard case .submitFinished = $0 else { - return false - } - return true - } + guard case .submitStarted = actions[0] else { + return XCTFail("Action 1 was not .submitFailed") + } + + guard case .submitFinished = actions[1] else { + return XCTFail("Action 2 was not .submitFinished") + } XCTAssert(mockService.submitBugReportProgressListenerCallsCount == 1) XCTAssert(mockService.submitBugReportProgressListenerReceivedArguments?.bugReport == BugReport(userID: "@mock.client.com", deviceID: nil, text: "", includeLogs: true, includeCrashLog: true, canContact: false, githubLabels: [], files: [])) @@ -96,19 +96,20 @@ class BugReportViewModelTests: XCTestCase { userID: "@mock.client.com", deviceID: nil, screenshot: nil, isModallyPresented: false) + + let deferred = deferFulfillment(viewModel.actions.collect(2).first()) let context = viewModel.context context.send(viewAction: .submit) - - _ = await viewModel - .actions - .values - .first { - guard case .submitFailed = $0 else { - return false - } - return true - } + let actions = try await deferred.fulfill() + guard case .submitStarted = actions[0] else { + return XCTFail("Action 1 was not .submitFailed") + } + + guard case .submitFailed = actions[1] else { + return XCTFail("Action 2 was not .submitFailed") + } + XCTAssert(mockService.submitBugReportProgressListenerCallsCount == 1) XCTAssert(mockService.submitBugReportProgressListenerReceivedArguments?.bugReport == BugReport(userID: "@mock.client.com", deviceID: nil, text: "", includeLogs: true, includeCrashLog: true, canContact: false, githubLabels: [], files: [])) } diff --git a/UnitTests/Sources/InviteUsersViewModelTests.swift b/UnitTests/Sources/InviteUsersViewModelTests.swift index 8453f0da71..574d7a5c24 100644 --- a/UnitTests/Sources/InviteUsersViewModelTests.swift +++ b/UnitTests/Sources/InviteUsersViewModelTests.swift @@ -59,17 +59,27 @@ class InviteUsersScreenViewModelTests: XCTestCase { XCTAssertTrue(context.viewState.selectedUsers.isEmpty) } - func testInviteButton() async { + func testInviteButton() async throws { let mockedMembers: [RoomMemberProxyMock] = [.mockAlice, .mockBob] setupWithRoomType(roomType: .room(roomProxy: RoomProxyMock(with: .init(displayName: "test", members: mockedMembers)))) - _ = await viewModel.context.$viewState.values.first(where: { $0.membershipState.isEmpty == false }) + + let deferredState = deferFulfillment(viewModel.context.$viewState + .map(\.membershipState) + .map(\.isEmpty) + .removeDuplicates() + .collect(2).first(), message: "2 states should be published.") context.send(viewAction: .toggleUser(.mockAlice)) + let states = try await deferredState.fulfill() + XCTAssertEqual(states, [true, false]) + + let deferredAction = deferFulfillment(viewModel.actions.first(), message: "1 action should be published.") + Task.detached(priority: .low) { await self.context.send(viewAction: .proceed) } - let action = await viewModel.actions.values.first() + let action = try await deferredAction.fulfill() guard case let .invite(members) = action else { XCTFail("Sent action should be 'invite'") diff --git a/UnitTests/Sources/InvitesScreenViewModelTests.swift b/UnitTests/Sources/InvitesScreenViewModelTests.swift index 41aaeff8e8..0822e7d62c 100644 --- a/UnitTests/Sources/InvitesScreenViewModelTests.swift +++ b/UnitTests/Sources/InvitesScreenViewModelTests.swift @@ -55,8 +55,11 @@ class InvitesScreenViewModelTests: XCTestCase { return } setupViewModel(roomSummaries: invites) + + let deferred = deferFulfillment(viewModel.actions.first(), message: "1 action should be published.") context.send(viewAction: .accept(.init(roomDetails: details, isUnread: false))) - let action: InvitesScreenViewModelAction? = await viewModel.actions.values.first() + let action = try await deferred.fulfill() + guard case .openRoom(let roomID) = action else { XCTFail("Wrong view model action") return diff --git a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift index 331222af3b..644f2dbff3 100644 --- a/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsEditScreenViewModelTests.swift @@ -91,12 +91,14 @@ class RoomDetailsEditScreenViewModelTests: XCTestCase { XCTAssertTrue(context.showMediaSheet) } - func testSaveTriggersViewModelAction() async { + func testSaveTriggersViewModelAction() async throws { setupViewModel(accountOwner: .mockOwner(allowedStateEvents: [.roomAvatar, .roomName, .roomTopic]), roomProxyConfiguration: .init(name: "Some room", displayName: "Some room")) + + let deferred = deferFulfillment(viewModel.actions.first()) context.name = "name" context.send(viewAction: .save) - let action = await viewModel.actions.values.first() + let action = try await deferred.fulfill() XCTAssertEqual(action, .saveFinished) } diff --git a/UnitTests/Sources/RoomDetailsViewModelTests.swift b/UnitTests/Sources/RoomDetailsViewModelTests.swift index b9ffb5c8c6..6c4a5f0695 100644 --- a/UnitTests/Sources/RoomDetailsViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsViewModelTests.swift @@ -35,30 +35,36 @@ class RoomDetailsScreenViewModelTests: XCTestCase { AppSettings.reset() } - func testLeaveRoomTappedWhenPublic() async { + func testLeaveRoomTappedWhenPublic() async throws { let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: true, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(accountUserID: "@owner:somewhere.com", roomProxy: roomProxyMock, mediaProvider: MockMediaProvider(), userIndicatorController: ServiceLocator.shared.userIndicatorController) - await context.nextViewState() + let deferred = deferFulfillment(context.$viewState.collect(2).first()) context.send(viewAction: .processTapLeave) - XCTAssertEqual(context.leaveRoomAlertItem?.state, .public) - XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertSubtitle) + let states = try await deferred.fulfill() + + XCTAssertNil(states[0].bindings.leaveRoomAlertItem) + XCTAssertEqual(states[1].bindings.leaveRoomAlertItem?.state, .public) + XCTAssertEqual(states[1].bindings.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertSubtitle) } - func testLeaveRoomTappedWhenRoomNotPublic() async { + func testLeaveRoomTappedWhenRoomNotPublic() async throws { let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: false, members: mockedMembers)) viewModel = RoomDetailsScreenViewModel(accountUserID: "@owner:somewhere.com", roomProxy: roomProxyMock, mediaProvider: MockMediaProvider(), userIndicatorController: ServiceLocator.shared.userIndicatorController) - await context.nextViewState() + let deferred = deferFulfillment(context.$viewState.collect(2).first()) context.send(viewAction: .processTapLeave) - XCTAssertEqual(context.leaveRoomAlertItem?.state, .private) - XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertPrivateSubtitle) + let states = try await deferred.fulfill() + context.send(viewAction: .processTapLeave) + XCTAssertNil(states[0].bindings.leaveRoomAlertItem) + XCTAssertEqual(states[1].bindings.leaveRoomAlertItem?.state, .private) + XCTAssertEqual(states[1].bindings.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertPrivateSubtitle) } func testLeaveRoomTappedWithLessThanTwoMembers() async { @@ -127,13 +133,13 @@ class RoomDetailsScreenViewModelTests: XCTestCase { await context.nextViewState() XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) context.send(viewAction: .ignoreConfirmed) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssert(context.viewState.dmRecipient?.isIgnored == true) } @@ -152,13 +158,13 @@ class RoomDetailsScreenViewModelTests: XCTestCase { await context.nextViewState() XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) context.send(viewAction: .ignoreConfirmed) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssert(context.viewState.dmRecipient?.isIgnored == false) XCTAssertNotNil(context.alertInfo) } @@ -178,13 +184,13 @@ class RoomDetailsScreenViewModelTests: XCTestCase { await context.nextViewState() XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) - context.send(viewAction: .unignoreConfirmed) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + context.send(viewAction: .unignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssert(context.viewState.dmRecipient?.isIgnored == false) } @@ -203,13 +209,13 @@ class RoomDetailsScreenViewModelTests: XCTestCase { await context.nextViewState() XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) - context.send(viewAction: .unignoreConfirmed) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + context.send(viewAction: .unignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssert(context.viewState.dmRecipient?.isIgnored == true) XCTAssertNotNil(context.alertInfo) } diff --git a/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift b/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift index 25cc44fff9..dd4836bb53 100644 --- a/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift +++ b/UnitTests/Sources/RoomMemberDetailsViewModelTests.swift @@ -44,13 +44,13 @@ class RoomMemberDetailsViewModelTests: XCTestCase { context.send(viewAction: .showIgnoreAlert) XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore)) - context.send(viewAction: .ignoreConfirmed) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - XCTAssertFalse(context.viewState.details.isIgnored) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } + context.send(viewAction: .ignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) XCTAssertTrue(context.viewState.details.isIgnored) } @@ -65,14 +65,13 @@ class RoomMemberDetailsViewModelTests: XCTestCase { context.send(viewAction: .showIgnoreAlert) XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore)) - context.send(viewAction: .ignoreConfirmed) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - XCTAssertFalse(context.viewState.details.isIgnored) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + context.send(viewAction: .ignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssertNotNil(context.alertInfo) XCTAssertFalse(context.viewState.details.isIgnored) } @@ -88,14 +87,13 @@ class RoomMemberDetailsViewModelTests: XCTestCase { context.send(viewAction: .showUnignoreAlert) XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore)) - context.send(viewAction: .unignoreConfirmed) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - XCTAssertTrue(context.viewState.details.isIgnored) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + context.send(viewAction: .unignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssertFalse(context.viewState.details.isIgnored) } @@ -110,14 +108,13 @@ class RoomMemberDetailsViewModelTests: XCTestCase { context.send(viewAction: .showUnignoreAlert) XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore)) - context.send(viewAction: .unignoreConfirmed) + let deferred = deferFulfillment(context.$viewState.map(\.isProcessingIgnoreRequest) + .removeDuplicates() + .collect(3).first()) - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == true } - XCTAssertTrue(context.viewState.isProcessingIgnoreRequest) - XCTAssertTrue(context.viewState.details.isIgnored) - - _ = await context.$viewState.values.first { $0.isProcessingIgnoreRequest == false } - XCTAssertFalse(context.viewState.isProcessingIgnoreRequest) + context.send(viewAction: .unignoreConfirmed) + let states = try await deferred.fulfill() + XCTAssertEqual(states, [false, true, false]) XCTAssertTrue(context.viewState.details.isIgnored) XCTAssertNotNil(context.alertInfo) }