diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index 538370f33..f19f8788a 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -332,7 +332,7 @@ extension Glia { case let .videoStreamAdded(stream): self?.callVisualizer.addVideoStream(stream: stream) case let .stateChanged(state): - if state == .ended(.byOperator) { + if case .ended = state { self?.callVisualizer.endSession() self?.onEvent?(.ended) } else if case .engaged = state { diff --git a/GliaWidgets/Sources/Interactor/Interactor.swift b/GliaWidgets/Sources/Interactor/Interactor.swift index 95ab3e77e..f46abd5cc 100644 --- a/GliaWidgets/Sources/Interactor/Interactor.swift +++ b/GliaWidgets/Sources/Interactor/Interactor.swift @@ -62,7 +62,7 @@ class Interactor { var isConfigurationPerformed: Bool = false private var observers = [() -> (AnyObject?, EventHandler)]() - private var isEngagementEndedByVisitor = false + private(set) var isEngagementEndedByVisitor = false var state: InteractorState = .none { didSet { diff --git a/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift b/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift index 26e843a84..b428f9a5a 100644 --- a/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift @@ -80,7 +80,8 @@ class EngagementViewModel: CommonEngagementModel { self.alertConfiguration.operatorEndedEngagement, accessibilityIdentifier: Self.alertSingleActionAccessibilityIdentifier, actionTapped: { [weak self] in - self?.endSession() + self?.screenShareHandler.stop(nil) + self?.engagementDelegate?(.finished) } ) ) @@ -144,7 +145,8 @@ class EngagementViewModel: CommonEngagementModel { guard let self = self else { return } guard case .success(let survey) = result, survey == nil else { - self.endSession() + self.screenShareHandler.stop(nil) + self.engagementDelegate?(.finished) return } @@ -153,7 +155,8 @@ class EngagementViewModel: CommonEngagementModel { self.alertConfiguration.operatorEndedEngagement, accessibilityIdentifier: Self.alertSingleActionAccessibilityIdentifier, actionTapped: { [weak self] in - self?.endSession() + self?.screenShareHandler.stop(nil) + self?.engagementDelegate?(.finished) self?.engagementDelegate?( .engaged( operatorImageUrl: nil diff --git a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift index 64593b0a2..f331b730f 100644 --- a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift +++ b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift @@ -726,6 +726,90 @@ class ChatViewModelTests: XCTestCase { XCTAssertEqual(viewModel.messagesSection.items.count, 0) XCTAssertEqual(viewModel.receivedMessageIds, []) } + + func test_viewModelDoesNotCallEndSessionWhenEngagementIsEndedByOperatorAndSurveyExists() throws { + enum Call { case finished } + var calls: [Call] = [] + var interactorEnv = Interactor.Environment.mock + let data = try JSONSerialization.data(withJSONObject: [ + "id": "mock", + "description": "mock", + "name": "mock", + "title": "mock", + "type": "visitor", + "siteId": "mock", + "questions": [] + ]) + let survey = try JSONDecoder().decode(CoreSdkClient.Survey.self, from: data) + let engagement: CoreSdkClient.Engagement = .mock { _, callback in + callback(.success(survey)) + } + let interactor: Interactor = .mock(environment: interactorEnv) + interactor.state = .engaged(.mock()) + interactor.currentEngagement = engagement + let screenShareHandler: ScreenShareHandler = .mock + screenShareHandler.status().value = .started + let viewModel: ChatViewModel = .mock( + interactor: interactor, + screenShareHandler: screenShareHandler + ) + viewModel.engagementDelegate = { event in + switch event { + case .finished: + calls.append(.finished) + default: + XCTFail("There is should not be other events") + } + } + + interactor.state = .ended(.byOperator) + + XCTAssertEqual(screenShareHandler.status().value, .stopped) + XCTAssertEqual(calls, [.finished]) + XCTAssertFalse(interactor.isEngagementEndedByVisitor) + } + + func test_viewModelDoesNotCallEndSessionWhenEngagementIsEndedByOperatorAndThereIsNoSurvey() throws { + enum Call: Equatable { case finished, engaged(String?) } + var calls: [Call] = [] + var interactorEnv = Interactor.Environment.mock + let engagement: CoreSdkClient.Engagement = .mock { _, callback in callback(.success(nil)) } + let interactor: Interactor = .mock(environment: interactorEnv) + interactor.state = .engaged(.mock()) + interactor.currentEngagement = engagement + let screenShareHandler: ScreenShareHandler = .mock + screenShareHandler.status().value = .started + let viewModel: ChatViewModel = .mock( + interactor: interactor, + screenShareHandler: screenShareHandler + ) + viewModel.engagementDelegate = { event in + switch event { + case .finished: + calls.append(.finished) + case let .engaged(operatorImage): + // This is called after ending engagement to reset bubble avatar + calls.append(.engaged(operatorImage)) + case .back: + XCTFail("There is should be `back` event") + } + } + + viewModel.engagementAction = { action in + switch action { + case let .showSingleActionAlert(_, _, actionTapped): + actionTapped?() + default: + XCTFail("There is should be no another action") + } + } + + interactor.state = .ended(.byOperator) + + XCTAssertEqual(screenShareHandler.status().value, .stopped) + XCTAssertEqual(calls, [.finished, .engaged(nil)]) + XCTAssertFalse(interactor.isEngagementEndedByVisitor) + } } extension ChatChoiceCardOption { diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests.swift b/GliaWidgetsTests/Sources/Glia/GliaTests.swift index 46dcde9ca..f887cd5bd 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests.swift @@ -283,4 +283,30 @@ final class GliaTests: XCTestCase { XCTAssertEqual(delegate.invokedEventCallParameter, .maximized) XCTAssertEqual(delegate.invokedEventCallParameterList, [.maximized]) } + + func test_screenSharingIsStoppedWhenCallVisualizerEngagementIsEnded() throws { + enum Call { case ended } + var calls: [Call] = [] + var gliaEnv = Glia.Environment.failing + let screenShareHandler: ScreenShareHandler = .mock + screenShareHandler.status().value = .started + gliaEnv.screenShareHandler = screenShareHandler + gliaEnv.gcd.mainQueue.asyncIfNeeded = { callback in callback() } + let sdk = Glia(environment: gliaEnv) + try sdk.configure(with: .mock()) + + sdk.environment.coreSdk.getCurrentEngagement = { .mock(source: .callVisualizer) } + sdk.onEvent = { event in + switch event { + case .ended: + calls.append(.ended) + default: + XCTFail("There is should be no another event") + } + } + sdk.interactor?.state = .ended(.byVisitor) + + XCTAssertEqual(screenShareHandler.status().value, .stopped) + XCTAssertEqual(calls, [.ended]) + } }