Fix various flakey unit tests (#1783)

* Fix flakey emoji provider tests

* Fix flakey RoomScreenViewModel tests

* Fix flakey HomeScreenViewModel tests

* Fix flakey RoomMemberListScreen tests, problem with bindings getting overriden and deferFulfillment cancellable not getting stored

* Fix flakey RoomNotificationSettingsScreen tests and crashes

* Fix flakey RoomMemberDetailsScreen tests

* Deprecate old `deferFulfillment` and `nextViewState` methods

* Convert more files to the new `deferFulfillment`

* Converted the rest of the tests to the new deferFulfillment

* Removed now unused `nextViewState` and `deferFulfillment`

* Remove automatic retries from unit tests

* Reset analytics flag after running unit tests

* Address PR comments

* Introduce a new `deferFulfillment(publisher, keyPath, transitionValues)` method and use it where appropiate
This commit is contained in:
Stefan Ceriu
2023-09-26 13:28:29 +03:00
committed by GitHub
parent 1f3898c69d
commit a05c3e3774
27 changed files with 841 additions and 519 deletions
@@ -282,11 +282,14 @@ class RoomScreenViewModelTests: XCTestCase {
}
.store(in: &cancellables)
// Test
let deferred = deferFulfillment(viewModel.context.$viewState.collect(3).first(),
message: "The existing view state plus one new one should be published.")
let deferred = deferFulfillment(viewModel.context.$viewState) { value in
value.bindings.alertInfo != nil
}
viewModel.context.send(viewAction: .tappedOnUser(userID: "bob"))
try await deferred.fulfill()
XCTAssertFalse(viewModel.state.bindings.alertInfo.isNil)
XCTAssert(roomProxyMock.getMemberUserIDCallsCount == 1)
XCTAssertEqual(roomProxyMock.getMemberUserIDReceivedUserID, "bob")
@@ -295,7 +298,6 @@ class RoomScreenViewModelTests: XCTestCase {
// MARK: - Sending
func testRetrySend() async throws {
// Setup
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
@@ -306,16 +308,15 @@ class RoomScreenViewModelTests: XCTestCase {
analytics: ServiceLocator.shared.analytics,
userIndicatorController: userIndicatorControllerMock)
// Test
viewModel.context.send(viewAction: .retrySend(itemID: .init(timelineID: UUID().uuidString, transactionID: "test retry send id")))
await Task.yield()
try? await Task.sleep(for: .microseconds(500))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 1)
XCTAssert(roomProxyMock.retrySendTransactionIDReceivedInvocations == ["test retry send id"])
}
func testRetrySendNoTransactionID() async {
// Setup
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
@@ -326,14 +327,14 @@ class RoomScreenViewModelTests: XCTestCase {
analytics: ServiceLocator.shared.analytics,
userIndicatorController: userIndicatorControllerMock)
// Test
viewModel.context.send(viewAction: .retrySend(itemID: .random))
await Task.yield()
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 0)
}
func testCancelSend() async {
// Setup
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
@@ -344,15 +345,15 @@ class RoomScreenViewModelTests: XCTestCase {
analytics: ServiceLocator.shared.analytics,
userIndicatorController: userIndicatorControllerMock)
// Test
viewModel.context.send(viewAction: .cancelSend(itemID: .init(timelineID: UUID().uuidString, transactionID: "test cancel send id")))
try? await Task.sleep(for: .microseconds(500))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 1)
XCTAssert(roomProxyMock.cancelSendTransactionIDReceivedInvocations == ["test cancel send id"])
}
func testCancelSendNoTransactionID() async {
// Setup
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
@@ -363,16 +364,16 @@ class RoomScreenViewModelTests: XCTestCase {
analytics: ServiceLocator.shared.analytics,
userIndicatorController: userIndicatorControllerMock)
// Test
viewModel.context.send(viewAction: .cancelSend(itemID: .random))
await Task.yield()
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
}
// MARK: - Read Receipts
// swiftlint:disable force_unwrapping
func testSendReadReceipt() async throws {
// Given a room with only text items in the timeline
let items = [TextRoomTimelineItem(eventID: "t1"),
@@ -382,7 +383,7 @@ class RoomScreenViewModelTests: XCTestCase {
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then the receipt should be sent.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, true)
@@ -401,13 +402,13 @@ class RoomScreenViewModelTests: XCTestCase {
TextRoomTimelineItem(eventID: "t3")]
let (viewModel, roomProxy, timelineController, _) = readReceiptsConfiguration(with: items)
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t3")
// When sending a receipt for the first item in the timeline.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.first!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then the request should be ignored.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
@@ -417,10 +418,10 @@ class RoomScreenViewModelTests: XCTestCase {
let newMessage = TextRoomTimelineItem(eventID: "t4")
timelineController.timelineItems.append(newMessage)
timelineController.callbacks.send(.updatedTimelineItems)
try await Task.sleep(for: .microseconds(500))
try await Task.sleep(for: .milliseconds(100))
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(newMessage.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then the request should be made.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 2)
@@ -436,7 +437,7 @@ class RoomScreenViewModelTests: XCTestCase {
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then nothing should be sent.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, false)
@@ -451,7 +452,7 @@ class RoomScreenViewModelTests: XCTestCase {
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then a read receipt should be sent for the item before it.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, true)
@@ -465,13 +466,13 @@ class RoomScreenViewModelTests: XCTestCase {
SeparatorRoomTimelineItem(timelineID: "v3")]
let (viewModel, roomProxy, _, _) = readReceiptsConfiguration(with: items)
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t2")
// When sending the same receipt again
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .microseconds(100))
try await Task.sleep(for: .milliseconds(100))
// Then the second call should be ignored.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)