the report flow is now based on the matrix version and the new one will only be used if the SDK checks if the server supports it.
203 lines
8.4 KiB
Swift
203 lines
8.4 KiB
Swift
//
|
|
// Copyright 2022-2024 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.
|
|
//
|
|
|
|
import XCTest
|
|
|
|
@testable import ElementX
|
|
|
|
@MainActor
|
|
class JoinRoomScreenViewModelTests: XCTestCase {
|
|
private enum TestMode {
|
|
case joined
|
|
case knocked
|
|
case invited
|
|
case banned
|
|
}
|
|
|
|
var viewModel: JoinRoomScreenViewModelProtocol!
|
|
|
|
var clientProxy: ClientProxyMock!
|
|
var appSettings: AppSettings!
|
|
|
|
var context: JoinRoomScreenViewModelType.Context {
|
|
viewModel.context
|
|
}
|
|
|
|
override func setUp() {
|
|
AppSettings.resetAllSettings()
|
|
appSettings = AppSettings()
|
|
ServiceLocator.shared.register(appSettings: appSettings)
|
|
}
|
|
|
|
override func tearDown() {
|
|
viewModel = nil
|
|
clientProxy = nil
|
|
AppSettings.resetAllSettings()
|
|
}
|
|
|
|
func testInteraction() async throws {
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "There shouldn't be any seen invites before running the tests.")
|
|
|
|
setupViewModel()
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.mode == .joinable }.fulfill()
|
|
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "Only an invited room should register the room ID as a seen invite.")
|
|
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { $0 == .joined }
|
|
context.send(viewAction: .join)
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testAcceptInviteInteraction() async throws {
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "There shouldn't be any seen invites before running the tests.")
|
|
|
|
setupViewModel(mode: .invited)
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.mode == .invited(isDM: false) }.fulfill()
|
|
|
|
XCTAssertEqual(appSettings.seenInvites, ["1"], "The invited room's ID should be registered as a seen invite.")
|
|
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { $0 == .joined }
|
|
context.send(viewAction: .acceptInvite)
|
|
try await deferred.fulfill()
|
|
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "The after accepting an invite the invite should be forgotten in case the user leaves.")
|
|
}
|
|
|
|
func testDeclineInviteInteraction() async throws {
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "There shouldn't be any seen invites before running the tests.")
|
|
|
|
setupViewModel(mode: .invited)
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.mode == .invited(isDM: false) }.fulfill()
|
|
XCTAssertEqual(appSettings.seenInvites, ["1"], "The invited room's ID should be registered as a seen invite.")
|
|
|
|
context.send(viewAction: .declineInvite)
|
|
|
|
XCTAssertEqual(viewModel.context.alertInfo?.id, .declineInvite)
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { $0 == .dismiss }
|
|
context.alertInfo?.secondaryButton?.action?()
|
|
try await deferred.fulfill()
|
|
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "The after declining an invite the invite should be forgotten in case another invite is received.")
|
|
}
|
|
|
|
func testKnockedState() async throws {
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "There shouldn't be any seen invites before running the tests.")
|
|
setupViewModel(mode: .knocked)
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.mode == .knocked }.fulfill()
|
|
|
|
XCTAssertTrue(appSettings.seenInvites.isEmpty, "Only an invited room should register the room ID as a seen invite.")
|
|
}
|
|
|
|
func testCancelKnock() async throws {
|
|
setupViewModel(mode: .knocked)
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { state in
|
|
state.mode == .knocked
|
|
}.fulfill()
|
|
|
|
context.send(viewAction: .cancelKnock)
|
|
XCTAssertEqual(viewModel.context.alertInfo?.id, .cancelKnock)
|
|
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { action in
|
|
action == .dismiss
|
|
}
|
|
context.alertInfo?.secondaryButton?.action?()
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testDeclineAndBlockInviteLegacyInteraction() async throws {
|
|
setupViewModel(mode: .invited)
|
|
clientProxy.underlyingIsReportRoomSupported = false
|
|
let expectation = expectation(description: "Wait for the user to be ignored")
|
|
clientProxy.ignoreUserClosure = { userID in
|
|
defer { expectation.fulfill() }
|
|
XCTAssertEqual(userID, "@test:matrix.org")
|
|
return .success(())
|
|
}
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.roomDetails != nil }.fulfill()
|
|
|
|
context.send(viewAction: .declineInviteAndBlock(userID: "@test:matrix.org"))
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.bindings.alertInfo != nil }.fulfill()
|
|
XCTAssertEqual(viewModel.context.alertInfo?.id, .declineInviteAndBlock)
|
|
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { action in
|
|
action == .dismiss
|
|
}
|
|
context.alertInfo?.secondaryButton?.action?()
|
|
await fulfillment(of: [expectation], timeout: 10)
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testDeclineAndBlockInviteInteraction() async throws {
|
|
setupViewModel(mode: .invited)
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.roomDetails != nil }.fulfill()
|
|
let deferredAction = deferFulfillment(viewModel.actionsPublisher) { $0 == .presentDeclineAndBlock(userID: "@test:matrix.org") }
|
|
context.send(viewAction: .declineInviteAndBlock(userID: "@test:matrix.org"))
|
|
try await deferredAction.fulfill()
|
|
}
|
|
|
|
func testForgetRoom() async throws {
|
|
setupViewModel(mode: .banned)
|
|
|
|
try await deferFulfillment(viewModel.context.$viewState) { $0.roomDetails != nil }.fulfill()
|
|
|
|
let deferred = deferFulfillment(viewModel.actionsPublisher) { action in
|
|
action == .dismiss
|
|
}
|
|
context.send(viewAction: .forget)
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
private func setupViewModel(throwing: Bool = false, mode: TestMode = .joined) {
|
|
ServiceLocator.shared.settings.knockingEnabled = true
|
|
|
|
clientProxy = ClientProxyMock(.init())
|
|
|
|
clientProxy.joinRoomViaReturnValue = throwing ? .failure(.sdkError(ClientProxyMockError.generic)) : .success(())
|
|
clientProxy.joinRoomAliasReturnValue = clientProxy.joinRoomViaReturnValue
|
|
|
|
switch mode {
|
|
case .knocked:
|
|
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(RoomPreviewProxyMock.knocked)
|
|
|
|
clientProxy.roomForIdentifierClosure = { _ in
|
|
let roomProxy = KnockedRoomProxyMock(.init())
|
|
// to test the cancel knock function
|
|
roomProxy.cancelKnockUnderlyingReturnValue = .success(())
|
|
return .knocked(roomProxy)
|
|
}
|
|
case .joined:
|
|
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(RoomPreviewProxyMock.joinable)
|
|
case .invited:
|
|
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(RoomPreviewProxyMock.invited())
|
|
clientProxy.roomForIdentifierClosure = { _ in
|
|
let roomProxy = InvitedRoomProxyMock(.init())
|
|
roomProxy.rejectInvitationReturnValue = .success(())
|
|
return .invited(roomProxy)
|
|
}
|
|
case .banned:
|
|
clientProxy.roomPreviewForIdentifierViaReturnValue = .success(RoomPreviewProxyMock.banned)
|
|
clientProxy.roomForIdentifierClosure = { _ in
|
|
let roomProxy = BannedRoomProxyMock(.init())
|
|
roomProxy.forgetRoomReturnValue = .success(())
|
|
return .banned(roomProxy)
|
|
}
|
|
}
|
|
|
|
viewModel = JoinRoomScreenViewModel(roomID: "1",
|
|
via: [],
|
|
appSettings: appSettings,
|
|
clientProxy: clientProxy,
|
|
mediaProvider: MediaProviderMock(configuration: .init()),
|
|
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
|
}
|
|
}
|