diff --git a/Examples/xx-messenger/Sources/RegisterFeature/RegisterFeature.swift b/Examples/xx-messenger/Sources/RegisterFeature/RegisterFeature.swift index cb43c43056f6d3e53c2b73b4bdfc10189f052b21..9b9754c60eb11b019a7674d6c247698f5b16ef01 100644 --- a/Examples/xx-messenger/Sources/RegisterFeature/RegisterFeature.swift +++ b/Examples/xx-messenger/Sources/RegisterFeature/RegisterFeature.swift @@ -7,6 +7,10 @@ import XXMessengerClient import XXModels public struct RegisterState: Equatable { + public enum Error: Swift.Error, Equatable { + case usernameMismatch(registering: String, registered: String?) + } + public enum Field: String, Hashable { case username } @@ -82,14 +86,22 @@ public let registerReducer = Reducer<RegisterState, RegisterAction, RegisterEnvi do { let db = try env.db() try env.messenger.register(username: username) - var contact = try env.messenger.e2e.tryGet().getContact() - try contact.setFact(.username, username) + let contact = try env.messenger.myContact() + let facts = try contact.getFacts() try db.saveContact(Contact( id: try contact.getId(), marshaled: contact.data, - username: username, + username: facts.get(.username)?.value, + email: facts.get(.email)?.value, + phone: facts.get(.phone)?.value, createdAt: env.now() )) + guard facts.get(.username)?.value == username else { + throw RegisterState.Error.usernameMismatch( + registering: username, + registered: facts.get(.username)?.value + ) + } fulfill(.success(.finished)) } catch { @@ -106,6 +118,7 @@ public let registerReducer = Reducer<RegisterState, RegisterAction, RegisterEnvi return .none case .finished: + state.isRegistering = false return .none } } diff --git a/Examples/xx-messenger/Tests/RegisterFeatureTests/RegisterFeatureTests.swift b/Examples/xx-messenger/Tests/RegisterFeatureTests/RegisterFeatureTests.swift index b156335b3de889ad21d9819e483fc5e27ef7c6ed..e0ffc5ef4fe9a3bc5f9d9f91d288025cd1065c85 100644 --- a/Examples/xx-messenger/Tests/RegisterFeatureTests/RegisterFeatureTests.swift +++ b/Examples/xx-messenger/Tests/RegisterFeatureTests/RegisterFeatureTests.swift @@ -8,38 +8,40 @@ import XXModels final class RegisterFeatureTests: XCTestCase { func testRegister() throws { + let now = Date() + let username = "registering-username" + let myContactId = "my-contact-id".data(using: .utf8)! + let myContactData = "my-contact-data".data(using: .utf8)! + let myContactUsername = username + let myContactEmail = "my-contact-email" + let myContactPhone = "my-contact-phone" + let myContactFacts = [ + Fact(type: .username, value: myContactUsername), + Fact(type: .email, value: myContactEmail), + Fact(type: .phone, value: myContactPhone), + ] + + var messengerDidRegisterUsername: [String] = [] + var didGetMyContact: [MessengerMyContact.IncludeFacts?] = [] + var dbDidSaveContact: [XXModels.Contact] = [] + let store = TestStore( initialState: RegisterState(), reducer: registerReducer, environment: .unimplemented ) - - let now = Date() - let mainQueue = DispatchQueue.test - let bgQueue = DispatchQueue.test - var didSetFactsOnContact: [[XXClient.Fact]] = [] - var dbDidSaveContact: [XXModels.Contact] = [] - var messengerDidRegisterUsername: [String] = [] - store.environment.now = { now } - store.environment.mainQueue = mainQueue.eraseToAnyScheduler() - store.environment.bgQueue = bgQueue.eraseToAnyScheduler() + store.environment.mainQueue = .immediate + store.environment.bgQueue = .immediate store.environment.messenger.register.run = { username in messengerDidRegisterUsername.append(username) } - store.environment.messenger.e2e.get = { - var e2e: E2E = .unimplemented - e2e.getContact.run = { - var contact = XXClient.Contact.unimplemented("contact-data".data(using: .utf8)!) - contact.getIdFromContact.run = { _ in "contact-id".data(using: .utf8)! } - contact.getFactsFromContact.run = { _ in [] } - contact.setFactsOnContact.run = { data, facts in - didSetFactsOnContact.append(facts) - return data - } - return contact - } - return e2e + store.environment.messenger.myContact.run = { includeFacts in + didGetMyContact.append(includeFacts) + var contact = XXClient.Contact.unimplemented(myContactData) + contact.getIdFromContact.run = { _ in myContactId } + contact.getFactsFromContact.run = { _ in myContactFacts } + return contact } store.environment.db.run = { var db: Database = .unimplemented @@ -50,33 +52,34 @@ final class RegisterFeatureTests: XCTestCase { return db } - store.send(.set(\.$username, "NewUser")) { - $0.username = "NewUser" + store.send(.set(\.$focusedField, .username)) { + $0.focusedField = .username + } + + store.send(.set(\.$username, myContactUsername)) { + $0.username = myContactUsername } store.send(.registerTapped) { + $0.focusedField = nil $0.isRegistering = true } - XCTAssertNoDifference(messengerDidRegisterUsername, []) - XCTAssertNoDifference(dbDidSaveContact, []) - - bgQueue.advance() - - XCTAssertNoDifference(messengerDidRegisterUsername, ["NewUser"]) - XCTAssertNoDifference(didSetFactsOnContact, [[Fact(type: .username, value: "NewUser")]]) + XCTAssertNoDifference(messengerDidRegisterUsername, [username]) XCTAssertNoDifference(dbDidSaveContact, [ XXModels.Contact( - id: "contact-id".data(using: .utf8)!, - marshaled: "contact-data".data(using: .utf8)!, - username: "NewUser", + id: myContactId, + marshaled: myContactData, + username: myContactUsername, + email: myContactEmail, + phone: myContactPhone, createdAt: now ) ]) - mainQueue.advance() - - store.receive(.finished) + store.receive(.finished) { + $0.isRegistering = false + } } func testGetDbFailure() throws { @@ -139,4 +142,78 @@ final class RegisterFeatureTests: XCTestCase { $0.failure = error.localizedDescription } } + + func testRegisterUsernameMismatchFailure() throws { + let now = Date() + let username = "registering-username" + let myContactId = "my-contact-id".data(using: .utf8)! + let myContactData = "my-contact-data".data(using: .utf8)! + let myContactUsername = "my-contact-username" + let myContactEmail = "my-contact-email" + let myContactPhone = "my-contact-phone" + let myContactFacts = [ + Fact(type: .username, value: myContactUsername), + Fact(type: .email, value: myContactEmail), + Fact(type: .phone, value: myContactPhone), + ] + + var messengerDidRegisterUsername: [String] = [] + var didGetMyContact: [MessengerMyContact.IncludeFacts?] = [] + var dbDidSaveContact: [XXModels.Contact] = [] + + let store = TestStore( + initialState: RegisterState( + username: username + ), + reducer: registerReducer, + environment: .unimplemented + ) + store.environment.now = { now } + store.environment.mainQueue = .immediate + store.environment.bgQueue = .immediate + store.environment.messenger.register.run = { username in + messengerDidRegisterUsername.append(username) + } + store.environment.messenger.myContact.run = { includeFacts in + didGetMyContact.append(includeFacts) + var contact = XXClient.Contact.unimplemented(myContactData) + contact.getIdFromContact.run = { _ in myContactId } + contact.getFactsFromContact.run = { _ in myContactFacts } + return contact + } + store.environment.db.run = { + var db: Database = .unimplemented + db.saveContact.run = { contact in + dbDidSaveContact.append(contact) + return contact + } + return db + } + + store.send(.registerTapped) { + $0.focusedField = nil + $0.isRegistering = true + } + + XCTAssertNoDifference(messengerDidRegisterUsername, [username]) + XCTAssertNoDifference(dbDidSaveContact, [ + XXModels.Contact( + id: myContactId, + marshaled: myContactData, + username: myContactUsername, + email: myContactEmail, + phone: myContactPhone, + createdAt: now + ) + ]) + + let failure = RegisterState.Error.usernameMismatch( + registering: username, + registered: myContactUsername + ) + store.receive(.failed(failure.localizedDescription)) { + $0.isRegistering = false + $0.failure = failure.localizedDescription + } + } }