mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Adopt StateStoreViewModelV2 in the authentication screens and some settings screens. (#4083)
* Add some tests for DeferredFulfillment with Observation. * Use StateStoreViewModelV2 in AuthenticationStartScreen. * Use StateStoreViewModelV2 in ServerConfirmationScreen. * Use StateStoreViewModelV2 in ServerSelectionScreen. * Use StateStoreViewModelV2 in SoftLogoutScreen. * Use StateStoreViewModelV2 in SettingsScreen. * Use StateStoreViewModelV2 in DeveloperOptionsScreen. * Use StateStoreViewModelV2 in AdvancedSettingsScreen.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
@testable import ElementX
|
||||
import XCTest
|
||||
|
||||
class DeferredFulfillmentTests: XCTestCase {
|
||||
private let observable = SomeObservable()
|
||||
|
||||
func testObservableWithoutUpdate() async throws {
|
||||
// Given a deferred fulfilment on a value that already matches the expected value.
|
||||
let initialValue = observable.counter
|
||||
let deferred = deferFulfillment(observable.observe(\.counter)) { $0 == initialValue }
|
||||
|
||||
// Then the test should be fulfilled by the initial value and shouldn't timeout whilst waiting for a update.
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
func testObservableWithSynchronousUpdate() async throws {
|
||||
// Given a deferred fulfilment for an expected value.
|
||||
let newValue = 100
|
||||
let deferred = deferFulfillment(observable.observe(\.counter)) { $0 == newValue }
|
||||
|
||||
// When that value is changed synchronously.
|
||||
observable.counter = newValue
|
||||
XCTAssertEqual(observable.counter, newValue)
|
||||
|
||||
// Then the test should be fulfilled.
|
||||
try await deferred.fulfill()
|
||||
XCTAssertEqual(observable.counter, newValue)
|
||||
}
|
||||
|
||||
func testObservableAsynchronousUpdate() async throws {
|
||||
// Given a deferred fulfilment for an expected value.
|
||||
let newValue = 100
|
||||
let deferred = deferFulfillment(observable.observe(\.counter)) { $0 == newValue }
|
||||
|
||||
// When that value is changed asynchronously.
|
||||
Task { try await observable.setCounter(newValue, delay: .seconds(1)) }
|
||||
XCTAssertEqual(observable.counter, 0)
|
||||
|
||||
// Then the test should be fulfilled once the update has taken place.
|
||||
try await deferred.fulfill()
|
||||
XCTAssertEqual(observable.counter, newValue)
|
||||
}
|
||||
|
||||
func testObservableMultipleUpdates() async throws {
|
||||
// Given a deferred fulfilment for an expected value.
|
||||
let finalValue = 500
|
||||
let deferred = deferFulfillment(observable.observe(\.counter)) { $0 == finalValue }
|
||||
|
||||
// When that value is changed asynchronously with some intermediate values before it is reached.
|
||||
Task {
|
||||
try await observable.setCounter(100, delay: .seconds(.random(in: 1.0...2.0)))
|
||||
try await observable.setCounter(250, delay: .seconds(.random(in: 1.0...2.0)))
|
||||
try await observable.setCounter(finalValue, delay: .seconds(.random(in: 1.0...2.0)))
|
||||
}
|
||||
XCTAssertEqual(observable.counter, 0)
|
||||
|
||||
// Then the test should be fulfilled once the expected update has taken place.
|
||||
try await deferred.fulfill()
|
||||
XCTAssertEqual(observable.counter, finalValue)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
@Observable private class SomeObservable {
|
||||
var counter = 0
|
||||
|
||||
func setCounter(_ newValue: Int, delay: Duration? = nil) async throws {
|
||||
if let delay {
|
||||
try await Task.sleep(for: delay)
|
||||
}
|
||||
counter = newValue
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
// When continuing from the confirmation screen.
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||
let deferred = deferFulfillment(context.observe(\.alertInfo)) { $0 != nil }
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
|
||||
@@ -167,7 +167,7 @@ class ServerConfirmationScreenViewModelTests: XCTestCase {
|
||||
XCTAssertNil(context.alertInfo)
|
||||
|
||||
// When continuing from the confirmation screen.
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||
let deferred = deferFulfillment(context.observe(\.alertInfo)) { $0 != nil }
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
|
||||
// When selecting a server that doesn't support login.
|
||||
context.homeserverAddress = "server.net"
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||
let deferred = deferFulfillment(context.observe(\.alertInfo)) { $0 != nil }
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
|
||||
@@ -78,7 +78,7 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
|
||||
// When selecting a server that doesn't support registration.
|
||||
context.homeserverAddress = "example.com"
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.alertInfo != nil }
|
||||
let deferred = deferFulfillment(context.observe(\.alertInfo)) { $0 != nil }
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
|
||||
@@ -96,7 +96,7 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
"The standard footer message should be shown.")
|
||||
|
||||
// When attempting to discover an invalid server
|
||||
var deferred = deferFulfillment(context.$viewState) { $0.isShowingFooterError }
|
||||
var deferred = deferFulfillment(context.observe(\.viewState.isShowingFooterError)) { $0 }
|
||||
context.homeserverAddress = "idontexist"
|
||||
context.send(viewAction: .confirm)
|
||||
try await deferred.fulfill()
|
||||
@@ -108,7 +108,7 @@ class ServerSelectionScreenViewModelTests: XCTestCase {
|
||||
"The error message should be shown.")
|
||||
|
||||
// And when clearing the error.
|
||||
deferred = deferFulfillment(context.$viewState) { !$0.isShowingFooterError }
|
||||
deferred = deferFulfillment(context.observe(\.viewState.isShowingFooterError)) { !$0 }
|
||||
context.homeserverAddress = ""
|
||||
context.send(viewAction: .clearFooterError)
|
||||
try await deferred.fulfill()
|
||||
|
||||
+6
-33
@@ -26,47 +26,20 @@ class SettingsScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
@MainActor func testLogout() async throws {
|
||||
var correctResult = false
|
||||
|
||||
viewModel.actions
|
||||
.sink { action in
|
||||
switch action {
|
||||
case .logout:
|
||||
correctResult = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
let deferred = deferFulfillment(viewModel.actions) { $0 == .logout }
|
||||
context.send(viewAction: .logout)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
func testReportBug() async throws {
|
||||
var correctResult = false
|
||||
viewModel.actions
|
||||
.sink { action in
|
||||
correctResult = action == .reportBug
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
let deferred = deferFulfillment(viewModel.actions) { $0 == .reportBug }
|
||||
context.send(viewAction: .reportBug)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
func testAnalytics() async throws {
|
||||
var correctResult = false
|
||||
viewModel.actions
|
||||
.sink { action in
|
||||
correctResult = action == .analytics
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
let deferred = deferFulfillment(viewModel.actions) { $0 == .analytics }
|
||||
context.send(viewAction: .analytics)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@ import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class SoftLogoutViewModelTests: XCTestCase {
|
||||
class SoftLogoutScreenViewModelTests: XCTestCase {
|
||||
let credentials = SoftLogoutScreenCredentials(userID: "mock_user_id",
|
||||
homeserverName: "https://example.com",
|
||||
userDisplayName: "mock_username",
|
||||
Reference in New Issue
Block a user