diff --git a/CHANGELOG.md b/CHANGELOG.md index 3154234a..1bf6842c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,26 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Load AMS based on config. + +### Fixed + +- Fix for methods receiving exceptionDetails , but not logging it in telemetry +- Fix to prevent double load of AMS +- Fix to prevent startchat to finish before AMS client loads. (latency detected, future work to be part of AMS client enhancements) + ## [1.10.16] - 2025-03-27 ### Added + - Added exception details for telemetry for SendMessage - Expose `OriginalMessageId` to `ChatSDK.onNewMessage()` to handle message ordering - Update `ChatSDK.sendMessage()` to return `OmnichannelMessage` ### Changed + - Uptake [@microsoft/ocsdk@0.5.13](https://www.npmjs.com/package/@microsoft/ocsdk/v/0.5.13) ## [1.10.15] - 2025-03-11 diff --git a/README.md b/README.md index fd86e35a..0fa99757 100644 --- a/README.md +++ b/README.md @@ -14,48 +14,49 @@ Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Please make sure you have a chat widget configured before using this package or you can follow this [link](https://docs.microsoft.com/en-us/dynamics365/customer-service/add-chat-widget) ## Table of Contents + - [Live Chat Widget vs. Chat SDK](#live-chat-widget-vs-chat-sdk) - [Releases](#releases) - [Installation](#installation) - [Installation on React Native](#installation-on-react-native) - [SDK Methods](#sdk-methods) - - [Initialization](#initialization) - - [Start Chat](#start-chat) - - [End Chat](#end-chat) - - [Get Pre-Chat Survey](#get-pre-chat-survey) - - [Get Live Chat Config](#get-live-chat-config) - - [Get Current Live Chat Context](#get-current-live-chat-context) - - [Get Data Masking Rules](#get-data-masking-rules) - - [Get Chat Reconnect Context](#get-chat-reconnect-context) - - [Get Conversation Details](#get-conversation-details) - - [Get Chat Token](#get-chat-token) - - [Get Calling Token](#get-calling-token) - - [Get Messages](#get-messages) - - [Send Messages](#send-messages) - - [On New Message](#on-new-message) - - [On Typing Event](#on-typing-event) - - [On Agent End Session](#on-agent-end-session) - - [Send Typing Event](#send-typing-event) - - [Email Live Chat Transcript](#email-live-chat-transcript) - - [Get Live Chat Transcript](#get-live-chat-transcript) - - [Upload File Attachment](#upload-file-attachment) - - [Download File Attachment](#download-file-attachment) - - [Create Chat Adapter](#create-chat-adapter) - - [Get Voice & Video Calling](#get-voice--video-calling) - - [Get Post Chat Survey Context](#get-post-chat-survey-context) + - [Initialization](#initialization) + - [Start Chat](#start-chat) + - [End Chat](#end-chat) + - [Get Pre-Chat Survey](#get-pre-chat-survey) + - [Get Live Chat Config](#get-live-chat-config) + - [Get Current Live Chat Context](#get-current-live-chat-context) + - [Get Data Masking Rules](#get-data-masking-rules) + - [Get Chat Reconnect Context](#get-chat-reconnect-context) + - [Get Conversation Details](#get-conversation-details) + - [Get Chat Token](#get-chat-token) + - [Get Calling Token](#get-calling-token) + - [Get Messages](#get-messages) + - [Send Messages](#send-messages) + - [On New Message](#on-new-message) + - [On Typing Event](#on-typing-event) + - [On Agent End Session](#on-agent-end-session) + - [Send Typing Event](#send-typing-event) + - [Email Live Chat Transcript](#email-live-chat-transcript) + - [Get Live Chat Transcript](#get-live-chat-transcript) + - [Upload File Attachment](#upload-file-attachment) + - [Download File Attachment](#download-file-attachment) + - [Create Chat Adapter](#create-chat-adapter) + - [Get Voice & Video Calling](#get-voice--video-calling) + - [Get Post Chat Survey Context](#get-post-chat-survey-context) - [Common Scenarios](#common-scenarios) - - [Using BotFramework-WebChat](#using-botframework-webchat) - - [Escalation to Voice & Video](#escalation-to-voice--video) - - [Pre-Chat Survey](#pre-chat-survey) - - [Post-Chat Survey](#post-chat-survey) - - [Reconnect to existing Chat](#reconnect-to-existing-chat) - - [Authenticated Chat](#authenticated-chat) - - [Persistent Chat](#persistent-chat) - - [Chat Reconnect with Authenticated User](#chat-reconnect-with-authenticated-user) - - [Chat Reconnect with Unauthenticated User](#chat-reconnect-with-unauthenticated-user) - - [Handling chat Disconnect on Mobile platform](#handling-chat-disconnect-on-mobile-platform) - - [Operating Hours](#operating-hours) - - [Single Sign-on for Bots](/docs/scenarios/SINGLE_SIGN_ON_FOR_BOTS.md) + - [Using BotFramework-WebChat](#using-botframework-webchat) + - [Escalation to Voice & Video](#escalation-to-voice--video) + - [Pre-Chat Survey](#pre-chat-survey) + - [Post-Chat Survey](#post-chat-survey) + - [Reconnect to existing Chat](#reconnect-to-existing-chat) + - [Authenticated Chat](#authenticated-chat) + - [Persistent Chat](#persistent-chat) + - [Chat Reconnect with Authenticated User](#chat-reconnect-with-authenticated-user) + - [Chat Reconnect with Unauthenticated User](#chat-reconnect-with-unauthenticated-user) + - [Handling chat Disconnect on Mobile platform](#handling-chat-disconnect-on-mobile-platform) + - [Operating Hours](#operating-hours) + - [Single Sign-on for Bots](/docs/scenarios/SINGLE_SIGN_ON_FOR_BOTS.md) - [Sample Apps](https://github.com/microsoft/omnichannel-chat-sdk-samples) - [Feature Comparisons](#feature-comparisons) - [Telemetry](#telemetry) @@ -65,6 +66,7 @@ Please make sure you have a chat widget configured before using this package or ## Live Chat Widget vs. Chat SDK Omnichannel offers a live chat widget (LCW) by default. You can use the Chat SDK to build your custom chat widget if: + - You want to fully customize the user interface of the chat widget to conform with your branding. - You want to integrate Omnichannel into your mobile app using React Native. - You want to integrate additional functionalities that LCW does not offer. @@ -75,24 +77,24 @@ Omnichannel offers a live chat widget (LCW) by default. You can use the Chat SDK | Feature | Live Chat Widget | Chat SDK | Notes | | ----- | ----- | ----- | ----- | | Bring Your Own Widget | ❌ | ✔ | | -| Web Support | ✔ | ✔ | -| React Native Support | ❌ | ✔ | +| Web Support | ✔ | ✔ || +| React Native Support | ❌ | ✔ | | | Escalation to Voice & Video | ✔ | ✔ | Only supported on Web | | Co-browse | ✔ | 3rd party add-on | Only supported on Web | | Screen Sharing | ✔ | 3rd party add-on | Only supported on Web | -| Authenticated Chat | ✔ | ✔ | -| Pre-chat Survey | ✔ | ✔ | -| Post-chat Survey | ✔ | ✔ | -| Download Transcript | ✔ | ✔ | -| Email Transcript | ✔ | ✔ | -| Data Masking | ✔ | ✔ | -| File Attachments | ✔ | ✔ | -| Custom Context | ✔ | ✔ | -| Proactive Chat | ✔ | BYOI **\*** | -| Persistent Chat | ✔ | ✔ | -| Chat Reconnect | ✔ | ✔ | -| Operating Hours | ✔ | ✔ | -| Get Agent Availability | ✔ | ✔ | +| Authenticated Chat | ✔ | ✔ | | +| Pre-chat Survey | ✔ | ✔ | | +| Post-chat Survey | ✔ | ✔ | | +| Download Transcript | ✔ | ✔ | | +| Email Transcript | ✔ | ✔ | | +| Data Masking | ✔ | ✔ | | +| File Attachments | ✔ | ✔ | | +| Custom Context | ✔ | ✔ | | +| Proactive Chat | ✔ | BYOI **\*** | | +| Persistent Chat | ✔ | ✔ | | +| Chat Reconnect | ✔ | ✔ | | +| Operating Hours | ✔ | ✔ | | +| Get Agent Availability | ✔ | ✔ | | | Queue Position | ✔ | ✔ | No SDK method. Handled as *system message* | | Average Wait Time | ✔ | ✔ | No SDK method. Handled as *system message* | @@ -142,7 +144,7 @@ New releases are published on a regular basis to ensure the product quality. ## Installation -``` +```console npm install @microsoft/omnichannel-chat-sdk --save ``` @@ -151,31 +153,37 @@ npm install @microsoft/omnichannel-chat-sdk --save The following steps will be required to run Omnichannel Chat SDK on React Native: 1. Install `node-libs-react-native` - ``` + + ```console npm install node-libs-react-native --save-dev ``` 1. Install `react-native-randomBytes` - ``` + + ```console npm install react-native-randombytes --save-dev ``` 1. Install `react-native-get-random-values` - ``` + + ```console npm install react-native-get-random-values --save-dev ``` 1. Install `react-native-url-polyfill` - ``` + + ```console npm install react-native-url-polyfill --save-dev ``` 1. Install `@azure/core-asynciterator-polyfill` - ``` + + ```console npm install @azure/core-asynciterator-polyfill --save-dev ``` 1. Update *metro.config.js* to use React Native compatible Node Core modules + ```ts module.exports = { // ... @@ -190,6 +198,7 @@ The following steps will be required to run Omnichannel Chat SDK on React Native ``` 1. Add the following *import* on top of your entry point file + ```ts import 'node-libs-react-native/globals'; import 'react-native-get-random-values'; @@ -223,10 +232,14 @@ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, cha const optionalParams = { getLiveChatConfigOptionalParams: { - sendCacheHeaders: false // Whether to send Cache-Control HTTP header to GetChatConfig call + sendCacheHeaders: false,// Whether to send Cache-Control HTTP header to GetChatConfig call + useSequentialLoad: false // Whether to use sequential load for chat config, if not present, by default uses parallel load for faster initialization + } }; + +// For the case when the widget doesnt have enabled support for attachments, Upload/download operations wont be supported await chatSDK.initialize(optionalParams); ``` @@ -394,6 +407,7 @@ chatSDK.onNewMessage((message) => { console.log(message); }, optionalParams); ``` + ### On Typing Event It subscribes to an agent typing event. @@ -512,6 +526,7 @@ try { } } ``` + ### Get Post Chat Survey Context It gets the participant type that should be used for the survey and both the default and bot survey details. @@ -532,7 +547,7 @@ const agentAvailability = await chatSDK.getAgentAvailability(); ### Pre-Chat Survey -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-pre-chat-survey?tabs=customerserviceadmincenter on how to set up pre-conversation surveys +> See on how to set up pre-conversation surveys ```ts import * as AdaptiveCards, { Action } from "adaptivecards"; @@ -567,7 +582,7 @@ const agentAvailability = await chatSDK.getAgentAvailability(); ### Post-Chat Survey -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-post-conversation-survey?tabs=customerserviceadmincenter on how to set up post-conversation surveys +> See on how to set up post-conversation surveys > ❗ `chatSDK.getPostChatSurveyContext()` needs to be called before `chatSDK.endChat()` is called @@ -626,7 +641,7 @@ messages.reverse().forEach((message: any) => renderMessage(message)); // Logic t ### Authenticated Chat -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-chat-auth-settings?tabs=customerserviceadmincenter#create-a-chat-authentication-setting-record on how to set up an authenticated chat +> See on how to set up an authenticated chat ```ts const chatSDKConfig = { @@ -649,7 +664,7 @@ await chatSDK.initialize(); ### Persistent Chat -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/persistent-chat on how to set up persistent chat +> See on how to set up persistent chat ```ts const chatSDKConfig = { @@ -673,9 +688,10 @@ await chatSDK.initialize(); // from this point, this acts like a persistent chat ``` + ### Chat Reconnect with Authenticated User -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect +> See on how to set up chat reconnect ```ts const chatSDKConfig = { @@ -715,7 +731,7 @@ chatSDK.startChat(); ### Chat Reconnect with Unauthenticated User -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect +> See on how to set up chat reconnect ```ts const chatSDKConfig = { @@ -759,7 +775,7 @@ if (chatReconnectContext.reconnectId) { ### Operating Hours -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-operating-hours?tabs=customerserviceadmincenter on how to set up operating hours +> See on how to set up operating hours ```ts const chatConfig = await chatSDK.getLiveChatConfig(); @@ -796,11 +812,12 @@ window.addEventListener("visibilitychange", async () => { }); ``` - ### Using [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat) +> > :warning: Currently supported on web only Minimum Requirement Checklist + 1. [ ] Initialize ChatSDK 1. [ ] Start new conversation 1. [ ] Create Chat Adapter @@ -838,9 +855,10 @@ const store = createStore( ``` ### Escalation to Voice & Video +> > :warning: Currently supported on web only -> See https://docs.microsoft.com/en-us/dynamics365/customer-service/call-options-visual-engagement on how to set up calling options +> See on how to set up calling options ```ts import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk'; @@ -948,17 +966,19 @@ if (VoiceVideoCallingSDK) { ## Feature Comparisons ### Web + | | Custom Control | WebChat Control | | --- | --- | --- | | **Features** | | | | Chat Widget UI | Not provided | Basic chat client provided | | Data Masking | Embedded | Requires `Data Masking Middleware` implementation | | Send Typing indicator | Embedded | Requires `sendTypingIndicator` flag set to `true` | -| PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer +| PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer| | Display Attachments | Requires implementation | Basic interface provided & Customizable | | Incoming messages handling | IC3 protocol message data | DirectLine activity data | ### React Native + | | Custom Control | Gifted Chat Control | WebChat Control | | --- | --- | --- | --- | | **Features** | | | Currently not supported | @@ -1007,7 +1027,7 @@ await chatSDK.initialize(); This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. +the rights to use your contribution. For details, visit . When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions diff --git a/__tests__/OmnichannelChatSDK.node.spec.ts b/__tests__/OmnichannelChatSDK.node.spec.ts index 24e41734..e4b341e8 100644 --- a/__tests__/OmnichannelChatSDK.node.spec.ts +++ b/__tests__/OmnichannelChatSDK.node.spec.ts @@ -36,6 +36,7 @@ describe('Omnichannel Chat SDK (Node), Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -82,6 +83,7 @@ describe('Omnichannel Chat SDK (Node), Sequential', () => { }; chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -113,6 +115,7 @@ describe('Omnichannel Chat SDK (Node), Sequential', () => { }; chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); diff --git a/__tests__/OmnichannelChatSDK.spec.ts b/__tests__/OmnichannelChatSDK.spec.ts index b42ef565..ed3c340e 100644 --- a/__tests__/OmnichannelChatSDK.spec.ts +++ b/__tests__/OmnichannelChatSDK.spec.ts @@ -521,6 +521,8 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.SDKProvider = SDKProvider; try { + chatSDK["isAMSClientAllowed"] = true; + await chatSDK.initialize(); fail(); } catch (e: any ) { @@ -537,6 +539,8 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(() => {throw Error()}); try { + chatSDK["isAMSClientAllowed"] = true; + await chatSDK.initialize(); fail(); } catch (e: any ) { @@ -552,6 +556,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const getLiveChatConfigOptionalParams = { sendCacheHeaders: true }; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({getLiveChatConfigOptionalParams}); @@ -585,6 +590,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.liveChatVersion = LiveChatVersion.V1; jest.spyOn(chatSDK, 'getIC3Client'); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); await chatSDK.initialize(); @@ -790,6 +796,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -816,6 +823,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -847,6 +855,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -883,6 +892,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -920,6 +930,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1014,6 +1025,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { }; chatSDK.dataMaskingRules = { rules : [dataMaskingRule]} as MaskingRules; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1063,6 +1075,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { // global.fetch = jest.fn(); const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1092,6 +1105,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should throw an error if OCClient.sessionInit() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1120,6 +1134,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should not call OCClient.sessionInit() if OCClient.getChatToken() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1139,7 +1154,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should throw a \'WidgetUseOutsideOperatingHour\' error if OCClient.sessionInit() fails with \'705\' error code', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); chatSDK.ACSClient.initialize = jest.fn(); @@ -1176,6 +1191,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1235,6 +1251,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should throw an exception if ACSClient.initialize() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1265,6 +1282,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should throw an exception if AMSClient.initialize() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1295,6 +1313,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() should throw an exception if ACSClient.joinConversation() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1325,6 +1344,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startchat() with existing liveChatContext should not call OCClient.getChatToken() & OCClient.sessionInit()', async() => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({ @@ -1364,6 +1384,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() with invalid liveChatContext should throw an error', async() => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({ @@ -1397,6 +1418,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.startChat() with liveChatContext of a closed conversation should throw an error', async() => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({ @@ -1492,6 +1514,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1533,6 +1556,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1556,6 +1580,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1600,6 +1625,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1662,6 +1688,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const oldGetChatConfig = chatSDK.getChatConfig; chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1745,6 +1772,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1826,6 +1854,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.getCurrentLiveChatContext() with empty chatToken should return an empty chat session data', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1852,6 +1881,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.getConversationDetails() should call OCClient.getLWIDetails()', async() => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1874,6 +1904,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it('ChatSDK.getConversationDetails() should return "{}" and not throw exception if OCClient.getLWIDetails() fails ', async() => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1893,6 +1924,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1942,6 +1974,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -1988,6 +2021,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.isPersistentChat = true; global.setInterval = jest.fn() as unknown as typeof setInterval; chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2022,6 +2056,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { it("ChatSDK.getConversationDetails() with liveChatContext should fetch conversation details from liveChatContext", async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2086,6 +2121,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2283,6 +2319,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2353,6 +2390,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; chatSDK.liveChatVersion = LiveChatVersion.V1; @@ -2399,6 +2437,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2459,6 +2498,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2522,6 +2562,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); chatSDK.OCClient = { @@ -2550,6 +2591,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2580,6 +2622,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2614,6 +2657,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2668,6 +2712,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); chatSDK.ACSClient.initialize = jest.fn(); @@ -2717,6 +2762,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2742,6 +2788,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2792,6 +2839,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2848,6 +2896,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { jest.spyOn(platform, 'isBrowser').mockReturnValue(false); jest.spyOn(chatSDK, 'getIC3Client'); jest.spyOn(IC3SDKProvider, 'getSDK'); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2891,6 +2940,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2919,6 +2969,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2947,6 +2998,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -2985,6 +3037,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3012,6 +3065,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); chatSDK.liveChatVersion = LiveChatVersion.V1; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3037,6 +3091,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3096,6 +3151,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3126,6 +3182,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3158,6 +3215,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3190,6 +3248,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3222,6 +3281,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3256,6 +3316,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3347,6 +3408,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isPersistentChat = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3422,6 +3484,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.isPersistentChat = true; chatSDK.updateChatToken = jest.fn(); global.setInterval = jest.fn() as unknown as typeof setInterval; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3460,6 +3523,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.isPersistentChat = true; chatSDK.liveChatVersion = LiveChatVersion.V1; global.setInterval = jest.fn() as unknown as typeof setInterval; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3554,6 +3618,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3583,6 +3648,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); chatSDK.ACSClient.initialize = jest.fn(); @@ -3621,6 +3687,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3656,6 +3723,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3690,6 +3758,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3731,6 +3800,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3766,6 +3836,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3795,6 +3866,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3830,6 +3902,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3846,7 +3919,6 @@ describe('Omnichannel Chat SDK, Sequential', () => { expect(chatSDK.OCClient.getReconnectableChats).toHaveBeenCalledTimes(1); }); - it('ChatSDK.getChatReconnectContext() should fail if OCClient.getReconnectAvailability() fails', async () => { const chatSDKConfig = { telemetry: { @@ -3860,6 +3932,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3900,6 +3973,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3941,6 +4015,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -3985,6 +4060,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -4032,6 +4108,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -4081,6 +4158,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -4132,6 +4210,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); @@ -4187,6 +4266,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); chatSDK.authSettings = {}; @@ -4229,6 +4309,7 @@ describe('Omnichannel Chat SDK, Sequential', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize(); diff --git a/__tests__/OmnichannelChatSDK.web.spec.ts b/__tests__/OmnichannelChatSDK.web.spec.ts index cb3cee7d..7968f28b 100644 --- a/__tests__/OmnichannelChatSDK.web.spec.ts +++ b/__tests__/OmnichannelChatSDK.web.spec.ts @@ -95,6 +95,7 @@ describe('Omnichannel Chat SDK (Web), Sequential', () => { try { await chatSDK.startChat(optionalParams); + fail("Error expected"); } catch (error : any ) { expect(error.message).toEqual(ChatSDKErrorName.UnsupportedPlatform); expect(console.error).toHaveBeenCalledWith("sendDefaultInitContext is only supported on browser"); diff --git a/__tests__/OmnichannelChatSDKParallel.node.spec.ts b/__tests__/OmnichannelChatSDKParallel.node.spec.ts index 7ed3efd8..81c30128 100644 --- a/__tests__/OmnichannelChatSDKParallel.node.spec.ts +++ b/__tests__/OmnichannelChatSDKParallel.node.spec.ts @@ -81,6 +81,7 @@ describe('Omnichannel Chat SDK (Node) Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.ACSClient.initialize = jest.fn(); @@ -118,7 +119,7 @@ describe('Omnichannel Chat SDK (Node) Parallel initialization', () => { }; chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { diff --git a/__tests__/OmnichannelChatSDKParallel.spec.ts b/__tests__/OmnichannelChatSDKParallel.spec.ts index f1e7fa73..e249164d 100644 --- a/__tests__/OmnichannelChatSDKParallel.spec.ts +++ b/__tests__/OmnichannelChatSDKParallel.spec.ts @@ -36,6 +36,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { if (global.window.document) { (global as any).window.document = undefined; } + }); describe('Configurations', () => { @@ -373,7 +374,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); // eslint-disable-next-line @typescript-eslint/no-var-requires const version = require("../package.json").version; @@ -396,7 +397,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); // eslint-disable-next-line @typescript-eslint/no-var-requires const version = require("../package.json").version; @@ -424,6 +425,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.liveChatVersion = 'invalid'; try { + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); } catch (e: any ) { expect(e.message).toBe("UnsupportedLiveChatVersion"); @@ -433,7 +435,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.initialize() should instantiate OCSDK & ACSClient & AMSClient', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -461,6 +463,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.SDKProvider = SDKProvider; try { + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); fail(); } catch (e: any ) { expect(e.message).toBe("OmnichannelClientInitializationFailure"); @@ -476,6 +479,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(() => { throw Error() }); try { + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); fail(); } catch (e: any ) { expect(e.message).toBe("ChatConfigRetrievalFailure"); @@ -490,7 +494,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const getLiveChatConfigOptionalParams = { sendCacheHeaders: true, }; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true, getLiveChatConfigOptionalParams }); jest.spyOn(chatSDK.OCClient, 'getChatConfig') @@ -714,7 +718,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK, 'setAuthTokenProvider'); jest.spyOn(chatSDK.scenarioMarker, 'failScenario'); @@ -738,7 +742,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK, 'setAuthTokenProvider'); jest.spyOn(chatSDK.scenarioMarker, 'failScenario'); @@ -768,7 +772,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK, 'setAuthTokenProvider'); jest.spyOn(chatSDK.scenarioMarker, 'failScenario'); @@ -803,7 +807,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { await new Promise(resolve => setTimeout(resolve, 2000)); @@ -843,7 +847,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.authSettings = {}; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -946,7 +950,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.dataMaskingRules = { rules : [ dataMaskingRules ] } as MaskingRules; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); const maskingRules : MaskingRules = await chatSDK.getDataMaskingRules(); expect(maskingRules.rules[0]).toBe(dataMaskingRules); @@ -967,7 +971,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { // global.fetch = jest.fn(); const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1002,7 +1006,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should throw an error if OCClient.sessionInit() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1037,7 +1041,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should not call OCClient.sessionInit() if OCClient.getChatToken() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(new Error("Async error message")); jest.spyOn(chatSDK.OCClient, 'sessionInit').mockRejectedValue(Promise.resolve()); @@ -1055,7 +1059,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should throw a \'WidgetUseOutsideOperatingHour\' error if OCClient.sessionInit() fails with \'705\' error code', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1098,7 +1102,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should throw an exception if ACSClient.initialize() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1135,7 +1139,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should throw an exception if AMSClient.initialize() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1171,7 +1175,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() should throw an exception if ACSClient.joinConversation() fails', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1207,7 +1211,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startchat() with existing liveChatContext should not call OCClient.getChatToken() & OCClient.sessionInit()', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1254,7 +1258,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() with invalid liveChatContext should throw an error', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1295,7 +1299,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.startChat() with liveChatContext of a closed conversation should throw an error', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1404,7 +1408,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1433,7 +1437,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.getCurrentLiveChatContext() with empty chatToken should return an empty chat session data', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1466,7 +1470,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.getConversationDetails() should call OCClient.getLWIDetails()', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1495,7 +1499,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it('ChatSDK.getConversationDetails() should return "{}" and not throw exception if OCClient.getLWIDetails() fails ', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1529,7 +1533,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1585,7 +1589,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1625,7 +1629,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { it("ChatSDK.getConversationDetails() with liveChatContext should fetch conversation details from liveChatContext", async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1670,7 +1674,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1706,7 +1710,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1745,7 +1749,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1780,7 +1784,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1819,7 +1823,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1855,7 +1859,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1892,7 +1896,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1933,7 +1937,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -1994,7 +1998,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2053,7 +2057,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { await new Promise(resolve => setTimeout(resolve, 2000)); @@ -2081,7 +2085,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2139,6 +2143,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2188,7 +2193,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2222,7 +2227,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2268,7 +2273,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2302,7 +2307,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { @@ -2334,7 +2339,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2371,7 +2376,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2410,7 +2415,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2450,7 +2455,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2488,7 +2493,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2527,7 +2532,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2565,7 +2570,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2619,7 +2624,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2700,7 +2705,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isPersistentChat = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.reconnectId = 'reconnectId'; @@ -2733,6 +2738,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.updateChatToken = jest.fn(); global.setInterval = jest.fn() as unknown as typeof setInterval; + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { await new Promise(resolve => setTimeout(resolve, 2000)); @@ -2835,7 +2841,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.reconnectId = 'reconnectId'; @@ -2863,7 +2869,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2909,7 +2915,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); let retryCount = 0; const maxRetries = 3; @@ -2951,7 +2957,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); const mockedResponse = { reconnectid: 'reconnectid' @@ -2984,7 +2990,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); const mockedResponse = { reconnectid: 'reconnectid' @@ -3024,7 +3030,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); const mockedResponse = { reconnectid: 'reconnectid' @@ -3058,7 +3064,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK.OCClient, 'getReconnectAvailability').mockResolvedValue(Promise.resolve()); @@ -3086,7 +3092,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); const mockedResponse = { isReconnectAvailable: false, @@ -3120,7 +3126,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; chatSDK.authenticatedUserToken = 'token'; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK.OCClient, 'getReconnectableChats').mockResolvedValue(Promise.reject()); jest.spyOn(console, 'error'); @@ -3147,7 +3153,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.isChatReconnect = true; - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); jest.spyOn(chatSDK.OCClient, 'getReconnectAvailability').mockResolvedValue(Promise.reject()); jest.spyOn(console, 'error'); @@ -3185,7 +3191,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3225,7 +3231,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3268,7 +3274,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3314,7 +3320,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3365,7 +3371,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3418,7 +3424,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.liveChatConfig = dummyConfig; jest.spyOn(chatSDK, 'getConversationDetails').mockResolvedValue({ @@ -3476,7 +3482,7 @@ describe('Omnichannel Chat SDK, Parallel initialization', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); chatSDK.authSettings = {}; chatSDK.authenticatedUserToken = {}; chatSDK.conversation = {}; diff --git a/__tests__/OmnichannelChatSDKParallel.web.spec.ts b/__tests__/OmnichannelChatSDKParallel.web.spec.ts index 4a993cbb..17048399 100644 --- a/__tests__/OmnichannelChatSDKParallel.web.spec.ts +++ b/__tests__/OmnichannelChatSDKParallel.web.spec.ts @@ -40,6 +40,7 @@ describe('Omnichannel Chat SDK (Web)', () => { it('ChatSDK.startChat() with sendDefaultInitContext should pass getContext to OCClient.sessionInit()', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); @@ -77,7 +78,7 @@ describe('Omnichannel Chat SDK (Web)', () => { it('ChatSDK.startChat() with sendDefaultInitContext should throw an error if not used on Web Platform', async () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { @@ -103,6 +104,7 @@ describe('Omnichannel Chat SDK (Web)', () => { try { await chatSDK.startChat(optionalParams); + fail("Error expected"); } catch (error : any ) { expect(error.message).toEqual(ChatSDKErrorName.UnsupportedPlatform); expect(console.error).toHaveBeenCalledWith("sendDefaultInitContext is only supported on browser"); @@ -113,7 +115,7 @@ describe('Omnichannel Chat SDK (Web)', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { @@ -142,7 +144,7 @@ describe('Omnichannel Chat SDK (Web)', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { @@ -174,7 +176,7 @@ describe('Omnichannel Chat SDK (Web)', () => { const chatSDK = new OmnichannelChatSDK(omnichannelConfig); chatSDK.getChatConfig = jest.fn(); chatSDK.getChatToken = jest.fn(); - + chatSDK["isAMSClientAllowed"] = true; await chatSDK.initialize({ useParallelLoad: true }); while (chatSDK.AMSClient === null) { diff --git a/package.json b/package.json index 75220dd1..43d21faf 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,9 @@ "postbuild:tsc": "node ./scripts/copy_files.js", "prebuild:tsc": "eslint src --ext .ts", "test": "npm run test:jsdom && npm run test:node", - "test:jsdom": "jest --config jest.config.jsdom.js", - "test:node": "jest --config jest.config.node.js", + "test:jsdom": "jest --config jest.config.jsdom.js --verbose", + "test:node": "jest --config jest.config.node.js --verbose", + "watch": "tsc --watch", "lint": "eslint src --ext .ts" }, "author": "Microsoft Corporation", diff --git a/src/OmnichannelChatSDK.ts b/src/OmnichannelChatSDK.ts index ba211fba..b958d563 100644 --- a/src/OmnichannelChatSDK.ts +++ b/src/OmnichannelChatSDK.ts @@ -11,6 +11,7 @@ import { SDKProvider as OCSDKProvider, uuidv4 } from "@microsoft/ocsdk"; import { createACSAdapter, createDirectLine, createIC3Adapter } from "./utils/chatAdapterCreators"; import { createCoreServicesOrgUrl, getCoreServicesGeoName, isCoreServicesOrgUrl, unqOrgUrlPattern } from "./utils/CoreServicesUtils"; import { defaultLocaleId, getLocaleStringFromId } from "./utils/locale"; +import exceptionThrowers, { throwAMSLoadFailure } from "./utils/exceptionThrowers"; import { getRuntimeId, isClientIdNotFoundErrorMessage, isCustomerMessage } from "./utils/utilities"; import { loadScript, removeElementById, sleep } from "./utils/WebUtils"; import platform, { isBrowser } from "./utils/platform"; @@ -37,6 +38,7 @@ import ConversationMode from "./core/ConversationMode"; import DeliveryMode from "@microsoft/omnichannel-ic3core/lib/model/DeliveryMode"; import EmailLiveChatTranscriptOptionaParams from "./core/EmailLiveChatTranscriptOptionalParams"; import EndChatOptionalParams from "./core/EndChatOptionalParams"; +import FetchChatTokenResponse from "@microsoft/ocsdk/lib/Model/FetchChatTokenResponse"; import FileMetadata from "@microsoft/omnichannel-amsclient/lib/FileMetadata"; import FileSharingProtocolType from "@microsoft/omnichannel-ic3core/lib/model/FileSharingProtocolType"; import FramedClient from "@microsoft/omnichannel-amsclient/lib/FramedClient"; @@ -98,7 +100,6 @@ import createTelemetry from "./utils/createTelemetry"; import createVoiceVideoCalling from "./api/createVoiceVideoCalling"; import { defaultMessageTags } from "./core/messaging/MessageTags"; import exceptionSuppressors from "./utils/exceptionSuppressors"; -import exceptionThrowers from "./utils/exceptionThrowers"; import { getLocationInfo } from "./utils/location"; import { isCoreServicesOrgUrlDNSError } from "./utils/internalUtils"; import loggerUtils from "./utils/loggerUtils"; @@ -109,7 +110,6 @@ import startPolling from "./commands/startPolling"; import stopPolling from "./commands/stopPolling"; import urlResolvers from "./utils/urlResolvers"; import validateOmnichannelConfig from "./validators/OmnichannelConfigValidator"; -import FetchChatTokenResponse from "@microsoft/ocsdk/lib/Model/FetchChatTokenResponse"; class OmnichannelChatSDK { private debug: boolean; @@ -149,10 +149,11 @@ class OmnichannelChatSDK { private isPersistentChat = false; private isChatReconnect = false; private reconnectId: null | string = null; - private refreshTokenTimer: NodeJS.Timeout | string |number | null = null; + private refreshTokenTimer: NodeJS.Timeout | string | number | null = null; private AMSClientLoadCurrentState: AMSClientLoadStates = AMSClientLoadStates.NOT_LOADED; private isMaskingDisabled = false; private maskingCharacter = "#"; + private isAMSClientAllowed = false; constructor(omnichannelConfig: OmnichannelConfig, chatSDKConfig: ChatSDKConfig = defaultChatSDKConfig) { this.debug = false; @@ -212,81 +213,106 @@ class OmnichannelChatSDK { /* istanbul ignore next */ public setDebug(flag: boolean): void { - this.debug = flag; - this.getAMSClient().then((client) => client?.setDebug(flag)); - this.telemetry?.setDebug(flag); this.scenarioMarker.setDebug(flag); + + if (this.AMSClient) { + this.AMSClient.setDebug(flag); + } + loggerUtils.setDebug(flag, this.ocSdkLogger, this.acsClientLogger, this.acsAdapterLogger, this.callingSdkLogger, this.amsClientLogger, this.ic3ClientLogger); } - private async retryLoadAMSClient() : Promise { + private async retryLoadAMSClient(): Promise { // Constants for retry logic const RETRY_DELAY_MS = 1000; - const MAX_RETRY_COUNT = 5; + const MAX_RETRY_COUNT = 30; let retryCount = 0; while (retryCount < MAX_RETRY_COUNT) { if (this.AMSClient) { return this.AMSClient; } - await sleep(RETRY_DELAY_MS); retryCount++; } return null; } - private async getAMSClient() : Promise { + private async getAMSClient(): Promise { + + //return null to do not break promise creation + if (this.isAMSClientAllowed === false) { + return null; + } if (this.AMSClientLoadCurrentState === AMSClientLoadStates.NOT_LOADED && this.liveChatVersion === LiveChatVersion.V1) { return null; } switch (this.AMSClientLoadCurrentState) { case AMSClientLoadStates.LOADED: + this.debug && console.log("Attachment handler is already loaded"); return this.AMSClient; case AMSClientLoadStates.LOADING: + this.debug && console.log("Attachment handler is loading, waiting for it to be ready"); return await this.retryLoadAMSClient(); - case AMSClientLoadStates.ERROR: case AMSClientLoadStates.NOT_LOADED: + this.debug && console.log("Attachment handler is not loaded, loading now"); await this.loadAmsClient(); return this.AMSClient; - default: return null; } } - private async loadInitComponents() : Promise{ + private async loadInitComponents(): Promise { this.scenarioMarker.startScenario(TelemetryEvent.InitializeComponents); const supportedLiveChatVersions = [LiveChatVersion.V1, LiveChatVersion.V2]; if (!supportedLiveChatVersions.includes(this.liveChatVersion)) { exceptionThrowers.throwUnsupportedLiveChatVersionFailure(new Error(ChatSDKErrorName.UnsupportedLiveChatVersion), this.scenarioMarker, TelemetryEvent.InitializeComponents); } - - this.isInitialized = true; + // we need this version validation, until we remove all v1 code, pending task. + if (this.liveChatVersion === LiveChatVersion.V2) { + this.ACSClient = new ACSClient(this.acsClientLogger); + } else { + this.IC3Client = await this.getIC3Client(); + } this.scenarioMarker.completeScenario(TelemetryEvent.InitializeComponents); } - private async loadAmsClient() : Promise { - this.scenarioMarker.startScenario(TelemetryEvent.InitializeMessagingClient); - try { + private evaluateAMSAvailability(): boolean { + + // it will load AMS only if enabled for Customer or Agent support for attachments, based on configuration + if (this.liveChatConfig?.LiveWSAndLiveChatEngJoin?.msdyn_enablefileattachmentsforcustomers === "true" || + this.liveChatConfig?.LiveWSAndLiveChatEngJoin?.msdyn_enablefileattachmentsforagents === "true") { if (this.liveChatVersion === LiveChatVersion.V2) { - this.ACSClient = new ACSClient(this.acsClientLogger); - this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADING; + //override of this value, since it will be needed to control access to attachment operations + this.isAMSClientAllowed = true; + return this.isAMSClientAllowed; + } + } + return this.isAMSClientAllowed; + } - this.AMSClient = await createAMSClient({ - framedMode: isBrowser(), - multiClient: true, - debug: false, - logger: this.amsClientLogger as PluggableLogger - }); - this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADED; - } else if (this.liveChatVersion === LiveChatVersion.V1) { - this.IC3Client = await this.getIC3Client(); + private async loadAmsClient(): Promise { + this.scenarioMarker.startScenario(TelemetryEvent.InitializeMessagingClient); + try { + if (this.isAMSClientAllowed) { + if (this.AMSClientLoadCurrentState === AMSClientLoadStates.NOT_LOADED) { + this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADING; + this.debug && console.time("ams_creation"); + this.AMSClient = await createAMSClient({ + framedMode: isBrowser(), + multiClient: true, + debug: this.debug, + logger: this.amsClientLogger as PluggableLogger + }); + this.debug && console.timeEnd("ams_creation"); + this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADED; + } } this.scenarioMarker.completeScenario(TelemetryEvent.InitializeMessagingClient); @@ -298,7 +324,6 @@ class OmnichannelChatSDK { private async parallelInitialization(optionalParams: InitializeOptionalParams = {}) { try { - this.scenarioMarker.startScenario(TelemetryEvent.InitializeChatSDKParallel); if (this.isInitialized) { @@ -310,7 +335,6 @@ class OmnichannelChatSDK { await Promise.all([this.loadInitComponents(), this.loadChatConfig(optionalParams)]); // this will load ams in the background, without holding the load this.loadAmsClient(); - this.isInitialized = true; this.scenarioMarker.completeScenario(TelemetryEvent.InitializeChatSDKParallel); } catch (error) { @@ -359,13 +383,20 @@ class OmnichannelChatSDK { if (this.liveChatVersion === LiveChatVersion.V2) { this.ACSClient = new ACSClient(this.acsClientLogger); - this.AMSClient = await createAMSClient({ - framedMode: isBrowser(), - multiClient: true, - debug: false, - logger: this.amsClientLogger as PluggableLogger - }); - this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADED; + + if (this.isAMSClientAllowed && this.AMSClientLoadCurrentState === AMSClientLoadStates.NOT_LOADED) { + this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADING; + this.debug && console.time("ams_seq_creation"); + this.AMSClient = await createAMSClient({ + framedMode: isBrowser(), + multiClient: true, + debug: this.debug, + logger: this.amsClientLogger as PluggableLogger + }); + this.debug && console.timeEnd("ams_seq_creation"); + this.AMSClientLoadCurrentState = AMSClientLoadStates.LOADED; + } + } else if (this.liveChatVersion === LiveChatVersion.V1) { this.IC3Client = await this.getIC3Client(); } @@ -395,7 +426,7 @@ class OmnichannelChatSDK { return await this.sequentialInitialization(optionalParams); } - private async loadChatConfig(optionalParams: InitializeOptionalParams = {}) : Promise { + private async loadChatConfig(optionalParams: InitializeOptionalParams = {}): Promise { this.scenarioMarker.startScenario(TelemetryEvent.InitializeLoadChatConfig); const useCoreServices = isCoreServicesOrgUrl(this.omnichannelConfig.orgUrl); @@ -410,6 +441,7 @@ class OmnichannelChatSDK { try { const { getLiveChatConfigOptionalParams } = optionalParams; await this.getChatConfig(getLiveChatConfigOptionalParams || {}); + // once we have the config, we can check if we need to load AMS } catch (e) { exceptionThrowers.throwChatConfigRetrievalFailure(e, this.scenarioMarker, TelemetryEvent.InitializeLoadChatConfig); } @@ -803,25 +835,28 @@ class OmnichannelChatSDK { } }; - const attachmentClientPromise = async () : Promise => { + const attachmentClientPromise = async (): Promise => { try { - const amsClient = await this.getAMSClient(); if (this.liveChatVersion === LiveChatVersion.V2) { + if (!this.isAMSClientAllowed) return; + // will wait till the AMSClient is loaded, and then initialize it + this.debug && console.time("ams_promise_initialization"); + const amsClient = await this.getAMSClient(); await amsClient?.initialize({ chatToken: this.chatToken as OmnichannelChatToken }); + this.debug && console.timeEnd("ams_promise_initialization"); } } catch (error) { const telemetryData = { RequestId: this.requestId, ChatId: this.chatToken.chatId as string, }; - exceptionThrowers.throwMessagingClientInitializationFailure(error, this.scenarioMarker, TelemetryEvent.StartChat, telemetryData); } }; if (!this.chatSDKConfig.useCreateConversation?.disable) { await createConversationPromise(); - await Promise.all([messagingClientPromise(), attachmentClientPromise()]); + await Promise.all([messagingClientPromise(),attachmentClientPromise()]); } else { await Promise.all([sessionInitPromise(), messagingClientPromise(), attachmentClientPromise()]); } @@ -1588,7 +1623,7 @@ class OmnichannelChatSDK { } public async uploadFileAttachment(fileInfo: IFileInfo | File): Promise { - const amsClient = await this.getAMSClient(); + this.scenarioMarker.startScenario(TelemetryEvent.UploadFileAttachment, { RequestId: this.requestId, ChatId: this.chatToken.chatId as string @@ -1599,6 +1634,16 @@ class OmnichannelChatSDK { } if (this.liveChatVersion === LiveChatVersion.V2) { + + if (this.isAMSClientAllowed === false) { + exceptionThrowers.throwFeatureDisabled(this.scenarioMarker, TelemetryEvent.UploadFileAttachment, "Enable support for attachment upload and receive in the widget configuration."); + } + const amsClient = await this.getAMSClient(); + + if (amsClient === null || amsClient === undefined) { + throwAMSLoadFailure(this.scenarioMarker, TelemetryEvent.UploadFileAttachment, "Attachment handler client is null, no action can be performed"); + } + const createObjectResponse: any = await amsClient?.createObject(this.chatToken?.chatId as string, fileInfo as any); // eslint-disable-line @typescript-eslint/no-explicit-any const documentId = createObjectResponse.id; const uploadDocumentResponse: any = await amsClient?.uploadDocument(documentId, fileInfo as any); // eslint-disable-line @typescript-eslint/no-explicit-any @@ -1651,7 +1696,6 @@ class OmnichannelChatSDK { return messageToSend; } catch (error) { console.error("OmnichannelChatSDK/uploadFileAttachment/sendMessage/error"); - this.scenarioMarker.failScenario(TelemetryEvent.UploadFileAttachment, { RequestId: this.requestId, ChatId: this.chatToken.chatId as string @@ -1706,7 +1750,7 @@ class OmnichannelChatSDK { } public async downloadFileAttachment(fileMetadata: FileMetadata | IFileMetadata): Promise { - const amsClient = await this.getAMSClient(); + this.scenarioMarker.startScenario(TelemetryEvent.DownloadFileAttachment, { RequestId: this.requestId, ChatId: this.chatToken.chatId as string @@ -1718,6 +1762,20 @@ class OmnichannelChatSDK { if (this.liveChatVersion === LiveChatVersion.V2) { try { + if (this.isAMSClientAllowed === false) { + this.scenarioMarker.failScenario(TelemetryEvent.DownloadFileAttachment, { + RequestId: this.requestId, + ChatId: this.chatToken.chatId as string, + ExceptionDetails: "AMSClient is disabled" + }); + exceptionThrowers.throwFeatureDisabled(this.scenarioMarker, TelemetryEvent.DownloadFileAttachment, "Enable support for attachment upload and receive in the widget configuration."); + } + const amsClient = await this.getAMSClient(); + + if (amsClient === null || amsClient === undefined) { + throwAMSLoadFailure(this.scenarioMarker, TelemetryEvent.DownloadFileAttachment, "Attachment handler is null, no action can be performed"); + } + const response: any = await amsClient?.getViewStatus(fileMetadata); // eslint-disable-line @typescript-eslint/no-explicit-any const { view_location } = response; const viewResponse: any = await amsClient?.getView(fileMetadata, view_location); // eslint-disable-line @typescript-eslint/no-explicit-any @@ -2311,7 +2369,7 @@ class OmnichannelChatSDK { } } - private async setPrechatConfigurations(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin) : Promise { + private async setPrechatConfigurations(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin): Promise { const isPreChatEnabled = parseLowerCaseString(liveWSAndLiveChatEngJoin.msdyn_prechatenabled) === "true"; @@ -2322,7 +2380,7 @@ class OmnichannelChatSDK { } } - private async setDataMaskingConfiguration(dataMaskingConfig: DataMaskingInfo) : Promise { + private async setDataMaskingConfiguration(dataMaskingConfig: DataMaskingInfo): Promise { if (dataMaskingConfig.setting.msdyn_maskforcustomer) { if (dataMaskingConfig.dataMaskingRules) { @@ -2336,7 +2394,7 @@ class OmnichannelChatSDK { } } - private async setAuthSettingConfig(authSettings: AuthSettings) : Promise { + private async setAuthSettingConfig(authSettings: AuthSettings): Promise { if (authSettings) { this.authSettings = authSettings; @@ -2347,7 +2405,7 @@ class OmnichannelChatSDK { } } - private async setPersistentChatConfiguration(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin) : Promise { + private async setPersistentChatConfiguration(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin): Promise { const isChatReconnectEnabled = parseLowerCaseString(liveWSAndLiveChatEngJoin.msdyn_enablechatreconnect) === "true"; if (liveWSAndLiveChatEngJoin.msdyn_conversationmode?.toString() === ConversationMode.PersistentChat.toString()) { this.isPersistentChat = true; @@ -2358,17 +2416,17 @@ class OmnichannelChatSDK { } } - private async setLocaleIdConfiguration(chatWidgetLanguage: ChatWidgetLanguage) : Promise { + private async setLocaleIdConfiguration(chatWidgetLanguage: ChatWidgetLanguage): Promise { this.localeId = chatWidgetLanguage.msdyn_localeid || defaultLocaleId; } - private async setCallingOptionConfiguration(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin) : Promise { + private async setCallingOptionConfiguration(liveWSAndLiveChatEngJoin: LiveWSAndLiveChatEngJoin): Promise { const { msdyn_callingoptions } = liveWSAndLiveChatEngJoin; this.callingOption = msdyn_callingoptions?.trim().length > 0 ? Number(msdyn_callingoptions) : CallingOptionsOptionSetNumber.NoCalling; } - private async setLiveChatVersionConfiguration(liveChatVersion: number) : Promise { + private async setLiveChatVersionConfiguration(liveChatVersion: number): Promise { this.liveChatVersion = liveChatVersion || LiveChatVersion.V2; } @@ -2382,6 +2440,7 @@ class OmnichannelChatSDK { liveChatConfig = await this.OCClient.getChatConfig(this.requestId, bypassCache); this.liveChatConfig = liveChatConfig; + this.evaluateAMSAvailability(); this.buildConfigurations(liveChatConfig); /* istanbul ignore next */ this.debug && console.log(`[OmnichannelChatSDK][getChatConfig][liveChatVersion] ${this.liveChatVersion}`); @@ -2405,7 +2464,7 @@ class OmnichannelChatSDK { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - private async buildConfigurations(liveChatConfig: any) : Promise { + private async buildConfigurations(liveChatConfig: any): Promise { const { DataMaskingInfo: dataMaskingConfig, @@ -2468,7 +2527,7 @@ class OmnichannelChatSDK { } } - private async setAuthTokenProvider(provider: ChatSDKConfig["getAuthToken"], optionalParams: SetAuthTokenProviderOptionalParams = {}) : Promise { + private async setAuthTokenProvider(provider: ChatSDKConfig["getAuthToken"], optionalParams: SetAuthTokenProviderOptionalParams = {}): Promise { this.scenarioMarker.startScenario(TelemetryEvent.GetAuthToken); this.chatSDKConfig.getAuthToken = provider; @@ -2525,7 +2584,7 @@ class OmnichannelChatSDK { } } - private useCoreServicesOrgUrlIfNotSet() : void { + private useCoreServicesOrgUrlIfNotSet(): void { /* Perform orgUrl conversion to CoreServices only if orgUrl is not a CoreServices orgUrl. * Feature should be enabled by default. `createCoreServicesOrgUrlAtRuntime` set to `false` * would disable the orgUrl conversion and should only be used as fallback only. diff --git a/src/core/ChatSDKError.ts b/src/core/ChatSDKError.ts index 6015a74d..30b45836 100644 --- a/src/core/ChatSDKError.ts +++ b/src/core/ChatSDKError.ts @@ -1,3 +1,5 @@ +import ChatSDKExceptionDetails from "./ChatSDKExceptionDetails"; + /** * Enum of ChatSDK standard errors. * @@ -59,15 +61,19 @@ export enum ChatSDKErrorName { /** Send message failure */ ChatSDKSendMessageFailed = "ChatSDKSendMessageFailed", + AttachmentClientNotLoaded = "AttachmentClientNotLoaded", + } export class ChatSDKError { public message: ChatSDKErrorName; public httpResponseStatusCode: number | undefined; + public exceptionDetails: ChatSDKExceptionDetails | undefined; - constructor(message: ChatSDKErrorName, httpResponseStatusCode?: number) { + constructor(message: ChatSDKErrorName, httpResponseStatusCode?: number, exceptionDetails?: ChatSDKExceptionDetails) { this.message = message; this.httpResponseStatusCode = httpResponseStatusCode; + this.exceptionDetails = exceptionDetails; } toString(): string { diff --git a/src/utils/exceptionThrowers.ts b/src/utils/exceptionThrowers.ts index 7d687faf..da1106a7 100644 --- a/src/utils/exceptionThrowers.ts +++ b/src/utils/exceptionThrowers.ts @@ -12,12 +12,13 @@ * Stack trace should only be logged and not printed. */ -import { ChatSDKErrorName, ChatSDKError } from "../core/ChatSDKError"; +import { ChatSDKError, ChatSDKErrorName } from "../core/ChatSDKError"; + import ChatSDKExceptionDetails from "../core/ChatSDKExceptionDetails"; import ScenarioMarker from "../telemetry/ScenarioMarker"; import TelemetryEvent from "../telemetry/TelemetryEvent"; -export const throwChatSDKError = (chatSDKError: ChatSDKErrorName, e: unknown, scenarioMarker: ScenarioMarker, telemetryEvent: TelemetryEvent, telemetryData: {[key: string]: string} = {}, message = ""): void => { +export const throwChatSDKError = (chatSDKError: ChatSDKErrorName, e: unknown, scenarioMarker: ScenarioMarker, telemetryEvent: TelemetryEvent, telemetryData: { [key: string]: string } = {}, message?: string): void => { const exceptionDetails: ChatSDKExceptionDetails = { response: chatSDKError }; @@ -26,23 +27,28 @@ export const throwChatSDKError = (chatSDKError: ChatSDKErrorName, e: unknown, sc exceptionDetails.errorObject = `${e}`; } - scenarioMarker.failScenario(telemetryEvent, { - ...telemetryData, - ExceptionDetails: JSON.stringify(exceptionDetails) - }); - if (message) { exceptionDetails.message = message; console.error(message); } + scenarioMarker.failScenario(telemetryEvent, { + ...telemetryData, + ExceptionDetails: JSON.stringify(exceptionDetails) + }); + throw new ChatSDKError( chatSDKError, // eslint-disable-next-line @typescript-eslint/no-explicit-any - ((e as any)?.isAxiosError && (e as any)?.response?.status) ? (e as any)?.response?.status : undefined + ((e as any)?.isAxiosError && (e as any)?.response?.status) ? (e as any)?.response?.status : undefined, + exceptionDetails ); } +export const throwAMSLoadFailure = (scenarioMarker: ScenarioMarker, telemetryEvent: TelemetryEvent, message: string): void => { + throwChatSDKError(ChatSDKErrorName.AttachmentClientNotLoaded, undefined, scenarioMarker, telemetryEvent, {}, message); +}; + export const throwScriptLoadFailure = (e: unknown, scenarioMarker: ScenarioMarker, telemetryEvent: TelemetryEvent): void => { throwChatSDKError(ChatSDKErrorName.ScriptLoadFailure, e, scenarioMarker, telemetryEvent); };