diff --git a/Example/Kommunicate.xcodeproj/project.pbxproj b/Example/Kommunicate.xcodeproj/project.pbxproj index 39694bcf..2dae9183 100644 --- a/Example/Kommunicate.xcodeproj/project.pbxproj +++ b/Example/Kommunicate.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 778B59CFD2A9AA01B2C8BB47 /* Pods_Kommunicate_ExampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C12430200CB714F7C6EC6DE /* Pods_Kommunicate_ExampleUITests.framework */; }; 8213687C2CDA2CEE00B09F37 /* KommunicateConfigurationTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8213687B2CDA2CEE00B09F37 /* KommunicateConfigurationTesting.swift */; }; 8213687E2CDA332100B09F37 /* KommunicateLoginAndWelcomeMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8213687D2CDA332100B09F37 /* KommunicateLoginAndWelcomeMessage.swift */; }; + 8237AC4C2D4A5DF8008BC1AC /* KommunicateResolveAndAssignmentUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8237AC4B2D4A5DF8008BC1AC /* KommunicateResolveAndAssignmentUITests.swift */; }; 8B33037F2226A494003BF306 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33037E2226A494003BF306 /* LoginViewController.swift */; }; 8B5BC12A22002FDC00F39956 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8B5BC12822002FDC00F39956 /* Localizable.strings */; }; 8B8FFA9421D5171F00C8ED57 /* PaymentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B8FFA9321D5171F00C8ED57 /* PaymentTests.swift */; }; @@ -67,6 +68,7 @@ 78226602544E9745BB6CB084 /* Pods_Kommunicate_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Kommunicate_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8213687B2CDA2CEE00B09F37 /* KommunicateConfigurationTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KommunicateConfigurationTesting.swift; sourceTree = ""; }; 8213687D2CDA332100B09F37 /* KommunicateLoginAndWelcomeMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KommunicateLoginAndWelcomeMessage.swift; sourceTree = ""; }; + 8237AC4B2D4A5DF8008BC1AC /* KommunicateResolveAndAssignmentUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KommunicateResolveAndAssignmentUITests.swift; sourceTree = ""; }; 8AFCF2C4706B87B553819E20 /* Pods-Kommunicate_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Kommunicate_Tests.debug.xcconfig"; path = "Target Support Files/Pods-Kommunicate_Tests/Pods-Kommunicate_Tests.debug.xcconfig"; sourceTree = ""; }; 8B33037E2226A494003BF306 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; 8B5BC12422002C4000F39956 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -242,6 +244,7 @@ isa = PBXGroup; children = ( 8213687B2CDA2CEE00B09F37 /* KommunicateConfigurationTesting.swift */, + 8237AC4B2D4A5DF8008BC1AC /* KommunicateResolveAndAssignmentUITests.swift */, C698B48F24AB76A5008BB4D9 /* KommunicateCreateConversationAndSendMessagesTests.swift */, C698B48E24AB76A5008BB4D9 /* TestCaseInfo.swift */, C698B49D24AB77D5008BB4D9 /* Info.plist */, @@ -588,6 +591,7 @@ buildActionMask = 2147483647; files = ( C698B4A424AB7803008BB4D9 /* KommunicateCreateConversationAndSendMessagesTests.swift in Sources */, + 8237AC4C2D4A5DF8008BC1AC /* KommunicateResolveAndAssignmentUITests.swift in Sources */, C67D56E824AE439A001BA419 /* KommunicateLoginAsVisitorUITests.swift in Sources */, C698B4A324AB7803008BB4D9 /* TestCaseInfo.swift in Sources */, 8213687E2CDA332100B09F37 /* KommunicateLoginAndWelcomeMessage.swift in Sources */, diff --git a/Example/Kommunicate_ExampleUITests/KommunicateResolveAndAssignmentUITests.swift b/Example/Kommunicate_ExampleUITests/KommunicateResolveAndAssignmentUITests.swift new file mode 100644 index 00000000..ee970396 --- /dev/null +++ b/Example/Kommunicate_ExampleUITests/KommunicateResolveAndAssignmentUITests.swift @@ -0,0 +1,184 @@ +// +// KommunicateResolveAndAssignmentUITests.swift +// Kommunicate_ExampleUITests +// +// Created by Abhijeet Ranjan on 29/01/25. +// Copyright © 2025 CocoaPods. All rights reserved. +// + +import XCTest + +class KommunicateResolveAndAssignmentUITests: XCTestCase { + enum GroupData { + static let typeText = "close" + static let typeVerifyingText = "Restarted" + static let typeAssignmentText = "Assign to Human" + static let typeAfterAssignmentText = "I have some issue." + static let AppId = loginCreadentials.testAppID + } + + override func setUp() { + super.setUp() + continueAfterFailure = false + sleep(10) + addUIInterruptionMonitor(withDescription: AppPermission.AlertMessage.accessNotificationInApplication) { alerts -> Bool in + if alerts.buttons[AppPermission.AlertButton.allow].exists { + alerts.buttons[AppPermission.AlertButton.allow].tap() + } + return true + } + let app = XCUIApplication() + if let appId = appIdFromEnvVars() { + app.launchArguments = [GroupData.AppId, appId] + } + app.launch() + sleep(5) + guard !XCUIApplication().scrollViews.otherElements.buttons[InAppButton.LaunchScreen.getStarted].exists else { + return + } + } + + func testRestartConversation () { + let app = beforeTest_Launch_NewConversation() + sleep(3) + waitFor(object: app) { $0.exists } + app.typeText(GroupData.typeText) // typing message + app.buttons[InAppButton.ConversationScreen.send].tap() // sending message in group + sleep(3) /// To wait for response + app.swipeUp() /// To get to bottom of the screen. + sleep(2) + let resolveConversationSuggestedButtonResponse = app.tables[AppScreen.innerChatScreenTableView] + .textViews[RichMessageResponseText.resolveConversationSuggestedButtonMessage] + waitFor(object: resolveConversationSuggestedButtonResponse) { $0.exists } + let buttons = app.tables[AppScreen.innerChatScreenTableView].staticTexts.matching(identifier: RichMessageButtons.resolveButton) + + // Ensure there's at least one element + guard buttons.count > 0 else { + XCTFail("No buttons found in Suggested Replies Template") + return + } + + // Use element(boundBy:) to select a specific button, e.g., the first one + let specificButton = buttons.element(boundBy: 0) // Change index as needed + + guard specificButton.isEnabled else { + XCTFail("Button in Suggested Replies Template is disabled or not visible") + return + } + specificButton.tap() + let resolveConversationButtonResponse = app.tables[AppScreen.innerChatScreenTableView] + .textViews[RichMessageResponseText.resolveConversationButtonResponseMessage] + waitFor(object: resolveConversationButtonResponse) { $0.exists } + + sleep(5) + app.buttons[InAppButton.ConversationScreen.restartConversation].tap() + + let inputView = app.otherElements[AppScreen.chatBar].children(matching: .textView).matching(identifier: AppTextFeild.chatTextView).firstMatch + waitFor(object: inputView) { $0.exists } + inputView.tap() + inputView.tap() + inputView.tap() + + app.typeText(GroupData.typeVerifyingText) // typing restart message for verifying + app.buttons[InAppButton.ConversationScreen.send].tap() // sending message in group + sleep(3) /// To wait for response + app.swipeUp() /// To get to bottom of the screen. + sleep(2) + let restartConversationResponse = app.tables[AppScreen.innerChatScreenTableView] + .textViews[RichMessageResponseText.restartConversationResponse] + waitFor(object: restartConversationResponse) { $0.exists } + } + + func testAssingment_awayMessage_emailCollection() { + let app = beforeTest_Launch_NewConversation() + sleep(3) + let inputView = app.otherElements[AppScreen.chatBar].children(matching: .textView).matching(identifier: AppTextFeild.chatTextView).firstMatch + waitFor(object: inputView) { $0.exists } + inputView.tap() + inputView.tap() + inputView.tap() + waitFor(object: app) { $0.exists } + app.typeText(GroupData.typeAssignmentText) // typing message + app.buttons[InAppButton.ConversationScreen.send].tap() // sending message in group + sleep(3) /// To wait for response + app.swipeUp() /// To get to bottom of the screen. + sleep(2) + + let assignmentMessageResponse = app.tables[AppScreen.innerChatScreenTableView] + .textViews[RichMessageResponseText.assignementMessageResponse] + waitFor(object: assignmentMessageResponse) { $0.exists } + + sleep(4) + + let awayMessageView = app.otherElements[AppScreen.awayMessageView].children(matching: .staticText).matching(identifier: AppTextFeild.awayMessageLabel).firstMatch + waitFor(object: awayMessageView) { $0.exists } + + inputView.tap() + inputView.tap() + inputView.tap() + + app.typeText(GroupData.typeAfterAssignmentText) // typing message + app.buttons[InAppButton.ConversationScreen.send].tap() // sending message in group + + sleep(3) + + let emailMessageView = app.otherElements[AppScreen.awayMessageView].children(matching: .staticText).matching(identifier: AppTextFeild.emailMessageLabel).firstMatch + waitFor(object: emailMessageView) { $0.exists } + + inputView.tap() + inputView.tap() + inputView.tap() + + app.typeText(CustomInputFieldReply.emailFieldResponse) // typing email + app.buttons[InAppButton.ConversationScreen.send].tap() // sending message in group + + sleep(5) + + waitFor(object: awayMessageView) { $0.exists } + } + + private func beforeTest_Launch_NewConversation() -> (XCUIApplication) { + let app = XCUIApplication() + if app.buttons[InAppButton.LaunchScreen.logoutButton].exists { + app.buttons[InAppButton.LaunchScreen.logoutButton].tap() + let loginAsVisitorButton = app.buttons[InAppButton.LaunchScreen.loginAsVisitor] + waitFor(object: loginAsVisitorButton) { $0.exists } + loginAsVisitorButton.tap() + } + let launchConversationButton = app.buttons[InAppButton.EditGroup.launch] + waitFor(object: launchConversationButton) { $0.exists } + launchConversationButton.tap() + sleep(3) + // Check if the specific screen is on top + let isScreenOnTop = app.navigationBars[AppScreen.myChatScreen].exists + + if isScreenOnTop { + // Perform actions only if the screen is not on top + let createConversationButton = app.navigationBars[AppScreen.myChatScreen] + waitFor(object: createConversationButton) { $0.exists } + createConversationButton.buttons[InAppButton.CreatingGroup.startNewIcon].tap() + + let inputView = app.otherElements[AppScreen.chatBar].children(matching: .textView).matching(identifier: AppTextFeild.chatTextView).firstMatch + waitFor(object: inputView) { $0.exists } + inputView.tap() + inputView.tap() + inputView.tap() + } else { + + let inputView = app.otherElements[AppScreen.chatBar].children(matching: .textView).matching(identifier: AppTextFeild.chatTextView).firstMatch + waitFor(object: inputView) { $0.exists } + inputView.tap() + inputView.tap() + inputView.tap() + } + + return app + } + + private func appIdFromEnvVars() -> String? { + let path = Bundle(for: KommunicateCreateConversationAndSendMessagesTests.self).url(forResource: "Info", withExtension: "plist") + let appId = GroupData.AppId + return appId + } +} + diff --git a/Example/Kommunicate_ExampleUITests/TestCaseInfo.swift b/Example/Kommunicate_ExampleUITests/TestCaseInfo.swift index 5b964cc7..587a945a 100644 --- a/Example/Kommunicate_ExampleUITests/TestCaseInfo.swift +++ b/Example/Kommunicate_ExampleUITests/TestCaseInfo.swift @@ -99,12 +99,14 @@ enum InAppButton { static let faqButton = "FAQ" static let loadingIndicator = "loadingIndicator" static let activityIndicator = "activityIndicator" + static let restartConversation = "Restart conversation" } } enum AppScreen { static let myChatScreen = "My Chats" static let chatBar = "chatBar" + static let awayMessageView = "awayMessageView" static let innerChatScreenTableView = "InnerChatScreenTableView" static let inneritemListView = "InneritemListView" static let kMConversationView = "Kommunicate.KMConversationView" @@ -117,6 +119,8 @@ enum AppTextFeild { static let userId = "User id (Use a random id for the first time login)" static let password = "Password" static let chatTextView = "chatTextView" + static let awayMessageLabel = "awayMessageLabel" + static let emailMessageLabel = "emailMessageLabel" static let HeadlineText = "Hi, how can we help you?" static let Helpcenter = "Helpcenter | Helpcenter" } @@ -140,6 +144,7 @@ enum FormIdentifier { enum RichMessageButtons { static let button = "Button" + static let resolveButton = "Resolve Conversation" static let goToGoogle = "Go To Google" static let pay = "Pay" static let male = "Male" @@ -174,6 +179,11 @@ enum RichMessageResponseText { static let submitFirstResponse = "Submit Button Rich Message" static let sugggestedRepliesFirstMessage = "Suggested Replies Rich Message" static let formFirstResponse = "Input your details" + static let resolveConversationSuggestedButtonMessage = "Are you sure you want to close the conversation." + static let resolveConversationButtonResponseMessage = "We are resolving this conversation. Please reach out to us in case of any more queries." + static let restartConversationResponse = "The conversation restarted successfully." + static let assignementMessageResponse = "Now this conversation is Assigned to Human." + static let awayMessageResponse = "The agent is currently unavailable. Please wait for sometime the agent will connect with you." } struct AutoSuggestionReply { diff --git a/Sources/Kommunicate/Classes/KMConversationViewController.swift b/Sources/Kommunicate/Classes/KMConversationViewController.swift index 8c5cb021..c882e810 100644 --- a/Sources/Kommunicate/Classes/KMConversationViewController.swift +++ b/Sources/Kommunicate/Classes/KMConversationViewController.swift @@ -164,6 +164,7 @@ open class KMConversationViewController: ALKConversationViewController, KMUpdate override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + awayMessageView.accessibilityIdentifier = "awayMessageView" awayMessageView.drawDottedLines() charLimitView.drawDottedLines() } @@ -613,13 +614,13 @@ open class KMConversationViewController: ALKConversationViewController, KMUpdate if let channelId = weakSelf.viewModel.channelKey { KMCustomEventHandler.shared.publish(triggeredEvent: KMCustomEvent.restartConversationClick, data: ["conversationId":channelId]) } + guard let zendeskAccountKey = ALApplozicSettings.getZendeskSdkAccountKey(), + !zendeskAccountKey.isEmpty else { return } #if canImport(ChatProvidersSDK) - guard let zendeskAcckountKey = ALApplozicSettings.getZendeskSdkAccountKey(), - !zendeskAcckountKey.isEmpty else { return } // if zendesk is integrated, create a new conversation instead of restarting the conversation let zendeskHandler = KMZendeskChatHandler.shared zendeskHandler.resetConfiguration() - zendeskHandler.initiateZendesk(key: zendeskAcckountKey) + zendeskHandler.initiateZendesk(key: zendeskAccountKey) #endif weakSelf.loadingStarted() // Create a new conversation diff --git a/Sources/Kommunicate/Classes/Views/AwayMessageView.swift b/Sources/Kommunicate/Classes/Views/AwayMessageView.swift index 6631afa8..b1afd8ab 100644 --- a/Sources/Kommunicate/Classes/Views/AwayMessageView.swift +++ b/Sources/Kommunicate/Classes/Views/AwayMessageView.swift @@ -47,6 +47,7 @@ class AwayMessageView: UIView , Localizable { label.textAlignment = .center label.textColor = .kmDynamicColor(light: UIColor(netHex: 0x676262), dark: .lightGray) label.numberOfLines = 4 + label.accessibilityIdentifier = "awayMessageLabel" return label }() @@ -65,6 +66,7 @@ class AwayMessageView: UIView , Localizable { completeText.append(NSAttributedString(string: " " + LocalizedText.CollectEmailMessageOnAwayMode)) label.attributedText = completeText label.textColor = .kmDynamicColor(light: UIColor(netHex: 0x676262), dark: .lightGray) + label.accessibilityIdentifier = "emailMessageLabel" return label }()