@webex/contact-center 3.12.0-next.15 → 3.12.0-next.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/.sdd/manifest.json +887 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +62 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +52 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +382 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/contact-owner-change-refactor.md +78 -0
  19. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  20. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  21. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  22. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  23. package/ai-docs/patterns/testing-patterns.md +480 -0
  24. package/ai-docs/patterns/typescript-patterns.md +365 -0
  25. package/ai-docs/templates/README.md +102 -0
  26. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  27. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  28. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  29. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  30. package/ai-docs/templates/new-method/00-master.md +80 -0
  31. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  32. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  33. package/ai-docs/templates/new-method/03-tests.md +201 -0
  34. package/ai-docs/templates/new-method/04-validation.md +141 -0
  35. package/ai-docs/templates/new-service/00-master.md +109 -0
  36. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  37. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  38. package/ai-docs/templates/new-service/03-integration.md +178 -0
  39. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  40. package/ai-docs/templates/new-service/05-validation.md +145 -0
  41. package/dist/cc.js +1010 -47
  42. package/dist/cc.js.map +1 -1
  43. package/dist/config.js +13 -0
  44. package/dist/config.js.map +1 -1
  45. package/dist/constants.js +40 -3
  46. package/dist/constants.js.map +1 -1
  47. package/dist/index.js +54 -17
  48. package/dist/index.js.map +1 -1
  49. package/dist/metrics/MetricsManager.js +16 -0
  50. package/dist/metrics/MetricsManager.js.map +1 -1
  51. package/dist/metrics/behavioral-events.js +211 -0
  52. package/dist/metrics/behavioral-events.js.map +1 -1
  53. package/dist/metrics/constants.js +58 -4
  54. package/dist/metrics/constants.js.map +1 -1
  55. package/dist/services/AddressBook.js +18 -15
  56. package/dist/services/AddressBook.js.map +1 -1
  57. package/dist/services/AnswerCallOnWebexService.js +202 -0
  58. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  59. package/dist/services/ApiAiAssistant.js +351 -14
  60. package/dist/services/ApiAiAssistant.js.map +1 -1
  61. package/dist/services/EntryPoint.js +46 -68
  62. package/dist/services/EntryPoint.js.map +1 -1
  63. package/dist/services/Queue.js +27 -22
  64. package/dist/services/Queue.js.map +1 -1
  65. package/dist/services/UserPreference.js +427 -0
  66. package/dist/services/UserPreference.js.map +1 -0
  67. package/dist/services/WebexCrossClientService.js +225 -0
  68. package/dist/services/WebexCrossClientService.js.map +1 -0
  69. package/dist/services/WxAppTelephonyMercurySync.js +111 -0
  70. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  71. package/dist/services/config/Util.js +48 -48
  72. package/dist/services/config/Util.js.map +1 -1
  73. package/dist/services/config/constants.js +56 -78
  74. package/dist/services/config/constants.js.map +1 -1
  75. package/dist/services/config/index.js +100 -226
  76. package/dist/services/config/index.js.map +1 -1
  77. package/dist/services/config/types.js +97 -24
  78. package/dist/services/config/types.js.map +1 -1
  79. package/dist/services/core/Err.js.map +1 -1
  80. package/dist/services/core/Utils.js +111 -32
  81. package/dist/services/core/Utils.js.map +1 -1
  82. package/dist/services/core/WebexRequest.js +6 -2
  83. package/dist/services/core/WebexRequest.js.map +1 -1
  84. package/dist/services/core/aqm-reqs.js +28 -14
  85. package/dist/services/core/aqm-reqs.js.map +1 -1
  86. package/dist/services/core/types.js.map +1 -1
  87. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  88. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  89. package/dist/services/core/websocket/types.js.map +1 -1
  90. package/dist/services/index.js +1 -1
  91. package/dist/services/index.js.map +1 -1
  92. package/dist/services/task/Task.js +955 -0
  93. package/dist/services/task/Task.js.map +1 -0
  94. package/dist/services/task/TaskFactory.js +50 -0
  95. package/dist/services/task/TaskFactory.js.map +1 -0
  96. package/dist/services/task/TaskManager.js +1272 -523
  97. package/dist/services/task/TaskManager.js.map +1 -1
  98. package/dist/services/task/TaskUtils.js +221 -27
  99. package/dist/services/task/TaskUtils.js.map +1 -1
  100. package/dist/services/task/WebexCallingUtils.js +70 -0
  101. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  102. package/dist/services/task/constants.js +21 -2
  103. package/dist/services/task/constants.js.map +1 -1
  104. package/dist/services/task/contact.js +29 -0
  105. package/dist/services/task/contact.js.map +1 -1
  106. package/dist/services/task/dialer.js +78 -0
  107. package/dist/services/task/dialer.js.map +1 -1
  108. package/dist/services/task/digital/Digital.js +78 -0
  109. package/dist/services/task/digital/Digital.js.map +1 -0
  110. package/dist/services/task/state-machine/TaskStateMachine.js +982 -0
  111. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  112. package/dist/services/task/state-machine/actions.js +572 -0
  113. package/dist/services/task/state-machine/actions.js.map +1 -0
  114. package/dist/services/task/state-machine/constants.js +161 -0
  115. package/dist/services/task/state-machine/constants.js.map +1 -0
  116. package/dist/services/task/state-machine/guards.js +379 -0
  117. package/dist/services/task/state-machine/guards.js.map +1 -0
  118. package/dist/services/task/state-machine/index.js +53 -0
  119. package/dist/services/task/state-machine/index.js.map +1 -0
  120. package/dist/services/task/state-machine/types.js +54 -0
  121. package/dist/services/task/state-machine/types.js.map +1 -0
  122. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  123. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  124. package/dist/services/task/taskDataNormalizer.js +99 -0
  125. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  126. package/dist/services/task/types.js +259 -5
  127. package/dist/services/task/types.js.map +1 -1
  128. package/dist/services/task/voice/Voice.js +1504 -0
  129. package/dist/services/task/voice/Voice.js.map +1 -0
  130. package/dist/services/task/voice/WebRTC.js +152 -0
  131. package/dist/services/task/voice/WebRTC.js.map +1 -0
  132. package/dist/services/task/voice/wxAppOfferObservability.js +145 -0
  133. package/dist/services/task/voice/wxAppOfferObservability.js.map +1 -0
  134. package/dist/services/task/voice/wxAppVoiceMethods.js +395 -0
  135. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  136. package/dist/services/wxAppDiagnosticLogging.js +159 -0
  137. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  138. package/dist/services/wxAppTelephonyUtils.js +19 -0
  139. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  140. package/dist/types/cc.d.ts +196 -9
  141. package/dist/types/config.d.ts +13 -0
  142. package/dist/types/constants.d.ts +38 -1
  143. package/dist/types/index.d.ts +54 -20
  144. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  145. package/dist/types/metrics/constants.d.ts +52 -1
  146. package/dist/types/services/AddressBook.d.ts +2 -1
  147. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  148. package/dist/types/services/ApiAiAssistant.d.ts +58 -5
  149. package/dist/types/services/EntryPoint.d.ts +7 -5
  150. package/dist/types/services/Queue.d.ts +5 -3
  151. package/dist/types/services/UserPreference.d.ts +118 -0
  152. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  153. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  154. package/dist/types/services/config/Util.d.ts +4 -8
  155. package/dist/types/services/config/constants.d.ts +49 -76
  156. package/dist/types/services/config/index.d.ts +16 -64
  157. package/dist/types/services/config/types.d.ts +248 -114
  158. package/dist/types/services/core/Err.d.ts +6 -0
  159. package/dist/types/services/core/Utils.d.ts +35 -13
  160. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  161. package/dist/types/services/core/types.d.ts +2 -0
  162. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  163. package/dist/types/services/core/websocket/types.d.ts +1 -1
  164. package/dist/types/services/index.d.ts +1 -1
  165. package/dist/types/services/task/Task.d.ts +186 -0
  166. package/dist/types/services/task/TaskFactory.d.ts +14 -0
  167. package/dist/types/services/task/TaskUtils.d.ts +54 -2
  168. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  169. package/dist/types/services/task/constants.d.ts +19 -0
  170. package/dist/types/services/task/contact.d.ts +4 -0
  171. package/dist/types/services/task/dialer.d.ts +30 -0
  172. package/dist/types/services/task/digital/Digital.d.ts +23 -0
  173. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
  174. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  175. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  176. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  177. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  178. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  179. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  180. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  181. package/dist/types/services/task/types.d.ts +790 -66
  182. package/dist/types/services/task/voice/Voice.d.ts +241 -0
  183. package/dist/types/services/task/voice/WebRTC.d.ts +54 -0
  184. package/dist/types/services/task/voice/wxAppOfferObservability.d.ts +39 -0
  185. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +68 -0
  186. package/dist/types/services/wxAppDiagnosticLogging.d.ts +63 -0
  187. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  188. package/dist/types/types.d.ts +213 -11
  189. package/dist/types/utils/PageCache.d.ts +20 -3
  190. package/dist/types/webex.d.ts +1 -0
  191. package/dist/types.js +168 -6
  192. package/dist/types.js.map +1 -1
  193. package/dist/utils/PageCache.js +19 -5
  194. package/dist/utils/PageCache.js.map +1 -1
  195. package/dist/webex.js +22 -2
  196. package/dist/webex.js.map +1 -1
  197. package/package.json +16 -12
  198. package/src/cc.ts +1338 -121
  199. package/src/config.ts +13 -0
  200. package/src/constants.ts +41 -1
  201. package/src/index.ts +62 -15
  202. package/src/metrics/MetricsManager.ts +16 -0
  203. package/src/metrics/ai-docs/AGENTS.md +350 -0
  204. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  205. package/src/metrics/ai-docs/metrics-spec.md +971 -0
  206. package/src/metrics/behavioral-events.ts +218 -0
  207. package/src/metrics/constants.ts +63 -4
  208. package/src/services/AddressBook.ts +17 -6
  209. package/src/services/AnswerCallOnWebexService.ts +239 -0
  210. package/src/services/ApiAiAssistant.ts +470 -15
  211. package/src/services/EntryPoint.ts +59 -60
  212. package/src/services/Queue.ts +29 -12
  213. package/src/services/UserPreference.ts +509 -0
  214. package/src/services/WebexCrossClientService.ts +298 -0
  215. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  216. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  217. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  218. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  219. package/src/services/ai-docs/AGENTS.md +386 -0
  220. package/src/services/ai-docs/services-spec.md +505 -0
  221. package/src/services/config/Util.ts +54 -84
  222. package/src/services/config/ai-docs/AGENTS.md +250 -0
  223. package/src/services/config/ai-docs/ARCHITECTURE.md +413 -0
  224. package/src/services/config/ai-docs/config-spec.md +669 -0
  225. package/src/services/config/constants.ts +63 -85
  226. package/src/services/config/index.ts +116 -277
  227. package/src/services/config/types.ts +233 -125
  228. package/src/services/core/Err.ts +3 -0
  229. package/src/services/core/Utils.ts +127 -37
  230. package/src/services/core/WebexRequest.ts +3 -1
  231. package/src/services/core/ai-docs/AGENTS.md +381 -0
  232. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  233. package/src/services/core/ai-docs/core-spec.md +787 -0
  234. package/src/services/core/aqm-reqs.ts +30 -15
  235. package/src/services/core/types.ts +33 -1
  236. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  237. package/src/services/core/websocket/types.ts +1 -1
  238. package/src/services/index.ts +1 -1
  239. package/src/services/task/Task.ts +1211 -0
  240. package/src/services/task/TaskFactory.ts +82 -0
  241. package/src/services/task/TaskManager.ts +1584 -643
  242. package/src/services/task/TaskUtils.ts +316 -25
  243. package/src/services/task/WebexCallingUtils.ts +136 -0
  244. package/src/services/task/ai-docs/AGENTS.md +457 -0
  245. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  246. package/src/services/task/ai-docs/task-spec.md +1501 -0
  247. package/src/services/task/constants.ts +20 -0
  248. package/src/services/task/contact.ts +30 -0
  249. package/src/services/task/dialer.ts +80 -0
  250. package/src/services/task/digital/Digital.ts +102 -0
  251. package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
  252. package/src/services/task/state-machine/actions.ts +741 -0
  253. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  254. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
  255. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
  256. package/src/services/task/state-machine/constants.ts +172 -0
  257. package/src/services/task/state-machine/guards.ts +442 -0
  258. package/src/services/task/state-machine/index.ts +28 -0
  259. package/src/services/task/state-machine/types.ts +258 -0
  260. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  261. package/src/services/task/taskDataNormalizer.ts +137 -0
  262. package/src/services/task/types.ts +974 -70
  263. package/src/services/task/voice/Voice.ts +1878 -0
  264. package/src/services/task/voice/WebRTC.ts +194 -0
  265. package/src/services/task/voice/wxAppOfferObservability.ts +204 -0
  266. package/src/services/task/voice/wxAppVoiceMethods.ts +575 -0
  267. package/src/services/wxAppDiagnosticLogging.ts +286 -0
  268. package/src/services/wxAppTelephonyUtils.ts +14 -0
  269. package/src/types.ts +272 -13
  270. package/src/utils/AGENTS.md +289 -0
  271. package/src/utils/PageCache.ts +38 -5
  272. package/src/utils/ai-docs/utils-spec.md +391 -0
  273. package/src/webex.js +10 -0
  274. package/test/unit/fixtures/aiSummaryTestUtils.ts +40 -0
  275. package/test/unit/spec/cc.ts +3705 -150
  276. package/test/unit/spec/index.ts +885 -0
  277. package/test/unit/spec/logger-proxy.ts +70 -0
  278. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  279. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  280. package/test/unit/spec/services/AddressBook.ts +37 -6
  281. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  282. package/test/unit/spec/services/ApiAiAssistant.ts +429 -23
  283. package/test/unit/spec/services/EntryPoint.ts +87 -40
  284. package/test/unit/spec/services/Queue.ts +123 -12
  285. package/test/unit/spec/services/UserPreference.ts +401 -0
  286. package/test/unit/spec/services/WebCallingService.ts +7 -1
  287. package/test/unit/spec/services/WebexCrossClientService.ts +509 -0
  288. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  289. package/test/unit/spec/services/config/Util.ts +501 -0
  290. package/test/unit/spec/services/config/index.ts +317 -547
  291. package/test/unit/spec/services/core/Utils.ts +425 -8
  292. package/test/unit/spec/services/core/WebexRequest.ts +8 -7
  293. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  294. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  295. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  296. package/test/unit/spec/services/task/Task.ts +2723 -0
  297. package/test/unit/spec/services/task/TaskFactory.ts +116 -0
  298. package/test/unit/spec/services/task/TaskManager.ts +4781 -1585
  299. package/test/unit/spec/services/task/TaskUtils.ts +307 -0
  300. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  301. package/test/unit/spec/services/task/contact.ts +33 -0
  302. package/test/unit/spec/services/task/dialer.ts +190 -0
  303. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  304. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
  305. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  306. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  307. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  308. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  309. package/test/unit/spec/services/task/voice/Voice.ts +2355 -0
  310. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  311. package/test/unit/spec/services/task/voice/wxAppOfferObservability.ts +361 -0
  312. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +719 -0
  313. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +179 -0
  314. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  315. package/typedoc.md +1 -1
  316. package/umd/contact-center.min.js +2 -2
  317. package/umd/contact-center.min.js.map +1 -1
  318. package/dist/services/task/index.js +0 -1530
  319. package/dist/services/task/index.js.map +0 -1
  320. package/dist/types/services/task/index.d.ts +0 -650
  321. package/src/services/task/index.ts +0 -1806
  322. package/test/unit/spec/services/task/index.ts +0 -2205
