From aa139c4bc597a5b3d74a146dfa63b55a0c32d00d Mon Sep 17 00:00:00 2001 From: Igor Kravchenko Date: Thu, 12 Oct 2023 17:53:26 +0300 Subject: [PATCH] Fix hiding of text input for Secure Transcript flow Fix hiding of text input for Secure Transcript flow when Secure Message Center is unavailable. MOB-2734 --- .../SecureConversations.TranscriptModel.swift | 16 ++- .../Chat/ChatViewController.swift | 2 + .../Chat/ChatViewModel+ViewModel.swift | 5 + .../ChatTranscript/TranscriptModelTests.swift | 131 +++++++++++++++++- 4 files changed, 148 insertions(+), 6 deletions(-) diff --git a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift index cae493e8e..4f4970037 100644 --- a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift +++ b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift @@ -59,7 +59,11 @@ extension SecureConversations { var availability: Availability var interactor: Interactor - private (set) var isSecureConversationsAvailable: Bool = true + private (set) var isSecureConversationsAvailable: Bool = true { + didSet { + action?(.transcript(.messageCenterAvailabilityUpdated)) + } + } var siteConfiguration: CoreSdkClient.Site? @@ -175,6 +179,7 @@ extension SecureConversations { let configuration = self.environment.alertConfiguration.unavailableMessageCenter self.reportMessageCenterUnavailable(configuration: configuration) case .success(.unavailable(.unauthenticated)): + self.isSecureConversationsAvailable = false let configuration = self.environment.alertConfiguration.unavailableMessageCenterForBeingUnauthenticated self.reportMessageCenterUnavailable(configuration: configuration) } @@ -746,3 +751,12 @@ extension SecureConversations.TranscriptModel { } } + +#if DEBUG +extension SecureConversations.TranscriptModel { + /// Setter for `isSecureConversationsAvailable`. Used in unit tests. + func setIsSecureConversationsAvailable(_ available: Bool) { + self.isSecureConversationsAvailable = available + } +} +#endif diff --git a/GliaWidgets/Sources/ViewController/Chat/ChatViewController.swift b/GliaWidgets/Sources/ViewController/Chat/ChatViewController.swift index b70a25503..488ac4eb8 100644 --- a/GliaWidgets/Sources/ViewController/Chat/ChatViewController.swift +++ b/GliaWidgets/Sources/ViewController/Chat/ChatViewController.swift @@ -168,6 +168,8 @@ final class ChatViewController: EngagementViewController, PopoverPresenter { view?.messageEntryView.uploadListView.props = fileUploadListProps case let .quickReplyPropsUpdated(props): view?.renderQuickReply(props: props) + case .transcript(.messageCenterAvailabilityUpdated): + break } self?.renderProps() } diff --git a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ViewModel.swift b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ViewModel.swift index 90e7493d8..d691fe4f6 100644 --- a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ViewModel.swift @@ -23,6 +23,10 @@ extension ChatViewModel: ViewModel { } enum Action { + /// Actions specific for `TranscriptModel`. + enum TranscriptAction { + case messageCenterAvailabilityUpdated + } case queue case connected(name: String?, imageUrl: String?) case transferring @@ -55,6 +59,7 @@ extension ChatViewModel: ViewModel { case setAttachmentButtonVisibility(MediaPickerButtonVisibility) case fileUploadListPropsUpdated(SecureConversations.FileUploadListView.Props) case quickReplyPropsUpdated(QuickReplyView.Props) + case transcript(TranscriptAction) } enum DelegateEvent { diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift index 67c11a36a..74ad9ad53 100644 --- a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift @@ -284,7 +284,6 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { XCTAssertTrue(viewModel.validateMessage()) } - func testSendMessageUsesSecureEndpoint() { var modelEnv = TranscriptModel.Environment.failing let fileUploadListModel = FileUploadListViewModel.mock() @@ -379,7 +378,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { callback(.success(1)) } modelEnv.startSocketObservation = {} - modelEnv.gcd.mainQueue.asyncAfterDeadline = { _, callback in } + modelEnv.gcd.mainQueue.asyncAfterDeadline = { _, _ in } modelEnv.loadChatMessagesFromHistory = { true } let scheduler = CoreSdkClient.ReactiveSwift.TestScheduler() modelEnv.messagesWithUnreadCountLoaderScheduler = scheduler @@ -451,7 +450,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { alertConfiguration: .mock() ) - modelEnv.fetchChatHistory = { callback in + modelEnv.fetchChatHistory = { _ in let uuid = UUID.mock.uuidString let message = CoreSdkClient.Message( id: uuid, @@ -491,7 +490,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { callback(.success(0)) } modelEnv.startSocketObservation = {} - modelEnv.gcd.mainQueue.asyncAfterDeadline = { _, callback in } + modelEnv.gcd.mainQueue.asyncAfterDeadline = { _, _ in } modelEnv.loadChatMessagesFromHistory = { true } let scheduler = CoreSdkClient.ReactiveSwift.TestScheduler() modelEnv.messagesWithUnreadCountLoaderScheduler = scheduler @@ -515,7 +514,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { alertConfiguration: .mock() ) - modelEnv.fetchChatHistory = { callback in + modelEnv.fetchChatHistory = { _ in let uuid = UUID.mock.uuidString let message = CoreSdkClient.Message( id: uuid, @@ -541,4 +540,126 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { viewModel.start() scheduler.run() } + + func testIsSecureConversationsAvailableIsFalseIsDueToEmptyQueue() { + var modelEnvironment = TranscriptModel.Environment.failing + modelEnvironment.fileManager = .mock + modelEnvironment.createFileUploadListModel = { + .mock(environment: $0) + } + var availabilityEnv = SecureConversations.Availability.Environment.failing + availabilityEnv.listQueues = { callback in + callback([], nil) + } + availabilityEnv.isAuthenticated = { true } + let model = TranscriptModel( + isCustomCardSupported: false, + environment: modelEnvironment, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + interactor: .failing, + alertConfiguration: .mock() + ) + XCTAssertFalse(model.isSecureConversationsAvailable) + } + + func testIsSecureConversationsAvailableIsFalseDueToUnauthenticated() { + var modelEnvironment = TranscriptModel.Environment.failing + modelEnvironment.fileManager = .mock + modelEnvironment.createFileUploadListModel = { + .mock(environment: $0) + } + var availabilityEnv = SecureConversations.Availability.Environment.failing + availabilityEnv.listQueues = { callback in + callback([.mock()], nil) + } + availabilityEnv.isAuthenticated = { false } + let model = TranscriptModel( + isCustomCardSupported: false, + environment: modelEnvironment, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + interactor: .failing, + alertConfiguration: .mock() + ) + XCTAssertFalse(model.isSecureConversationsAvailable) + } + + func testIsSecureConversationsAvailableIsFalseDueToListQueuesError() { + var modelEnvironment = TranscriptModel.Environment.failing + modelEnvironment.fileManager = .mock + modelEnvironment.createFileUploadListModel = { + .mock(environment: $0) + } + var availabilityEnv = SecureConversations.Availability.Environment.failing + availabilityEnv.listQueues = { callback in + callback(nil, .mock()) + } + availabilityEnv.isAuthenticated = { false } + let model = TranscriptModel( + isCustomCardSupported: false, + environment: modelEnvironment, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + interactor: .failing, + alertConfiguration: .mock() + ) + XCTAssertFalse(model.isSecureConversationsAvailable) + } + + func testIsSecureConversationsAvailableIsTrue() { + var modelEnvironment = TranscriptModel.Environment.failing + modelEnvironment.fileManager = .mock + modelEnvironment.createFileUploadListModel = { + .mock(environment: $0) + } + var availabilityEnv = SecureConversations.Availability.Environment.failing + availabilityEnv.listQueues = { callback in + callback([.mock()], nil) + } + availabilityEnv.isAuthenticated = { true } + let model = TranscriptModel( + isCustomCardSupported: false, + environment: modelEnvironment, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + interactor: .failing, + alertConfiguration: .mock() + ) + XCTAssertFalse(model.isSecureConversationsAvailable) + } + + func testSetIsSecureConversationsAvailableCallsAction() throws { + var modelEnvironment = TranscriptModel.Environment.failing + modelEnvironment.fileManager = .mock + modelEnvironment.createFileUploadListModel = { + .mock(environment: $0) + } + var availabilityEnv = SecureConversations.Availability.Environment.failing + availabilityEnv.listQueues = { callback in + callback([.mock()], nil) + } + availabilityEnv.isAuthenticated = { true } + let model = TranscriptModel( + isCustomCardSupported: false, + environment: modelEnvironment, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + interactor: .failing, + alertConfiguration: .mock() + ) + var actions: [TranscriptModel.Action] = [] + model.action = { + actions.append($0) + } + model.setIsSecureConversationsAvailable(true) + XCTAssertEqual(actions.count, 1) + let receivedAction = try XCTUnwrap(actions.first) + switch receivedAction { + case .transcript(.messageCenterAvailabilityUpdated): + break + default: + XCTFail("Unexpected action: \(receivedAction)") + } + } }