From dd53d9f1112b3d5c9f3e2e527edae62f23b8e499 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Wed, 14 Sep 2022 14:39:15 +0200
Subject: [PATCH] Handle send errors in ChatFeature

---
 .../Sources/ChatFeature/ChatFeature.swift     | 16 +++++++-
 .../ChatFeatureTests/ChatFeatureTests.swift   | 38 +++++++++++++++++++
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift
index 6119a237..46cfdbfa 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatFeature.swift
@@ -39,12 +39,14 @@ public struct ChatState: Equatable, Identifiable {
     myContactId: Data? = nil,
     messages: IdentifiedArrayOf<Message> = [],
     failure: String? = nil,
+    sendFailure: String? = nil,
     text: String = ""
   ) {
     self.id = id
     self.myContactId = myContactId
     self.messages = messages
     self.failure = failure
+    self.sendFailure = sendFailure
     self.text = text
   }
 
@@ -52,6 +54,7 @@ public struct ChatState: Equatable, Identifiable {
   public var myContactId: Data?
   public var messages: IdentifiedArrayOf<Message>
   public var failure: String?
+  public var sendFailure: String?
   @BindableState public var text: String
 }
 
@@ -59,6 +62,8 @@ public enum ChatAction: Equatable, BindableAction {
   case start
   case didFetchMessages(IdentifiedArrayOf<ChatState.Message>)
   case sendTapped
+  case sendFailed(String)
+  case dismissSendFailureTapped
   case binding(BindingAction<ChatState>)
 }
 
@@ -152,8 +157,7 @@ public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment>
           text: text,
           to: recipientId,
           onError: { error in
-            // TODO: handle error
-            print("^^^ ERROR: \(error)")
+            subscriber.send(.sendFailed(error.localizedDescription))
           },
           completion: {
             subscriber.send(completion: .finished)
@@ -166,6 +170,14 @@ public let chatReducer = Reducer<ChatState, ChatAction, ChatEnvironment>
     .receive(on: env.mainQueue)
     .eraseToEffect()
 
+  case .sendFailed(let failure):
+    state.sendFailure = failure
+    return .none
+
+  case .dismissSendFailureTapped:
+    state.sendFailure = nil
+    return .none
+
   case .binding(_):
     return .none
   }
diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift
index f8065742..1a513af0 100644
--- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatFeatureTests.swift
@@ -169,4 +169,42 @@ final class ChatFeatureTests: XCTestCase {
 
     sendMessageCompletion?()
   }
+
+  func testSendFailure() {
+    var sendMessageOnError: SendMessage.OnError?
+    var sendMessageCompletion: SendMessage.Completion?
+
+    let store = TestStore(
+      initialState: ChatState(
+        id: .contact("contact-id".data(using: .utf8)!),
+        text: "Hello"
+      ),
+      reducer: chatReducer,
+      environment: .unimplemented
+    )
+
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.sendMessage.run = { _, _, onError, completion in
+      sendMessageOnError = onError
+      sendMessageCompletion = completion
+    }
+
+    store.send(.sendTapped) {
+      $0.text = ""
+    }
+
+    let error = NSError(domain: "test", code: 123)
+    sendMessageOnError?(error)
+
+    store.receive(.sendFailed(error.localizedDescription)) {
+      $0.sendFailure = error.localizedDescription
+    }
+
+    sendMessageCompletion?()
+
+    store.send(.dismissSendFailureTapped) {
+      $0.sendFailure = nil
+    }
+  }
 }
-- 
GitLab