@@ -6,6 +6,7 @@ import {CONFIG_FILE_NAME} from '../../../../../src/constants';
6
6
  import MockWebex from '@webex/test-helper-mock-webex';
7
7
  import LoggerProxy from '../../../../../src/logger-proxy';
8
8
  import * as util from '../../../../../src/services/config/Util';
9
+ import {DEFAULT_AUXCODE_ATTRIBUTES} from '../../../../../src/services/config/constants';
9
10
 
10
11
  jest.mock('../../../../../src/logger-proxy', () => ({
11
12
  __esModule: true,
@@ -44,36 +45,38 @@ describe('AgentConfigService', () => {
44
45
  jest.clearAllMocks();
45
46
  });
46
47
 
47
- describe('getUserUsingCI', () => {
48
- it('should return AgentResponse on success', async () => {
48
+ describe('getOrgDesktopLoginConfig', () => {
49
+ it('should return OrgDesktopLoginResponse on success', async () => {
49
50
  const mockResponse = {
50
51
  statusCode: 200,
51
52
  body: {
52
- firstName: 'John',
53
- lastName: 'Doe',
54
- agentProfileId: 'profile123',
55
- email: 'john.doe@example.com',
56
- teamIds: ['123', '456'],
53
+ organization: {tenantId: 'tenant123', timezone: 'America/New_York'},
54
+ organizationSetting: {webRtcEnabled: true},
55
+ tenantConfiguration: {forceDefaultDn: false},
56
+ urlMappings: {},
57
+ aiFeature: {realtimeTranscripts: {enable: false}},
57
58
  },
58
59
  };
59
60
  (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
60
61
 
61
- const result = await agentConfigService.getUserUsingCI(mockOrgId, mockAgentId);
62
+ const result = await agentConfigService.getOrgDesktopLoginConfig(mockOrgId);
62
63
 
63
64
  expect(mockWebexRequest.request).toHaveBeenCalledWith({
64
65
  service: mockWccAPIURL,
65
- resource: `organization/${mockOrgId}/user/by-ci-user-id/${mockAgentId}`,
66
+ resource: `organization/${mockOrgId}/desktop-login`,
66
67
  method: 'GET',
67
68
  });
68
69
  expect(result).toEqual(mockResponse.body);
69
-
70
- expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching user data using CI', {
71
- module: CONFIG_FILE_NAME,
72
- method: 'getUserUsingCI',
73
- });
74
- expect(LoggerProxy.log).toHaveBeenCalledWith('getUserUsingCI api success.', {
70
+ expect(LoggerProxy.info).toHaveBeenCalledWith(
71
+ 'Fetching organization desktop-login configuration',
72
+ {
73
+ module: CONFIG_FILE_NAME,
74
+ method: 'getOrgDesktopLoginConfig',
75
+ }
76
+ );
77
+ expect(LoggerProxy.log).toHaveBeenCalledWith('getOrgDesktopLoginConfig api success.', {
75
78
  module: CONFIG_FILE_NAME,
76
- method: 'getUserUsingCI',
79
+ method: 'getOrgDesktopLoginConfig',
77
80
  });
78
81
  });
79
82
 
@@ -81,57 +84,58 @@ describe('AgentConfigService', () => {
81
84
  const mockError = new Error('API call failed');
82
85
  (mockWebexRequest.request as jest.Mock).mockRejectedValue(mockError);
83
86
 
84
- await expect(agentConfigService.getUserUsingCI(mockOrgId, mockAgentId)).rejects.toThrow(
87
+ await expect(agentConfigService.getOrgDesktopLoginConfig(mockOrgId)).rejects.toThrow(
85
88
  'API call failed'
86
89
  );
90
+ expect(LoggerProxy.error).toHaveBeenCalledWith(
91
+ 'getOrgDesktopLoginConfig API call failed with Error: API call failed',
92
+ {module: CONFIG_FILE_NAME, method: 'getOrgDesktopLoginConfig'}
93
+ );
87
94
  });
88
95
 
89
- it('should throw an error if the getUserUsingCI call fails with other than 200', async () => {
90
- const mockResponse = {
91
- statusCode: 400,
92
- };
93
- (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
96
+ it('should throw an error if the call fails with other than 200', async () => {
97
+ (mockWebexRequest.request as jest.Mock).mockResolvedValue({statusCode: 403});
94
98
 
95
- try {
96
- await agentConfigService.getUserUsingCI(mockOrgId, mockAgentId);
97
- } catch (error) {
98
- expect(error).toEqual(new Error(`API call failed with ${mockResponse.statusCode}`));
99
- }
99
+ await expect(agentConfigService.getOrgDesktopLoginConfig(mockOrgId)).rejects.toThrow(
100
+ 'API call failed with 403'
101
+ );
100
102
  });
101
103
  });
102
104
 
103
- describe('getDesktopProfileById', () => {
104
- const desktopProfileId = 'profile123';
105
-
106
- it('should return DesktopProfileResponse on success', async () => {
105
+ describe('getUserDesktopLoginConfig', () => {
106
+ it('should return UserDesktopLoginResponse on success', async () => {
107
107
  const mockResponse = {
108
108
  statusCode: 200,
109
109
  body: {
110
- loginVoiceOptions: ['option1', 'option2'],
111
- accessWrapUpCode: 'ALL',
112
- accessIdleCode: 'SPECIFIC',
113
- wrapUpCodes: ['code1', 'code2'],
114
- idleCodes: ['idle1', 'idle2'],
110
+ user: {
111
+ ciUserId: mockAgentId,
112
+ dbId: 'db123',
113
+ firstName: 'John',
114
+ lastName: 'Doe',
115
+ agentProfileId: 'profile123',
116
+ email: 'john.doe@example.com',
117
+ siteId: 'site123',
118
+ },
119
+ agentProfile: {accessIdleCode: 'ALL', dialPlanEnabled: true},
115
120
  },
116
121
  };
117
122
  (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
118
123
 
119
- const result = await agentConfigService.getDesktopProfileById(mockOrgId, desktopProfileId);
124
+ const result = await agentConfigService.getUserDesktopLoginConfig(mockOrgId, mockAgentId);
120
125
 
121
126
  expect(mockWebexRequest.request).toHaveBeenCalledWith({
122
127
  service: mockWccAPIURL,
123
- resource: `organization/${mockOrgId}/agent-profile/${desktopProfileId}`,
128
+ resource: `organization/${mockOrgId}/v2/user/by-ci-user-id/${mockAgentId}/desktop-login`,
124
129
  method: 'GET',
125
130
  });
126
131
  expect(result).toEqual(mockResponse.body);
127
-
128
- expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching desktop profile', {
132
+ expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching user desktop-login configuration', {
129
133
  module: CONFIG_FILE_NAME,
130
- method: 'getDesktopProfileById',
134
+ method: 'getUserDesktopLoginConfig',
131
135
  });
132
- expect(LoggerProxy.log).toHaveBeenCalledWith('getDesktopProfileById api success.', {
136
+ expect(LoggerProxy.log).toHaveBeenCalledWith('getUserDesktopLoginConfig api success.', {
133
137
  module: CONFIG_FILE_NAME,
134
- method: 'getDesktopProfileById',
138
+ method: 'getUserDesktopLoginConfig',
135
139
  });
136
140
  });
137
141
 
@@ -139,51 +143,47 @@ describe('AgentConfigService', () => {
139
143
  const mockError = new Error('API call failed');
140
144
  (mockWebexRequest.request as jest.Mock).mockRejectedValue(mockError);
141
145
 
142
- try {
143
- await agentConfigService.getDesktopProfileById(mockOrgId, desktopProfileId);
144
- } catch (error) {
145
- expect(error).toEqual(mockError);
146
- }
146
+ await expect(
147
+ agentConfigService.getUserDesktopLoginConfig(mockOrgId, mockAgentId)
148
+ ).rejects.toThrow('API call failed');
149
+ expect(LoggerProxy.error).toHaveBeenCalledWith(
150
+ 'getUserDesktopLoginConfig API call failed with Error: API call failed',
151
+ {module: CONFIG_FILE_NAME, method: 'getUserDesktopLoginConfig'}
152
+ );
147
153
  });
148
154
 
149
- it('should throw an error if the getDesktopProfileById call fails with other than 200', async () => {
150
- const mockResponse = {
151
- statusCode: 400,
152
- };
153
- (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
155
+ it.each([403, 404])('should throw an error if the call fails with %i', async (statusCode) => {
156
+ (mockWebexRequest.request as jest.Mock).mockResolvedValue({statusCode});
154
157
 
155
- try {
156
- await agentConfigService.getDesktopProfileById(mockOrgId, desktopProfileId);
157
- } catch (error) {
158
- expect(error).toEqual(new Error(`API call failed with ${mockResponse.statusCode}`));
159
- }
158
+ await expect(
159
+ agentConfigService.getUserDesktopLoginConfig(mockOrgId, mockAgentId)
160
+ ).rejects.toThrow(`API call failed with ${statusCode}`);
160
161
  });
161
162
  });
162
163
 
163
164
  describe('getListOfTeams', () => {
164
165
  const page = 0;
165
166
  const pageSize = 10;
166
- const filter: string[] = ['123'];
167
+ const userDbId = 'db123';
167
168
 
168
- it('should return team on success', async () => {
169
+ it('should filter by unquoted userId and return teams on success', async () => {
169
170
  const mockResponse = {
170
171
  statusCode: 200,
171
- body: [
172
- {id: '123', name: 'Team 1'},
173
- {id: '12345', name: 'Team 2'},
174
- ],
172
+ body: {
173
+ data: [{id: '123', name: 'Team 1', multiMediaProfileId: 'mm1', siteName: 'Site 1'}],
174
+ meta: {totalPages: 1},
175
+ },
175
176
  };
176
177
  (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
177
178
 
178
- const result = await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, filter);
179
+ const result = await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, userDbId);
179
180
 
180
181
  expect(mockWebexRequest.request).toHaveBeenCalledWith({
181
182
  service: mockWccAPIURL,
182
- resource: `organization/${mockOrgId}/v2/team?page=${page}&pageSize=${pageSize}&filter=id=in=(${filter})`,
183
+ resource: `organization/${mockOrgId}/v2/team?page=${page}&pageSize=${pageSize}&agentView=true&filter=userId==${userDbId}`,
183
184
  method: 'GET',
184
185
  });
185
186
  expect(result).toEqual(mockResponse.body);
186
-
187
187
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching list of teams', {
188
188
  module: CONFIG_FILE_NAME,
189
189
  method: 'getListOfTeams',
@@ -199,7 +199,7 @@ describe('AgentConfigService', () => {
199
199
  (mockWebexRequest.request as jest.Mock).mockRejectedValue(mockError);
200
200
 
201
201
  try {
202
- await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, filter);
202
+ await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, userDbId);
203
203
  } catch (error) {
204
204
  expect(error).toEqual(mockError);
205
205
  }
@@ -212,7 +212,7 @@ describe('AgentConfigService', () => {
212
212
  (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockResponse);
213
213
 
214
214
  try {
215
- await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, filter);
215
+ await agentConfigService.getListOfTeams(mockOrgId, page, pageSize, userDbId);
216
216
  } catch (error) {
217
217
  expect(error).toEqual(new Error(`API call failed with ${mockResponse.statusCode}`));
218
218
  }
@@ -267,7 +267,6 @@ describe('AgentConfigService', () => {
267
267
  method: 'GET',
268
268
  });
269
269
  expect(result).toEqual(mockResponse.body);
270
-
271
270
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching list of aux codes', {
272
271
  module: CONFIG_FILE_NAME,
273
272
  method: 'getListOfAuxCodes',
@@ -302,237 +301,6 @@ describe('AgentConfigService', () => {
302
301
  });
303
302
  });
304
303
 
305
- describe('getOrgInfo', () => {
306
- it('should return organization info successfully', async () => {
307
- const mockResponse = {
308
- statusCode: 200,
309
- body: {
310
- id: 'org123',
311
- name: 'Organization 123',
312
- description: 'Description',
313
- type: 'type',
314
- status: 'status',
315
- created: '2021-01-01',
316
- },
317
- };
318
- mockWebexRequest.request.mockResolvedValue(mockResponse);
319
-
320
- const result = await agentConfigService.getOrgInfo(mockOrgId);
321
- expect(result).toEqual(mockResponse.body);
322
- expect(LoggerProxy.log).toHaveBeenCalledWith('getOrgInfo api success.', {
323
- module: CONFIG_FILE_NAME,
324
- method: 'getOrgInfo',
325
- });
326
- });
327
-
328
- it('should throw an error if API call returns non-200 status code', async () => {
329
- const mockError = {statusCode: 500};
330
- mockWebexRequest.request.mockResolvedValue(mockError);
331
-
332
- await expect(agentConfigService.getOrgInfo(mockOrgId)).rejects.toThrow(
333
- 'API call failed with 500'
334
- );
335
- expect(LoggerProxy.error).toHaveBeenCalledWith(
336
- 'getOrgInfo API call failed with Error: API call failed with 500',
337
- {module: CONFIG_FILE_NAME, method: 'getOrgInfo'}
338
- );
339
- });
340
-
341
- it('should handle network errors gracefully', async () => {
342
- const networkError = new Error('Network Error');
343
- mockWebexRequest.request.mockRejectedValue(networkError);
344
-
345
- await expect(agentConfigService.getOrgInfo(mockOrgId)).rejects.toThrow('Network Error');
346
- expect(LoggerProxy.error).toHaveBeenCalledWith(
347
- 'getOrgInfo API call failed with Error: Network Error',
348
- {module: CONFIG_FILE_NAME, method: 'getOrgInfo'}
349
- );
350
- });
351
-
352
- it('should handle timeout errors gracefully', async () => {
353
- const timeoutError = new Error('Timeout Error');
354
- mockWebexRequest.request.mockRejectedValue(timeoutError);
355
-
356
- await expect(agentConfigService.getOrgInfo(mockOrgId)).rejects.toThrow('Timeout Error');
357
- expect(LoggerProxy.error).toHaveBeenCalledWith(
358
- 'getOrgInfo API call failed with Error: Timeout Error',
359
- {module: CONFIG_FILE_NAME, method: 'getOrgInfo'}
360
- );
361
- });
362
- });
363
-
364
- describe('getOrganizationSetting', () => {
365
- it('should return organization settings successfully', async () => {
366
- const mockResponse = {statusCode: 200, body: {data: [{}]}}; // Adjust data accordingly
367
- mockWebexRequest.request.mockResolvedValue(mockResponse);
368
-
369
- const result = await agentConfigService.getOrganizationSetting();
370
- expect(result).toEqual(mockResponse.body.data[0]);
371
- expect(LoggerProxy.log).toHaveBeenCalledWith('getOrganizationSetting api success.', {
372
- module: CONFIG_FILE_NAME,
373
- method: 'getOrganizationSetting',
374
- });
375
- });
376
-
377
- it('should throw an error if API call returns non-200 status code', async () => {
378
- const mockError = {statusCode: 500};
379
- mockWebexRequest.request.mockResolvedValue(mockError);
380
-
381
- await expect(agentConfigService.getOrganizationSetting(mockOrgId)).rejects.toThrow(
382
- 'API call failed with 500'
383
- );
384
- expect(LoggerProxy.error).toHaveBeenCalledWith(
385
- 'getOrganizationSetting API call failed with Error: API call failed with 500',
386
- {module: CONFIG_FILE_NAME, method: 'getOrganizationSetting'}
387
- );
388
- });
389
-
390
- it('should handle network errors gracefully', async () => {
391
- const networkError = new Error('Network Error');
392
- mockWebexRequest.request.mockRejectedValue(networkError);
393
-
394
- await expect(agentConfigService.getOrganizationSetting(mockOrgId)).rejects.toThrow(
395
- 'Network Error'
396
- );
397
- expect(LoggerProxy.error).toHaveBeenCalledWith(
398
- 'getOrganizationSetting API call failed with Error: Network Error',
399
- {module: CONFIG_FILE_NAME, method: 'getOrganizationSetting'}
400
- );
401
- });
402
-
403
- it('should handle timeout errors gracefully', async () => {
404
- const timeoutError = new Error('Timeout Error');
405
- mockWebexRequest.request.mockRejectedValue(timeoutError);
406
-
407
- await expect(agentConfigService.getOrganizationSetting(mockOrgId)).rejects.toThrow(
408
- 'Timeout Error'
409
- );
410
- expect(LoggerProxy.error).toHaveBeenCalledWith(
411
- 'getOrganizationSetting API call failed with Error: Timeout Error',
412
- {module: CONFIG_FILE_NAME, method: 'getOrganizationSetting'}
413
- );
414
- });
415
- });
416
-
417
- describe('getTenantData', () => {
418
- it('should return tenant successfully', async () => {
419
- const mockResponse = {statusCode: 200, body: {data: [{}]}}; // Adjust data accordingly
420
- mockWebexRequest.request.mockResolvedValue(mockResponse);
421
-
422
- const result = await agentConfigService.getTenantData(mockOrgId);
423
- expect(result).toEqual(mockResponse.body.data[0]);
424
- expect(LoggerProxy.log).toHaveBeenCalledWith('getTenantData api success.', {
425
- module: CONFIG_FILE_NAME,
426
- method: 'getTenantData',
427
- });
428
- });
429
-
430
- it('should throw an error if API call returns non-200 status code', async () => {
431
- const mockError = {statusCode: 500};
432
- mockWebexRequest.request.mockResolvedValue(mockError);
433
-
434
- await expect(agentConfigService.getTenantData(mockOrgId)).rejects.toThrow(
435
- 'API call failed with 500'
436
- );
437
- expect(LoggerProxy.error).toHaveBeenCalledWith(
438
- 'getTenantData API call failed with Error: API call failed with 500',
439
- {module: CONFIG_FILE_NAME, method: 'getTenantData'}
440
- );
441
- });
442
-
443
- it('should handle network errors gracefully', async () => {
444
- const networkError = new Error('Network Error');
445
- mockWebexRequest.request.mockRejectedValue(networkError);
446
-
447
- await expect(agentConfigService.getTenantData(mockOrgId)).rejects.toThrow('Network Error');
448
- expect(LoggerProxy.error).toHaveBeenCalledWith(
449
- 'getTenantData API call failed with Error: Network Error',
450
- {module: CONFIG_FILE_NAME, method: 'getTenantData'}
451
- );
452
- });
453
- });
454
-
455
- describe(`getURLMapping`, () => {
456
- it('should return URL mapping successfully', async () => {
457
- const mockResponse = {statusCode: 200, body: {data: {}}}; // Adjust data accordingly
458
- mockWebexRequest.request.mockResolvedValue(mockResponse);
459
-
460
- const result = await agentConfigService.getURLMapping(mockOrgId);
461
- expect(result).toEqual(mockResponse.body.data);
462
- expect(LoggerProxy.log).toHaveBeenCalledWith('getURLMapping api success.', {
463
- module: CONFIG_FILE_NAME,
464
- method: 'getURLMapping',
465
- });
466
- });
467
-
468
- it('should throw an error if API call returns non-200 status code', async () => {
469
- const mockError = {statusCode: 500};
470
- mockWebexRequest.request.mockResolvedValue(mockError);
471
-
472
- await expect(agentConfigService.getURLMapping(mockOrgId)).rejects.toThrow(
473
- 'API call failed with 500'
474
- );
475
- expect(LoggerProxy.error).toHaveBeenCalledWith(
476
- 'getURLMapping API call failed with Error: API call failed with 500',
477
- {module: CONFIG_FILE_NAME, method: 'getURLMapping'}
478
- );
479
- });
480
-
481
- it('should handle network errors gracefully', async () => {
482
- const networkError = new Error('Network Error');
483
- mockWebexRequest.request.mockRejectedValue(networkError);
484
-
485
- await expect(agentConfigService.getURLMapping(mockOrgId)).rejects.toThrow('Network Error');
486
- expect(LoggerProxy.error).toHaveBeenCalledWith(
487
- 'getURLMapping API call failed with Error: Network Error',
488
- {module: CONFIG_FILE_NAME, method: 'getURLMapping'}
489
- );
490
- });
491
- });
492
-
493
- describe('getAIFeatureFlags', () => {
494
- it('should return AI feature flags successfully', async () => {
495
- const mockResponse = {
496
- statusCode: 200,
497
- body: {
498
- realtimeTranscripts: {enable: true},
499
- },
500
- };
501
- mockWebexRequest.request.mockResolvedValue(mockResponse);
502
-
503
- const result = await agentConfigService.getAIFeatureFlags(mockOrgId);
504
- expect(result).toEqual(mockResponse.body);
505
- expect(LoggerProxy.log).toHaveBeenCalledWith('getAIFeatureFlags api success.', {
506
- module: CONFIG_FILE_NAME,
507
- method: 'getAIFeatureFlags',
508
- });
509
- });
510
-
511
- it('should throw an error if API call returns non-200 status code', async () => {
512
- const mockError = {statusCode: 500};
513
- mockWebexRequest.request.mockResolvedValue(mockError);
514
-
515
- await expect(agentConfigService.getAIFeatureFlags(mockOrgId)).rejects.toThrow(
516
- 'API call failed with 500'
517
- );
518
- expect(LoggerProxy.error).toHaveBeenCalledWith(
519
- 'getAIFeatureFlags API call failed with Error: API call failed with 500',
520
- {module: CONFIG_FILE_NAME, method: 'getAIFeatureFlags'}
521
- );
522
- });
523
-
524
- it('should handle network errors gracefully', async () => {
525
- const networkError = new Error('Network Error');
526
- mockWebexRequest.request.mockRejectedValue(networkError);
527
-
528
- await expect(agentConfigService.getAIFeatureFlags(mockOrgId)).rejects.toThrow('Network Error');
529
- expect(LoggerProxy.error).toHaveBeenCalledWith(
530
- 'getAIFeatureFlags API call failed with Error: Network Error',
531
- {module: CONFIG_FILE_NAME, method: 'getAIFeatureFlags'}
532
- );
533
- });
534
- });
535
-
536
304
  describe(`getDialPlanData`, () => {
537
305
  it('should return dial plan data successfully', async () => {
538
306
  const mockResponse = {statusCode: 200, body: {data: {}}}; // Adjust data accordingly
@@ -572,10 +340,10 @@ describe('AgentConfigService', () => {
572
340
  });
573
341
 
574
342
  describe(`getAllTeams`, () => {
343
+ const userDbId = 'db123';
344
+
575
345
  it('should return all teams successfully', async () => {
576
346
  const pageSize = 10;
577
- const filter = ['filter1'];
578
- const attributes = ['attribute1'];
579
347
 
580
348
  const mockResponseFirst = {
581
349
  body: {
@@ -594,7 +362,7 @@ describe('AgentConfigService', () => {
594
362
  .mockResolvedValueOnce(mockResponseFirst)
595
363
  .mockResolvedValue(mockResponseOther);
596
364
 
597
- const result = await agentConfigService.getAllTeams(mockOrgId, pageSize, filter, attributes);
365
+ const result = await agentConfigService.getAllTeams(mockOrgId, pageSize, userDbId);
598
366
  expect(result).toEqual([
599
367
  ...mockResponseFirst.body.data,
600
368
  ...mockResponseOther.body.data,
@@ -620,15 +388,13 @@ describe('AgentConfigService', () => {
620
388
 
621
389
  it('should throw an error if API call returns non-200 status code', async () => {
622
390
  const pageSize = 10;
623
- const filter = ['filter1'];
624
- const attributes = ['attribute1'];
625
391
 
626
392
  const mockError = {statusCode: 500};
627
393
  (mockWebexRequest.request as jest.Mock).mockResolvedValue(mockError);
628
394
 
629
- await expect(
630
- agentConfigService.getAllTeams(mockOrgId, pageSize, filter, attributes)
631
- ).rejects.toThrow('API call failed with 500');
395
+ await expect(agentConfigService.getAllTeams(mockOrgId, pageSize, userDbId)).rejects.toThrow(
396
+ 'API call failed with 500'
397
+ );
632
398
  expect(LoggerProxy.error).toHaveBeenCalledWith(
633
399
  'getListOfTeams API call failed with Error: API call failed with 500',
634
400
  {module: CONFIG_FILE_NAME, method: 'getListOfTeams'}
@@ -709,76 +475,90 @@ describe('AgentConfigService', () => {
709
475
  });
710
476
  });
711
477
 
712
- describe('getAgentConfig', () => {
713
- beforeEach(() => {
714
- jest.clearAllMocks();
478
+ describe('getWellbeingBreakIdleCode', () => {
479
+ it('uses the system-code query and finds the exact code across pages', async () => {
480
+ (mockWebexRequest.request as jest.Mock)
481
+ .mockResolvedValueOnce({
482
+ statusCode: 200,
483
+ body: {
484
+ data: [
485
+ {id: 'other', name: 'Other', active: true, isSystemCode: true, defaultCode: false},
486
+ ],
487
+ meta: {totalPages: 2},
488
+ },
489
+ })
490
+ .mockResolvedValueOnce({
491
+ statusCode: 200,
492
+ body: {
493
+ data: [
494
+ {
495
+ id: 'wellbeing-code',
496
+ name: 'WellbeingBreak',
497
+ active: true,
498
+ isSystemCode: true,
499
+ defaultCode: false,
500
+ },
501
+ ],
502
+ meta: {totalPages: 2},
503
+ },
504
+ });
505
+
506
+ await expect(agentConfigService.getWellbeingBreakIdleCode(mockOrgId)).resolves.toEqual({
507
+ id: 'wellbeing-code',
508
+ name: 'WellbeingBreak',
509
+ isSystem: true,
510
+ isDefault: false,
511
+ });
512
+ expect(mockWebexRequest.request).toHaveBeenNthCalledWith(1, {
513
+ service: mockWccAPIURL,
514
+ resource:
515
+ `organization/${mockOrgId}/v2/auxiliary-code?page=0&pageSize=100` +
516
+ '&workType=IDLE_CODE&customFilter=isSystemCode==true&desktopProfileFilter=false',
517
+ method: 'GET',
518
+ });
519
+ expect(mockWebexRequest.request).toHaveBeenNthCalledWith(2, {
520
+ service: mockWccAPIURL,
521
+ resource:
522
+ `organization/${mockOrgId}/v2/auxiliary-code?page=1&pageSize=100` +
523
+ '&workType=IDLE_CODE&customFilter=isSystemCode==true&desktopProfileFilter=false',
524
+ method: 'GET',
525
+ });
715
526
  });
716
527
 
717
- it('should fetch and parse agent configuration successfully', async () => {
718
- const mockAgentId = 'agent001';
719
- const mockUserConfig = {
720
- ciUserId: 'agent001',
721
- firstName: 'John',
722
- lastName: 'Doe',
723
- email: 'john.doe@example.com',
724
- agentProfileId: 'profile123',
725
- siteId: 'site789',
726
- dbId: 'db123',
727
- defaultDialledNumber: '1234567890',
728
- id: 'user001',
729
- teamIds: ['team1', 'team2'],
730
- };
731
-
732
- const mockAgentProfile = {
733
- timeoutDesktopInactivityCustomEnabled: true,
734
- timeoutDesktopInactivityMins: 10,
735
- accessWrapUpCode: 'SPECIFIC',
736
- wrapUpCodes: ['aux1'],
737
- accessIdleCode: 'SPECIFIC',
738
- idleCodes: ['aux2'],
739
- autoWrapUp: true,
740
- autoWrapAfterSeconds: 30,
741
- lastAgentRouting: true,
742
- allowAutoWrapUpExtension: false,
743
- outdialEnabled: true,
744
- dialPlanEnabled: false,
745
- agentAvailableAfterOutdial: true,
746
- outdialEntryPointId: 'entryPoint123',
747
- consultToQueue: true,
748
- addressBookId: 'addressBook123',
749
- outdialANIId: 'ani123',
750
- dialPlans: ['plan1', 'plan2'],
751
- agentDNValidation: 'validation123',
752
- };
753
-
754
- const mockDialPlanData = [];
755
-
756
- const mockTeamData = [
757
- {id: 'team1', name: 'Support Team'},
758
- {id: 'team2', name: 'Sales Team'},
759
- ];
528
+ it('rejects when the exact system code is unavailable', async () => {
529
+ (mockWebexRequest.request as jest.Mock).mockResolvedValue({
530
+ statusCode: 200,
531
+ body: {
532
+ data: [
533
+ {id: 'inactive', name: 'WellbeingBreak', active: false, isSystemCode: true},
534
+ {id: 'lookalike', name: 'wellbeingbreak', active: true, isSystemCode: true},
535
+ ],
536
+ meta: {totalPages: 1},
537
+ },
538
+ });
760
539
 
761
- const mockOrgInfo = {
762
- tenantId: 'tenant123',
763
- timezone: 'GMT',
764
- environment: 'produs1',
765
- };
540
+ await expect(agentConfigService.getWellbeingBreakIdleCode(mockOrgId)).rejects.toThrow(
541
+ 'WELLBEING_BREAK_IDLE_CODE_NOT_FOUND'
542
+ );
543
+ });
544
+ });
766
545
 
767
- const mockOrgSettings = {
546
+ describe('getAgentConfig', () => {
547
+ const mockSiteInfo = {
548
+ id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
549
+ name: 'Site-1',
550
+ multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
551
+ };
552
+
553
+ const mockOrgConfig = {
554
+ organization: {tenantId: 'tenant123', timezone: 'GMT'},
555
+ organizationSetting: {
768
556
  campaignManagerEnabled: true,
769
557
  webRtcEnabled: true,
770
558
  maskSensitiveData: false,
771
- };
772
-
773
- const mockSiteInfo = {
774
- id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
775
- name: 'Site-1',
776
- multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
777
- };
778
-
779
- const mockTenantData = {
559
+ },
560
+ tenantConfiguration: {
780
561
  timeoutDesktopInactivityEnabled: false,
781
- timeoutDesktopInactivityMins: 15,
782
562
  forceDefaultDn: true,
783
563
  dnDefaultRegex: 'regexUS',
784
564
  dnOtherRegex: 'regexOther',
@@ -787,38 +567,94 @@ describe('AgentConfigService', () => {
787
567
  endCallEnabled: true,
788
568
  endConsultEnabled: true,
789
569
  callVariablesSuppressed: false,
790
- };
570
+ lostConnectionRecoveryTimeout: 120000,
571
+ },
572
+ urlMappings: {},
573
+ aiFeature: {realtimeTranscripts: {enable: true}},
574
+ webexConfig: {showUserDetails: false, stateSynchronization: true},
575
+ };
576
+
577
+ const mockUser = {
578
+ ciUserId: 'agent001',
579
+ firstName: 'John',
580
+ lastName: 'Doe',
581
+ email: 'john.doe@example.com',
582
+ agentProfileId: 'profile123',
583
+ skillProfileId: 'skillProfile456',
584
+ siteId: 'site789',
585
+ dbId: 'db123',
586
+ deafultDialledNumber: '1234567890',
587
+ id: 'user001',
588
+ };
589
+
590
+ const mockAgentProfile = {
591
+ timeoutDesktopInactivityCustomEnabled: true,
592
+ timeoutDesktopInactivityMins: 10,
593
+ accessWrapUpCode: 'ALL',
594
+ accessIdleCode: 'ALL',
595
+ autoWrapUp: true,
596
+ autoWrapAfterSeconds: 30,
597
+ lastAgentRouting: true,
598
+ allowAutoWrapUpExtension: false,
599
+ outdialEnabled: true,
600
+ dialPlanEnabled: false,
601
+ agentAvailableAfterOutdial: true,
602
+ outdialEntryPointId: 'entryPoint123',
603
+ consultToQueue: true,
604
+ viewableStatistics: {agentStats: true},
605
+ addressBookId: 'addressBook123',
606
+ outdialANIId: 'ani123',
607
+ loginVoiceOptions: ['BROWSER', 'EXTENSION'],
608
+ agentDNValidation: 'PROVISIONED_VALUE',
609
+ };
610
+
611
+ const mockTeamData = [
612
+ {id: 'team1', name: 'Support Team', multiMediaProfileId: 'mmTeam123'},
613
+ ];
614
+
615
+ const mockAuxCodes = [
616
+ {id: 'aux1', workTypeCode: 'WRAP_UP_CODE', name: 'Wrap Up Code 1', active: true},
617
+ {id: 'aux2', workTypeCode: 'IDLE_CODE', name: 'Idle Code 1', active: true},
618
+ ];
619
+
620
+ const mockDialPlanData = [
621
+ {
622
+ id: 'dialPlan1',
623
+ name: 'Plan 1',
624
+ regularExpression: '[0-9]+',
625
+ prefix: '1',
626
+ strippedChars: '( )-',
627
+ active: true,
628
+ },
629
+ ];
630
+
631
+ /** Stubs every call getAgentConfig makes, so each test overrides only what it exercises. */
632
+ const stubConfigCalls = ({
633
+ agentProfile = mockAgentProfile,
634
+ teamData = mockTeamData,
635
+ }: {agentProfile?: object; teamData?: object[]} = {}) => {
636
+ agentConfigService.getOrgDesktopLoginConfig = jest.fn().mockResolvedValue(mockOrgConfig);
637
+ agentConfigService.getUserDesktopLoginConfig = jest
638
+ .fn()
639
+ .mockResolvedValue({user: mockUser, agentProfile});
640
+ agentConfigService.getAllAuxCodes = jest.fn().mockResolvedValue(mockAuxCodes);
641
+ agentConfigService.getSiteInfo = jest.fn().mockResolvedValue(mockSiteInfo);
642
+ agentConfigService.getAllTeams = jest.fn().mockResolvedValue(teamData);
643
+ agentConfigService.getDialPlanData = jest.fn().mockResolvedValue(mockDialPlanData);
644
+ };
791
645
 
792
- const mockURLMapping = [
793
- {key: 'ACQUEON_API_URL', url: 'https://api.example.com'},
794
- {key: 'ACQUEON_CONSOLE_URL', url: 'https://console.example.com'},
795
- ];
796
-
797
- const mockAuxCodes = [
798
- {id: 'aux1', type: 'WRAP_UP_CODE', name: 'Wrap Up Code 1', isDefault: true},
799
- {id: 'aux2', type: 'IDLE_CODE', name: 'Idle Code 1', isDefault: true},
800
- ];
801
- const mockAIFeatureFlags = {
802
- data: [{realtimeTranscripts: {enable: true}}],
803
- };
646
+ beforeEach(() => {
647
+ jest.clearAllMocks();
648
+ });
804
649
 
650
+ it('should fetch and parse agent configuration successfully', async () => {
805
651
  const parseAgentConfigsSpy = jest.spyOn(util, 'parseAgentConfigs');
806
- agentConfigService.getUserUsingCI = jest.fn().mockResolvedValue(mockUserConfig);
807
- agentConfigService.getOrgInfo = jest.fn().mockResolvedValue(mockOrgInfo);
808
- agentConfigService.getOrganizationSetting = jest.fn().mockResolvedValue(mockOrgSettings);
809
- agentConfigService.getSiteInfo = jest.fn().mockResolvedValue(mockSiteInfo);
810
- agentConfigService.getTenantData = jest.fn().mockResolvedValue(mockTenantData);
811
- agentConfigService.getURLMapping = jest.fn().mockResolvedValue(mockURLMapping);
812
- agentConfigService.getAIFeatureFlags = jest.fn().mockResolvedValue(mockAIFeatureFlags);
813
- agentConfigService.getAllAuxCodes = jest.fn().mockResolvedValue(mockAuxCodes);
814
- agentConfigService.getDesktopProfileById = jest.fn().mockResolvedValue(mockAgentProfile);
815
- agentConfigService.getDialPlanData = jest.fn().mockResolvedValue(mockDialPlanData);
816
- agentConfigService.getAllTeams = jest.fn().mockResolvedValue(mockTeamData);
652
+ stubConfigCalls();
817
653
 
818
- const result = await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
654
+ await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
819
655
 
820
656
  expect(LoggerProxy.info).toHaveBeenCalledWith(
821
- `Fetched user data, userId: ${mockUserConfig.ciUserId}`,
657
+ `Fetched user data, userId: ${mockUser.ciUserId}`,
822
658
  {
823
659
  module: CONFIG_FILE_NAME,
824
660
  method: 'getAgentConfig',
@@ -839,183 +675,117 @@ describe('AgentConfigService', () => {
839
675
  expect(parseAgentConfigsSpy).toHaveBeenCalledTimes(1);
840
676
 
841
677
  expect(parseAgentConfigsSpy).toHaveBeenCalledWith({
842
- userData: mockUserConfig,
678
+ orgConfig: mockOrgConfig,
679
+ userData: mockUser,
680
+ agentProfileData: mockAgentProfile,
843
681
  teamData: mockTeamData,
844
- tenantData: mockTenantData,
845
- orgInfoData: mockOrgInfo,
846
682
  auxCodes: mockAuxCodes,
847
- orgSettingsData: mockOrgSettings,
848
- agentProfileData: mockAgentProfile,
849
- dialPlanData: mockDialPlanData,
850
- urlMapping: mockURLMapping,
851
- multimediaProfileId: mockSiteInfo.multimediaProfileId,
852
- aiFeatureFlags: mockAIFeatureFlags,
683
+ dialPlanData: [],
684
+ multimediaProfileId: 'mmTeam123',
853
685
  });
854
686
  });
855
687
 
856
- it('should fetch and parse agent configuration with different values and conditions successfully', async () => {
857
- const mockAgentId = 'agent001';
858
- const mockUserConfig = {
859
- ciUserId: 'agent001',
860
- firstName: 'John',
861
- lastName: 'Doe',
862
- email: 'john.doe@example.com',
863
- agentProfileId: 'profile123',
864
- skillProfileId: 'skillProfile456',
865
- siteId: 'site789',
866
- dbId: 'db123',
867
- defaultDialledNumber: '1234567890',
868
- id: 'user001',
869
- teamIds: ['team1', 'team2'],
870
- };
688
+ it('should request both aggregates and the aux-code pool for the given org and agent', async () => {
689
+ stubConfigCalls();
871
690
 
872
- const mockAgentProfile = {
873
- timeoutDesktopInactivityCustomEnabled: false,
874
- timeoutDesktopInactivityMins: 10,
875
- accessWrapUpCode: 'ALL',
876
- wrapUpCodes: [],
877
- accessIdleCode: 'ALL',
878
- idleCodes: [],
879
- autoWrapUp: true,
880
- autoWrapAfterSeconds: 30,
881
- lastAgentRouting: true,
882
- allowAutoWrapUpExtension: false,
883
- outdialEnabled: true,
884
- dialPlanEnabled: true,
885
- agentAvailableAfterOutdial: true,
886
- outdialEntryPointId: 'entryPoint123',
887
- consultToQueue: true,
888
- viewableStatistics: {agentStats: true},
889
- addressBookId: 'addressBook123',
890
- outdialANIId: 'ani123',
891
- loginVoiceOptions: ['option1', 'option2'],
892
- dialPlans: ['dialPlan1', 'dialPlan2'],
893
- agentDNValidation: 'validation123',
894
- };
691
+ await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
895
692
 
896
- const mockDialPlanData = [
897
- {id: 'dialPlan1', name: 'Plan 1'},
898
- {id: 'dialPlan2', name: 'Plan 2'},
899
- ];
693
+ expect(agentConfigService.getOrgDesktopLoginConfig).toHaveBeenCalledWith(mockOrgId);
694
+ expect(agentConfigService.getUserDesktopLoginConfig).toHaveBeenCalledWith(
695
+ mockOrgId,
696
+ mockAgentId
697
+ );
698
+ expect(agentConfigService.getAllAuxCodes).toHaveBeenCalledWith(
699
+ mockOrgId,
700
+ 100,
701
+ [],
702
+ DEFAULT_AUXCODE_ATTRIBUTES
703
+ );
704
+ });
900
705
 
901
- const mockTeamData = [
902
- {id: 'team1', name: 'Support Team'},
903
- {id: 'team2', name: 'Sales Team'},
904
- ];
706
+ it('should query teams by the user dbId and the site by the user siteId', async () => {
707
+ stubConfigCalls();
905
708
 
906
- const mockOrgInfo = {
907
- tenantId: 'tenant123',
908
- timezone: 'GMT',
909
- environment: 'produs1',
910
- };
709
+ await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
911
710
 
912
- const mockOrgSettings = {
913
- campaignManagerEnabled: true,
914
- webRtcEnabled: true,
915
- maskSensitiveData: true,
916
- };
711
+ expect(agentConfigService.getAllTeams).toHaveBeenCalledWith(mockOrgId, 100, mockUser.dbId);
712
+ expect(agentConfigService.getSiteInfo).toHaveBeenCalledWith(mockOrgId, mockUser.siteId);
713
+ });
917
714
 
918
- const mockSiteInfo = {
919
- id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
920
- name: 'Site-1',
921
- multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
922
- };
715
+ it.each([
716
+ {dialPlanEnabled: true, expectedCalls: 1},
717
+ {dialPlanEnabled: false, expectedCalls: 0},
718
+ ])(
719
+ 'should issue the dial-plan call $expectedCalls time(s) when dialPlanEnabled is $dialPlanEnabled',
720
+ async ({dialPlanEnabled, expectedCalls}) => {
721
+ stubConfigCalls({agentProfile: {...mockAgentProfile, dialPlanEnabled}});
923
722
 
924
- const mockTenantData = {
925
- timeoutDesktopInactivityEnabled: true,
926
- timeoutDesktopInactivityMins: 15,
927
- forceDefaultDn: true,
928
- dnDefaultRegex: 'regexUS',
929
- dnOtherRegex: 'regexOther',
930
- privacyShieldVisible: true,
931
- outdialEnabled: true,
932
- endCallEnabled: true,
933
- endConsultEnabled: true,
934
- callVariablesSuppressed: false,
935
- lostConnectionRecoveryTimeout: 30,
936
- };
723
+ await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
937
724
 
938
- const mockURLMapping = [
939
- {key: 'ACQUEON_API_URL', url: 'https://api.example.com'},
940
- {key: 'ACQUEON_CONSOLE_URL', url: 'https://console.example.com'},
941
- ];
942
-
943
- const mockAuxCodes = [
944
- {id: 'aux1', type: 'WRAP_UP_CODE', name: 'Wrap Up Code 1'},
945
- {id: 'aux2', type: 'IDLE_CODE', name: 'Idle Code 1'},
946
- ];
947
- const mockAIFeatureFlags = {
948
- data: [{realtimeTranscripts: {enable: true}}],
949
- };
725
+ expect(agentConfigService.getDialPlanData).toHaveBeenCalledTimes(expectedCalls);
726
+ }
727
+ );
950
728
 
729
+ it.each([
730
+ {
731
+ scenario: 'the team value when the agent has a team',
732
+ teamData: mockTeamData,
733
+ expected: 'mmTeam123',
734
+ },
735
+ {
736
+ scenario: 'the site value when the agent has no team',
737
+ teamData: [],
738
+ expected: mockSiteInfo.multimediaProfileId,
739
+ },
740
+ {
741
+ scenario: 'the site value when the team carries no multimedia profile',
742
+ teamData: [{id: 'team1', name: 'Support Team'}],
743
+ expected: mockSiteInfo.multimediaProfileId,
744
+ },
745
+ ])('should resolve multimediaProfileId to $scenario', async ({teamData, expected}) => {
951
746
  const parseAgentConfigsSpy = jest.spyOn(util, 'parseAgentConfigs');
952
- agentConfigService.getUserUsingCI = jest.fn().mockResolvedValue(mockUserConfig);
953
- agentConfigService.getOrgInfo = jest.fn().mockResolvedValue(mockOrgInfo);
954
- agentConfigService.getOrganizationSetting = jest.fn().mockResolvedValue(mockOrgSettings);
955
- agentConfigService.getSiteInfo = jest.fn().mockResolvedValue(mockSiteInfo);
956
- agentConfigService.getTenantData = jest.fn().mockResolvedValue(mockTenantData);
957
- agentConfigService.getURLMapping = jest.fn().mockResolvedValue(mockURLMapping);
958
- agentConfigService.getAIFeatureFlags = jest.fn().mockResolvedValue(mockAIFeatureFlags);
959
- agentConfigService.getAllAuxCodes = jest.fn().mockResolvedValue(mockAuxCodes);
960
- agentConfigService.getDesktopProfileById = jest.fn().mockResolvedValue(mockAgentProfile);
961
- agentConfigService.getDialPlanData = jest.fn().mockResolvedValue(mockDialPlanData);
962
- agentConfigService.getAllTeams = jest.fn().mockResolvedValue(mockTeamData);
747
+ stubConfigCalls({teamData});
963
748
 
964
- const result = await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
749
+ await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
965
750
 
966
- expect(LoggerProxy.info).toHaveBeenCalledWith(
967
- `Fetched user data, userId: ${mockUserConfig.ciUserId}`,
968
- {
969
- module: CONFIG_FILE_NAME,
970
- method: 'getAgentConfig',
971
- }
751
+ expect(parseAgentConfigsSpy).toHaveBeenCalledWith(
752
+ expect.objectContaining({multimediaProfileId: expected})
972
753
  );
973
- expect(LoggerProxy.info).toHaveBeenCalledWith('Fetched all required data', {
974
- module: CONFIG_FILE_NAME,
975
- method: 'getAgentConfig',
976
- });
977
- expect(LoggerProxy.info).toHaveBeenCalledWith('Parsing completed for agent-config', {
978
- module: CONFIG_FILE_NAME,
979
- method: 'getAgentConfig',
980
- });
981
- expect(LoggerProxy.info).toHaveBeenCalledWith('Fetched configuration data successfully', {
982
- module: CONFIG_FILE_NAME,
983
- method: 'getAgentConfig',
984
- });
985
- expect(parseAgentConfigsSpy).toHaveBeenCalledTimes(1);
754
+ });
986
755
 
987
- expect(parseAgentConfigsSpy).toHaveBeenCalledWith({
988
- userData: mockUserConfig,
989
- teamData: mockTeamData,
990
- tenantData: mockTenantData,
991
- orgInfoData: mockOrgInfo,
992
- auxCodes: mockAuxCodes,
993
- orgSettingsData: mockOrgSettings,
994
- agentProfileData: mockAgentProfile,
995
- dialPlanData: mockDialPlanData,
996
- urlMapping: mockURLMapping,
997
- multimediaProfileId: mockSiteInfo.multimediaProfileId,
998
- aiFeatureFlags: mockAIFeatureFlags,
756
+ it('should build the dial plan from the dial-plan response when dial planning is enabled', async () => {
757
+ const parseAgentConfigsSpy = jest.spyOn(util, 'parseAgentConfigs');
758
+ stubConfigCalls({agentProfile: {...mockAgentProfile, dialPlanEnabled: true}});
759
+
760
+ const result = await agentConfigService.getAgentConfig(mockOrgId, mockAgentId);
761
+
762
+ expect(parseAgentConfigsSpy).toHaveBeenCalledWith(
763
+ expect.objectContaining({dialPlanData: mockDialPlanData})
764
+ );
765
+ expect(result.dialPlan).toEqual({
766
+ type: 'adhocDial',
767
+ dialPlanEntity: [{regex: '[0-9]+', prefix: '1', strippedChars: '( )-', name: 'Plan 1'}],
999
768
  });
1000
769
  });
1001
770
 
1002
- it('should throw an error if any of the API calls fail', async () => {
1003
- const mockAgentId = 'agent001';
771
+ it.each([
772
+ 'getOrgDesktopLoginConfig',
773
+ 'getUserDesktopLoginConfig',
774
+ 'getAllAuxCodes',
775
+ 'getSiteInfo',
776
+ 'getAllTeams',
777
+ ])('should throw an error if %s fails', async (failingCall) => {
1004
778
  const mockError = new Error('API call failed');
1005
- agentConfigService.getUserUsingCI = jest.fn().mockRejectedValue(mockError);
1006
- agentConfigService.getOrgInfo = jest.fn().mockResolvedValue({});
1007
- agentConfigService.getOrganizationSetting = jest.fn().mockResolvedValue({});
1008
- agentConfigService.getTenantData = jest.fn().mockResolvedValue({});
1009
- agentConfigService.getURLMapping = jest.fn().mockResolvedValue({});
1010
- agentConfigService.getAIFeatureFlags = jest.fn().mockResolvedValue({data: []});
1011
- agentConfigService.getAllAuxCodes = jest.fn().mockResolvedValue({});
1012
- agentConfigService.getDesktopProfileById = jest.fn().mockResolvedValue({});
1013
- agentConfigService.getDialPlanData = jest.fn().mockResolvedValue({});
1014
- agentConfigService.getAllTeams = jest.fn().mockResolvedValue({});
779
+ stubConfigCalls();
780
+ agentConfigService[failingCall] = jest.fn().mockRejectedValue(mockError);
1015
781
 
1016
782
  await expect(agentConfigService.getAgentConfig(mockOrgId, mockAgentId)).rejects.toThrow(
1017
783
  'API call failed'
1018
784
  );
785
+ expect(LoggerProxy.error).toHaveBeenCalledWith(
786
+ 'getAgentConfig call failed with Error: API call failed',
787
+ {module: CONFIG_FILE_NAME, method: 'getAgentConfig'}
788
+ );
1019
789
  });
1020
790
  });
1021
791