mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00

* WIP RequestToJoin struct * implemented the logic to display the cells * knock request banner accept flow * mark all knocks as seen implemented * details logic * implemented accept, decline and ban in the list * added a loader and modified the stacked view of the banner * pr suggestions * updated naming and loading strings * added the initial loading state improved code and the tests * updated a string that has changed * code improvement * tests for the room screen view model * room details tests and improved the knock requests tests for the room screen * knock requests list tests * added error state alerts with retry * struct has been renamed on the sdk so I renamed it also on the app side * update SDK
227 lines
11 KiB
Swift
227 lines
11 KiB
Swift
//
|
|
// Copyright 2022-2024 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// Please see LICENSE in the repository root for full details.
|
|
//
|
|
|
|
import XCTest
|
|
|
|
@testable import ElementX
|
|
|
|
@MainActor
|
|
class KnockRequestsListScreenViewModelTests: XCTestCase {
|
|
var viewModel: KnockRequestsListScreenViewModelProtocol!
|
|
|
|
var context: KnockRequestsListScreenViewModelType.Context {
|
|
viewModel.context
|
|
}
|
|
|
|
override func setUpWithError() throws {
|
|
AppSettings.resetAllSettings()
|
|
}
|
|
|
|
func testLoadingState() async throws {
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(knockRequestsState: .loading, joinRule: .knock))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
let deferred = deferFulfillment(context.$viewState) { state in
|
|
!state.shouldDisplayRequests &&
|
|
state.isKnockableRoom &&
|
|
state.canAccept &&
|
|
!state.canBan &&
|
|
!state.canDecline &&
|
|
state.isLoading &&
|
|
!state.shouldDisplayEmptyView
|
|
}
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testEmptyState() async throws {
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(knockRequestsState: .loaded([]), joinRule: .knock))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
let deferred = deferFulfillment(context.$viewState) { state in
|
|
!state.shouldDisplayRequests &&
|
|
state.isKnockableRoom &&
|
|
state.canAccept &&
|
|
!state.canBan &&
|
|
!state.canDecline &&
|
|
!state.isLoading &&
|
|
state.shouldDisplayEmptyView
|
|
}
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testLoadedState() async throws {
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(members: [.mockAdmin],
|
|
knockRequestsState: .loaded([KnockRequestProxyMock(.init(eventID: "1", userID: "@alice:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "2", userID: "@bob:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "3", userID: "@charlie:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "4", userID: "@dan:matrix.org"))]),
|
|
ownUserID: RoomMemberProxyMock.mockAdmin.userID,
|
|
joinRule: .knock))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
var deferred = deferFulfillment(context.$viewState) { state in
|
|
state.shouldDisplayRequests &&
|
|
state.isKnockableRoom &&
|
|
state.canAccept &&
|
|
state.canBan &&
|
|
state.canDecline &&
|
|
!state.isLoading &&
|
|
!state.shouldDisplayEmptyView &&
|
|
state.displayedRequests.count == 4 &&
|
|
state.handledEventIDs.isEmpty &&
|
|
state.shouldDisplayAcceptAllButton
|
|
}
|
|
try await deferred.fulfill()
|
|
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.shouldDisplayRequests &&
|
|
state.handledEventIDs == ["1"] &&
|
|
!state.shouldDisplayEmptyView &&
|
|
state.displayedRequests.count == 3 &&
|
|
state.shouldDisplayAcceptAllButton
|
|
}
|
|
context.send(viewAction: .acceptRequest(eventID: "1"))
|
|
try await deferred.fulfill()
|
|
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.bindings.alertInfo?.id == .declineRequest
|
|
}
|
|
context.send(viewAction: .declineRequest(eventID: "2"))
|
|
try await deferred.fulfill()
|
|
|
|
guard let declineAlertInfo = context.alertInfo else {
|
|
XCTFail("Can't be nil")
|
|
return
|
|
}
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.shouldDisplayRequests &&
|
|
state.handledEventIDs == ["1", "2"] &&
|
|
!state.shouldDisplayEmptyView &&
|
|
state.displayedRequests.count == 2 &&
|
|
state.shouldDisplayAcceptAllButton
|
|
}
|
|
declineAlertInfo.primaryButton.action?()
|
|
try await deferred.fulfill()
|
|
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.bindings.alertInfo?.id == .declineAndBan
|
|
}
|
|
context.send(viewAction: .ban(eventID: "3"))
|
|
try await deferred.fulfill()
|
|
|
|
guard let banAlertInfo = context.alertInfo else {
|
|
XCTFail("Can't be nil")
|
|
return
|
|
}
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.shouldDisplayRequests &&
|
|
state.handledEventIDs == ["1", "2", "3"] &&
|
|
!state.shouldDisplayEmptyView &&
|
|
state.displayedRequests.count == 1 &&
|
|
!state.shouldDisplayAcceptAllButton
|
|
}
|
|
banAlertInfo.primaryButton.action?()
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testAcceptAll() async throws {
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(knockRequestsState: .loaded([KnockRequestProxyMock(.init(eventID: "1", userID: "@alice:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "2", userID: "@bob:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "3", userID: "@charlie:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "4", userID: "@dan:matrix.org"))]),
|
|
joinRule: .knock))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
var deferred = deferFulfillment(context.$viewState) { state in
|
|
state.shouldDisplayRequests &&
|
|
state.isKnockableRoom &&
|
|
state.canAccept &&
|
|
!state.canBan &&
|
|
!state.canDecline &&
|
|
!state.isLoading &&
|
|
!state.shouldDisplayEmptyView &&
|
|
state.displayedRequests.count == 4 &&
|
|
state.handledEventIDs.isEmpty &&
|
|
state.shouldDisplayAcceptAllButton
|
|
}
|
|
try await deferred.fulfill()
|
|
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
state.bindings.alertInfo?.id == .acceptAllRequests
|
|
}
|
|
context.send(viewAction: .acceptAllRequests)
|
|
try await deferred.fulfill()
|
|
|
|
guard let alertInfo = context.alertInfo else {
|
|
XCTFail("Can't be nil")
|
|
return
|
|
}
|
|
|
|
deferred = deferFulfillment(context.$viewState) { state in
|
|
!state.shouldDisplayRequests &&
|
|
state.handledEventIDs == ["1", "2", "3", "4"] &&
|
|
!state.isLoading &&
|
|
state.shouldDisplayEmptyView
|
|
}
|
|
alertInfo.primaryButton.action?()
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testLoadedStateBecomesEmptyIfTheJoinRuleIsNotKnocking() async throws {
|
|
// If there is a sudden change in the rule, but the requests are still published, we want to hide all of them and show the empty view
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(members: [.mockAdmin],
|
|
knockRequestsState: .loaded([KnockRequestProxyMock(.init(eventID: "1", userID: "@alice:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "2", userID: "@bob:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "3", userID: "@charlie:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "4", userID: "@dan:matrix.org"))]),
|
|
ownUserID: RoomMemberProxyMock.mockAdmin.userID,
|
|
joinRule: .invite))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
let deferred = deferFulfillment(context.$viewState) { state in
|
|
!state.shouldDisplayRequests &&
|
|
state.shouldDisplayEmptyView &&
|
|
!state.isLoading &&
|
|
!state.isKnockableRoom
|
|
}
|
|
try await deferred.fulfill()
|
|
}
|
|
|
|
func testLoadedStateBecomesEmptyIfPermissionsAreRemoved() async throws {
|
|
// If there is a sudden change in permissions, and the user can't do any other action, we hide all the requests and shoe the empty view
|
|
let roomProxyMock = JoinedRoomProxyMock(.init(knockRequestsState: .loaded([KnockRequestProxyMock(.init(eventID: "1", userID: "@alice:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "2", userID: "@bob:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "3", userID: "@charlie:matrix.org")),
|
|
KnockRequestProxyMock(.init(eventID: "4", userID: "@dan:matrix.org"))]),
|
|
canUserInvite: false,
|
|
joinRule: .knock))
|
|
viewModel = KnockRequestsListScreenViewModel(roomProxy: roomProxyMock,
|
|
mediaProvider: MediaProviderMock(),
|
|
userIndicatorController: UserIndicatorControllerMock())
|
|
|
|
let deferred = deferFulfillment(context.$viewState) { state in
|
|
!state.shouldDisplayRequests &&
|
|
state.shouldDisplayEmptyView &&
|
|
!state.canAccept &&
|
|
!state.canBan &&
|
|
!state.canDecline &&
|
|
!state.isLoading
|
|
}
|
|
try await deferred.fulfill()
|
|
}
|
|
}
|