mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Implement Knock Logic (#3573)
* 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
This commit is contained in:
@@ -18,6 +18,209 @@ class KnockRequestsListScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
viewModel = KnockRequestsListScreenViewModel(roomProxy: JoinedRoomProxyMock(.init()), mediaProvider: MediaProviderMock())
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user