diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 067669301..18d20f15e 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -351,6 +351,7 @@ 845E2F9D283FCB1400C04D56 /* Theme.Survey.Checkbox.Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845E2F9C283FCB1400C04D56 /* Theme.Survey.Checkbox.Accessibility.swift */; }; 84602A742AE94DE50031E606 /* ProximityManager.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84602A732AE94DE50031E606 /* ProximityManager.Mock.swift */; }; 84602A772AEA5BEA0031E606 /* ProximityManager.Failing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84602A762AEA5BEA0031E606 /* ProximityManager.Failing.swift */; }; + 84602A792AEAB7CA0031E606 /* Survey.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84602A782AEAB7CA0031E606 /* Survey.Mock.swift */; }; 8464297A2A44937600943BD6 /* AlertViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846429792A44937600943BD6 /* AlertViewControllerTests.swift */; }; 8464297D2A459E7D00943BD6 /* UIViewController+Replaceble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8464297C2A459E7D00943BD6 /* UIViewController+Replaceble.swift */; }; 846429802A45A1F200943BD6 /* OfferPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8464297F2A45A1F200943BD6 /* OfferPresenter.swift */; }; @@ -1093,6 +1094,7 @@ 845E2F9C283FCB1400C04D56 /* Theme.Survey.Checkbox.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.Survey.Checkbox.Accessibility.swift; sourceTree = ""; }; 84602A732AE94DE50031E606 /* ProximityManager.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProximityManager.Mock.swift; sourceTree = ""; }; 84602A762AEA5BEA0031E606 /* ProximityManager.Failing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProximityManager.Failing.swift; sourceTree = ""; }; + 84602A782AEAB7CA0031E606 /* Survey.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Survey.Mock.swift; sourceTree = ""; }; 846429792A44937600943BD6 /* AlertViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewControllerTests.swift; sourceTree = ""; }; 8464297C2A459E7D00943BD6 /* UIViewController+Replaceble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Replaceble.swift"; sourceTree = ""; }; 8464297F2A45A1F200943BD6 /* OfferPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferPresenter.swift; sourceTree = ""; }; @@ -3180,6 +3182,7 @@ isa = PBXGroup; children = ( 84681A972A61853300DD7406 /* GvaOption.Mock.swift */, + 84602A782AEAB7CA0031E606 /* Survey.Mock.swift */, ); path = Mocks; sourceTree = ""; @@ -4940,6 +4943,7 @@ 846429832A45DA7500943BD6 /* AlertViewController+Mock.swift in Sources */, 846A5C4529F6BEFA0049B29F /* GliaTests+StartEngagement.swift in Sources */, 7512A57A27BF9FCD00319DF1 /* ChatViewModelTests.swift in Sources */, + 84602A792AEAB7CA0031E606 /* Survey.Mock.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index b6249ada2..31ce3b2f6 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -338,7 +338,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 7873b4d39..207d864a0 100644 --- a/GliaWidgets/Sources/Interactor/Interactor.swift +++ b/GliaWidgets/Sources/Interactor/Interactor.swift @@ -59,7 +59,6 @@ class Interactor { var currentEngagement: CoreSdkClient.Engagement? private var observers = [() -> (AnyObject?, EventHandler)]() - private var isEngagementEndedByVisitor = false var state: InteractorState = .none { didSet { @@ -159,8 +158,6 @@ extension Interactor { success: @escaping () -> Void, failure: @escaping (CoreSdkClient.SalemoveError) -> Void ) { - isEngagementEndedByVisitor = true - switch state { case .none: success() @@ -203,10 +200,11 @@ extension Interactor { success: @escaping () -> Void, failure: @escaping (CoreSdkClient.SalemoveError) -> Void ) { - environment.coreSdk.endEngagement { _, error in + environment.coreSdk.endEngagement { [weak self] _, error in if let error = error { failure(error) } else { + self?.state = .ended(.byVisitor) success() } } @@ -335,7 +333,16 @@ extension Interactor: CoreSdkClient.Interactable { func end(with reason: CoreSdkClient.EngagementEndingReason) { currentEngagement = environment.coreSdk.getCurrentEngagement() - state = isEngagementEndedByVisitor == true ? .ended(.byVisitor) : .ended(.byOperator) + switch reason { + case .visitorHungUp: + state = .ended(.byVisitor) + case .operatorHungUp: + state = .ended(.byOperator) + case .error: + state = .ended(.byError) + @unknown default: + state = .ended(.byError) + } } func fail(error: CoreSdkClient.SalemoveError) { diff --git a/GliaWidgetsTests/Sources/ChatViewModel/Mocks/Survey.Mock.swift b/GliaWidgetsTests/Sources/ChatViewModel/Mocks/Survey.Mock.swift new file mode 100644 index 000000000..2c73f171c --- /dev/null +++ b/GliaWidgetsTests/Sources/ChatViewModel/Mocks/Survey.Mock.swift @@ -0,0 +1,24 @@ +import Foundation +@testable import GliaWidgets + +extension CoreSdkClient.Survey { + static func mock( + id: String = "mock", + description: String = "mock", + name: String = "mock", + title: String = "mock", + type: String = "visitor", + siteId: String = "mock" + ) throws -> Self { + let data = try JSONSerialization.data(withJSONObject: [ + "id": id, + "description": description, + "name": name, + "title": title, + "type": type, + "siteId": siteId, + "questions": [] + ]) + return try JSONDecoder().decode(CoreSdkClient.Survey.self, from: data) + } +} diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests.swift b/GliaWidgetsTests/Sources/Glia/GliaTests.swift index 519fe5bc3..e4e3e83ef 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests.swift @@ -353,4 +353,34 @@ final class GliaTests: XCTestCase { XCTAssertNil(sdk.rootCoordinator) XCTAssertNil(rootCoordinator) } + + 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() } + gliaEnv.coreSDKConfigurator.configureWithConfiguration = { _, callback in + callback?() + } + gliaEnv.coreSDKConfigurator.configureWithInteractor = { _ in } + let sdk = Glia(environment: gliaEnv) + try sdk.configure(with: .mock()) {} + sdk.callVisualizer.delegate?(.visitorCodeIsRequested) + 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]) + } } diff --git a/GliaWidgetsTests/Sources/InteractorTests.swift b/GliaWidgetsTests/Sources/InteractorTests.swift index 78f3d0510..c91c880e2 100644 --- a/GliaWidgetsTests/Sources/InteractorTests.swift +++ b/GliaWidgetsTests/Sources/InteractorTests.swift @@ -447,4 +447,34 @@ class InteractorTests: XCTestCase { XCTAssertEqual(callbacks, [.mediaUpgradeOffered]) } + + func test_endEngagementSetsStateToEndedByVisitor() { + var interactorEnv = Interactor.Environment.failing + interactorEnv.coreSdk.endEngagement = { completion in completion(true, nil) } + let interactor = Interactor.mock(environment: interactorEnv) + interactor.state = .engaged(.mock()) + + interactor.endSession(success: {}, failure: { _ in }) + + XCTAssertEqual(interactor.state, .ended(.byVisitor)) + } + + func test_endWithReasonSetsProperState() { + let interactor = Interactor.failing + interactor.state = .engaged(.mock()) + typealias Item = (reason: CoreSdkClient.EngagementEndingReason, state: InteractorState) + + let items: [Item] = [ + (.visitorHungUp, .ended(.byVisitor)), + (.operatorHungUp, .ended(.byOperator)), + (.error, .ended(.byError)) + ] + + let test: (Item) -> Void = { item in + interactor.end(with: item.reason) + XCTAssertEqual(interactor.state, item.state) + } + + items.forEach(test) + } }