diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift index 9fa77542c81c457d095244fbec6aceee8776c316..a538e28e2a409f08d7fc994b5716747813d6f493 100644 --- a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift +++ b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift @@ -11,6 +11,7 @@ public struct ChatComponent: ReducerProtocol { public struct State: Equatable, Identifiable { public enum ID: Equatable, Hashable { case contact(XXModels.Contact.ID) + case group(XXModels.Group.ID) } public struct Message: Equatable, Identifiable { @@ -93,25 +94,33 @@ public struct ChatComponent: ReducerProtocol { let myContactId = try messenger.e2e.tryGet().getContact().getId() state.myContactId = myContactId let queryChat: XXModels.Message.Query.Chat - let receivedFileTransfersQuery: XXModels.FileTransfer.Query - let sentFileTransfersQuery: XXModels.FileTransfer.Query + let receivedFileTransfersPublisher: AnyPublisher<[XXModels.FileTransfer], Error> + let sentFileTransfersPublisher: AnyPublisher<[XXModels.FileTransfer], Error> switch state.id { case .contact(let contactId): queryChat = .direct(myContactId, contactId) - receivedFileTransfersQuery = .init( + receivedFileTransfersPublisher = try db().fetchFileTransfersPublisher(.init( contactId: contactId, isIncoming: true - ) - sentFileTransfersQuery = .init( + )) + sentFileTransfersPublisher = try db().fetchFileTransfersPublisher(.init( contactId: myContactId, isIncoming: false - ) + )) + case .group(let groupId): + queryChat = .group(groupId) + receivedFileTransfersPublisher = Just([]) + .setFailureType(to: Error.self) + .eraseToAnyPublisher() + sentFileTransfersPublisher = Just([]) + .setFailureType(to: Error.self) + .eraseToAnyPublisher() } let messagesQuery = XXModels.Message.Query(chat: queryChat) return Publishers.CombineLatest3( try db().fetchMessagesPublisher(messagesQuery), - try db().fetchFileTransfersPublisher(receivedFileTransfersQuery), - try db().fetchFileTransfersPublisher(sentFileTransfersQuery) + receivedFileTransfersPublisher, + sentFileTransfersPublisher ) .map { messages, receivedFileTransfers, sentFileTransfers in (messages, receivedFileTransfers + sentFileTransfers) @@ -163,6 +172,9 @@ public struct ChatComponent: ReducerProtocol { subscriber.send(completion: .finished) } ) + case .group(let groupId): + // TODO: send group message + fatalError() } return AnyCancellable {} } @@ -175,21 +187,18 @@ public struct ChatComponent: ReducerProtocol { return .none case .imagePicked(let data): - let chatId = state.id + guard case .contact(let recipientId) = state.id else { return .none } return Effect.run { subscriber in - switch chatId { - case .contact(let recipientId): - sendImage( - data, - to: recipientId, - onError: { error in - subscriber.send(.sendFailed(error.localizedDescription)) - }, - completion: { - subscriber.send(completion: .finished) - } - ) - } + sendImage( + data, + to: recipientId, + onError: { error in + subscriber.send(.sendFailed(error.localizedDescription)) + }, + completion: { + subscriber.send(completion: .finished) + } + ) return AnyCancellable {} } .subscribe(on: bgQueue) diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift index c8f5952864c6f77f04ec42b53b5875a317ee37a4..4303416c8a1635c917efeb5f99ecde246899f5fc 100644 --- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift +++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift @@ -9,7 +9,7 @@ import XXModels @testable import ChatFeature final class ChatComponentTests: XCTestCase { - func testStart() { + func testStartDirectChat() { let contactId = "contact-id".data(using: .utf8)! let myContactId = "my-contact-id".data(using: .utf8)! @@ -139,6 +139,112 @@ final class ChatComponentTests: XCTestCase { fileTransfersPublisher.send(completion: .finished) } + func testStartGroupChat() { + let groupId = "group-id".data(using: .utf8)! + let myContactId = "my-contact-id".data(using: .utf8)! + let firstMemberId = "member-1-id".data(using: .utf8)! + let secondMemberId = "member-2-id".data(using: .utf8)! + + let store = TestStore( + initialState: ChatComponent.State(id: .group(groupId)), + reducer: ChatComponent() + ) + + var didFetchMessagesWithQuery: [XXModels.Message.Query] = [] + let messagesPublisher = PassthroughSubject<[XXModels.Message], Error>() + + store.dependencies.app.mainQueue = .immediate + store.dependencies.app.bgQueue = .immediate + store.dependencies.app.messenger.e2e.get = { + var e2e: E2E = .unimplemented + e2e.getContact.run = { + var contact: XXClient.Contact = .unimplemented(Data()) + contact.getIdFromContact.run = { _ in myContactId } + return contact + } + return e2e + } + store.dependencies.app.dbManager.getDB.run = { + var db: Database = .unimplemented + db.fetchMessagesPublisher.run = { query in + didFetchMessagesWithQuery.append(query) + return messagesPublisher.eraseToAnyPublisher() + } + return db + } + + store.send(.start) { + $0.myContactId = myContactId + } + + XCTAssertNoDifference(didFetchMessagesWithQuery, [ + .init(chat: .group(groupId)) + ]) + + messagesPublisher.send([ + .init( + id: 0, + senderId: myContactId, + recipientId: nil, + groupId: groupId, + date: Date(timeIntervalSince1970: 0), + status: .sent, + isUnread: false, + text: "Message 0" + ), + .init( + id: 1, + senderId: firstMemberId, + recipientId: nil, + groupId: groupId, + date: Date(timeIntervalSince1970: 1), + status: .received, + isUnread: false, + text: "Message 1" + ), + .init( + id: 2, + senderId: secondMemberId, + recipientId: nil, + groupId: groupId, + date: Date(timeIntervalSince1970: 2), + status: .received, + isUnread: false, + text: "Message 2" + ), + ]) + + let expectedMessages = IdentifiedArrayOf<ChatComponent.State.Message>(uniqueElements: [ + .init( + id: 0, + date: Date(timeIntervalSince1970: 0), + senderId: myContactId, + text: "Message 0", + status: .sent + ), + .init( + id: 1, + date: Date(timeIntervalSince1970: 1), + senderId: firstMemberId, + text: "Message 1", + status: .received + ), + .init( + id: 2, + date: Date(timeIntervalSince1970: 2), + senderId: secondMemberId, + text: "Message 2", + status: .received + ), + ]) + + store.receive(.didFetchMessages(expectedMessages)) { + $0.messages = expectedMessages + } + + messagesPublisher.send(completion: .finished) + } + func testStartFailure() { let store = TestStore( initialState: ChatComponent.State(id: .contact("contact-id".data(using: .utf8)!)), @@ -165,7 +271,7 @@ final class ChatComponentTests: XCTestCase { } } - func testSend() { + func testSendDirectMessage() { struct SendMessageParams: Equatable { var text: String var recipientId: Data