mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Add alias to public room creation (#3450)
* added the address section * updated code and strings * syncing name and address * improved code * added a way to reset the state * better documentation * update strings * handling the alias * alias error state * update strings * error handling * improved the error handling * new preview tests, even if they do not work well * improved tests * unit tests * pr comments and using the correct value * fix * pr comments * to improve safety and control of the FF * fixed a test * updated tests * update SDK
This commit is contained in:
@@ -25,7 +25,7 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
cancellables.removeAll()
|
||||
clientProxy = ClientProxyMock(.init(userID: "@a:b.com"))
|
||||
clientProxy = ClientProxyMock(.init(userIDServerName: "matrix.org", userID: "@a:b.com"))
|
||||
userSession = UserSessionMock(.init(clientProxy: clientProxy))
|
||||
let parameters = CreateRoomFlowParameters()
|
||||
usersSubject.send([.mockAlice, .mockBob, .mockCharlie])
|
||||
@@ -68,21 +68,25 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
||||
|
||||
func testCreateRoomRequirements() {
|
||||
XCTAssertFalse(context.viewState.canCreateRoom)
|
||||
context.roomName = "A"
|
||||
context.send(viewAction: .updateRoomName("A"))
|
||||
XCTAssertTrue(context.viewState.canCreateRoom)
|
||||
}
|
||||
|
||||
func testCreateKnockingRoom() async {
|
||||
context.roomName = "A"
|
||||
context.send(viewAction: .updateRoomName("A"))
|
||||
context.roomTopic = "B"
|
||||
context.isRoomPrivate = false
|
||||
// When setting the room as private we always reset the knocking state to the default value of false
|
||||
// so we need to wait a main actor cycle to ensure the view state is updated
|
||||
await Task.yield()
|
||||
context.isKnockingOnly = true
|
||||
XCTAssertTrue(context.viewState.canCreateRoom)
|
||||
|
||||
let expectation = expectation(description: "Wait for the room to be created")
|
||||
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure = { _, _, isPrivate, isKnockingOnly, _, _ in
|
||||
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLAliasLocalPartClosure = { _, _, isPrivate, isKnockingOnly, _, _, localAliasPart in
|
||||
XCTAssertTrue(isKnockingOnly)
|
||||
XCTAssertFalse(isPrivate)
|
||||
XCTAssertEqual(localAliasPart, "a")
|
||||
defer { expectation.fulfill() }
|
||||
return .success("")
|
||||
}
|
||||
@@ -90,14 +94,67 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
||||
await fulfillment(of: [expectation])
|
||||
}
|
||||
|
||||
func testCreatePublicRoomFailsForInvalidAlias() async throws {
|
||||
context.send(viewAction: .updateRoomName("A"))
|
||||
context.roomTopic = "B"
|
||||
context.isRoomPrivate = false
|
||||
// When setting the room as private we always reset the alias
|
||||
// so we need to wait a main actor cycle to ensure the view state is updated
|
||||
await Task.yield()
|
||||
|
||||
// we wait for the debounce to show the error
|
||||
let deferred = deferFulfillment(context.$viewState) { viewState in
|
||||
viewState.aliasErrors.contains(.invalidSymbols) && !viewState.canCreateRoom
|
||||
}
|
||||
context.send(viewAction: .updateAliasLocalPart("#:"))
|
||||
try await deferred.fulfill()
|
||||
|
||||
// We also want to force the room creation in case the user may tap the button before the debounce
|
||||
// blocked it
|
||||
context.send(viewAction: .createRoom)
|
||||
await Task.yield()
|
||||
XCTAssertFalse(clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLAliasLocalPartCalled)
|
||||
}
|
||||
|
||||
func testCreatePublicRoomFailsForExistingAlias() async throws {
|
||||
clientProxy.isAliasAvailableReturnValue = .success(false)
|
||||
context.send(viewAction: .updateRoomName("A"))
|
||||
context.roomTopic = "B"
|
||||
context.isRoomPrivate = false
|
||||
// When setting the room as private we always reset the alias
|
||||
// so we need to wait a main actor cycle to ensure the view state is updated
|
||||
await Task.yield()
|
||||
|
||||
// we wait for the debounce to show the error
|
||||
let deferred = deferFulfillment(context.$viewState) { viewState in
|
||||
viewState.aliasErrors.contains(.alreadyExists) && !viewState.canCreateRoom
|
||||
}
|
||||
context.send(viewAction: .updateAliasLocalPart("abc"))
|
||||
try await deferred.fulfill()
|
||||
|
||||
// We also want to force the room creation in case the user may tap the button before the debounce
|
||||
// blocked it
|
||||
let expectation = expectation(description: "Wait for the alias to be checked again")
|
||||
clientProxy.isAliasAvailableClosure = { _ in
|
||||
defer {
|
||||
expectation.fulfill()
|
||||
}
|
||||
return .success(false)
|
||||
}
|
||||
context.send(viewAction: .createRoom)
|
||||
await fulfillment(of: [expectation])
|
||||
XCTAssertEqual(clientProxy.isAliasAvailableCallsCount, 2)
|
||||
XCTAssertFalse(clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLAliasLocalPartCalled)
|
||||
}
|
||||
|
||||
func testCreatePrivateRoomCantHaveKnockRule() async {
|
||||
context.roomName = "A"
|
||||
context.send(viewAction: .updateRoomName("A"))
|
||||
context.roomTopic = "B"
|
||||
context.isRoomPrivate = true
|
||||
context.isKnockingOnly = true
|
||||
context.send(viewAction: .createRoom)
|
||||
let expectation = expectation(description: "Wait for the room to be created")
|
||||
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLClosure = { _, _, isPrivate, isKnockingOnly, _, _ in
|
||||
clientProxy.createRoomNameTopicIsRoomPrivateIsKnockingOnlyUserIDsAvatarURLAliasLocalPartClosure = { _, _, isPrivate, isKnockingOnly, _, _, _ in
|
||||
XCTAssertFalse(isKnockingOnly)
|
||||
XCTAssertTrue(isPrivate)
|
||||
expectation.fulfill()
|
||||
@@ -105,4 +162,35 @@ class CreateRoomScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
await fulfillment(of: [expectation])
|
||||
}
|
||||
|
||||
func testNameAndAddressSync() async {
|
||||
context.isRoomPrivate = true
|
||||
await Task.yield()
|
||||
context.send(viewAction: .updateRoomName("abc"))
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "abc")
|
||||
XCTAssertEqual(context.viewState.roomName, "abc")
|
||||
context.send(viewAction: .updateRoomName("DEF"))
|
||||
XCTAssertEqual(context.viewState.roomName, "DEF")
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "def")
|
||||
context.send(viewAction: .updateRoomName("a b c"))
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "a-b-c")
|
||||
XCTAssertEqual(context.viewState.roomName, "a b c")
|
||||
context.send(viewAction: .updateAliasLocalPart("hello-world"))
|
||||
// This removes the sync
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "hello-world")
|
||||
XCTAssertEqual(context.viewState.roomName, "a b c")
|
||||
|
||||
context.send(viewAction: .updateRoomName("Hello Matrix!"))
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "hello-world")
|
||||
XCTAssertEqual(context.viewState.roomName, "Hello Matrix!")
|
||||
|
||||
// Deleting the whole name will restore the sync
|
||||
context.send(viewAction: .updateRoomName(""))
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "")
|
||||
XCTAssertEqual(context.viewState.roomName, "")
|
||||
|
||||
context.send(viewAction: .updateRoomName("Hello# Matrix!"))
|
||||
XCTAssertEqual(context.viewState.aliasLocalPart, "hello-matrix!")
|
||||
XCTAssertEqual(context.viewState.roomName, "Hello# Matrix!")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user