@webex/contact-center 3.10.0-next.2 → 3.10.0-next.21

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 (103) hide show
  1. package/dist/cc.js +13 -1
  2. package/dist/cc.js.map +1 -1
  3. package/dist/config.js.map +1 -1
  4. package/dist/constants.js.map +1 -1
  5. package/dist/index.js +17 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger-proxy.js.map +1 -1
  8. package/dist/metrics/MetricsManager.js +2 -1
  9. package/dist/metrics/MetricsManager.js.map +1 -1
  10. package/dist/metrics/behavioral-events.js +12 -0
  11. package/dist/metrics/behavioral-events.js.map +1 -1
  12. package/dist/metrics/constants.js +4 -0
  13. package/dist/metrics/constants.js.map +1 -1
  14. package/dist/services/AddressBook.js +2 -3
  15. package/dist/services/AddressBook.js.map +1 -1
  16. package/dist/services/EntryPoint.js +2 -3
  17. package/dist/services/EntryPoint.js.map +1 -1
  18. package/dist/services/Queue.js +2 -3
  19. package/dist/services/Queue.js.map +1 -1
  20. package/dist/services/WebCallingService.js +1 -1
  21. package/dist/services/WebCallingService.js.map +1 -1
  22. package/dist/services/agent/index.js +1 -2
  23. package/dist/services/agent/index.js.map +1 -1
  24. package/dist/services/agent/types.js +10 -0
  25. package/dist/services/agent/types.js.map +1 -1
  26. package/dist/services/config/Util.js.map +1 -1
  27. package/dist/services/config/constants.js.map +1 -1
  28. package/dist/services/config/index.js +1 -1
  29. package/dist/services/config/index.js.map +1 -1
  30. package/dist/services/config/types.js +2 -2
  31. package/dist/services/config/types.js.map +1 -1
  32. package/dist/services/constants.js.map +1 -1
  33. package/dist/services/core/Err.js.map +1 -1
  34. package/dist/services/core/GlobalTypes.js.map +1 -1
  35. package/dist/services/core/Utils.js +92 -74
  36. package/dist/services/core/Utils.js.map +1 -1
  37. package/dist/services/core/WebexRequest.js +1 -2
  38. package/dist/services/core/WebexRequest.js.map +1 -1
  39. package/dist/services/core/aqm-reqs.js +2 -3
  40. package/dist/services/core/aqm-reqs.js.map +1 -1
  41. package/dist/services/core/constants.js +17 -1
  42. package/dist/services/core/constants.js.map +1 -1
  43. package/dist/services/core/types.js.map +1 -1
  44. package/dist/services/core/websocket/WebSocketManager.js +1 -2
  45. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  46. package/dist/services/core/websocket/connection-service.js +1 -1
  47. package/dist/services/core/websocket/connection-service.js.map +1 -1
  48. package/dist/services/core/websocket/keepalive.worker.js.map +1 -1
  49. package/dist/services/core/websocket/types.js.map +1 -1
  50. package/dist/services/index.js +1 -1
  51. package/dist/services/index.js.map +1 -1
  52. package/dist/services/task/AutoWrapup.js +1 -1
  53. package/dist/services/task/AutoWrapup.js.map +1 -1
  54. package/dist/services/task/TaskManager.js +177 -56
  55. package/dist/services/task/TaskManager.js.map +1 -1
  56. package/dist/services/task/TaskUtils.js +122 -5
  57. package/dist/services/task/TaskUtils.js.map +1 -1
  58. package/dist/services/task/constants.js +3 -1
  59. package/dist/services/task/constants.js.map +1 -1
  60. package/dist/services/task/contact.js +0 -2
  61. package/dist/services/task/contact.js.map +1 -1
  62. package/dist/services/task/dialer.js.map +1 -1
  63. package/dist/services/task/index.js +46 -40
  64. package/dist/services/task/index.js.map +1 -1
  65. package/dist/services/task/types.js +377 -4
  66. package/dist/services/task/types.js.map +1 -1
  67. package/dist/types/cc.d.ts +6 -0
  68. package/dist/types/index.d.ts +1 -1
  69. package/dist/types/metrics/constants.d.ts +4 -0
  70. package/dist/types/services/config/types.d.ts +4 -4
  71. package/dist/types/services/core/Utils.d.ts +32 -17
  72. package/dist/types/services/core/constants.d.ts +14 -0
  73. package/dist/types/services/task/TaskUtils.d.ts +59 -3
  74. package/dist/types/services/task/constants.d.ts +2 -0
  75. package/dist/types/services/task/types.d.ts +57 -13
  76. package/dist/types.js +5 -0
  77. package/dist/types.js.map +1 -1
  78. package/dist/utils/PageCache.js +1 -1
  79. package/dist/utils/PageCache.js.map +1 -1
  80. package/dist/webex-config.js.map +1 -1
  81. package/dist/webex.js +2 -2
  82. package/dist/webex.js.map +1 -1
  83. package/package.json +8 -8
  84. package/src/cc.ts +12 -0
  85. package/src/index.ts +1 -0
  86. package/src/metrics/behavioral-events.ts +12 -0
  87. package/src/metrics/constants.ts +4 -0
  88. package/src/services/config/types.ts +2 -2
  89. package/src/services/core/Utils.ts +101 -85
  90. package/src/services/core/constants.ts +16 -0
  91. package/src/services/task/TaskManager.ts +204 -36
  92. package/src/services/task/TaskUtils.ts +145 -5
  93. package/src/services/task/constants.ts +2 -0
  94. package/src/services/task/index.ts +50 -63
  95. package/src/services/task/types.ts +60 -13
  96. package/test/unit/spec/cc.ts +1 -0
  97. package/test/unit/spec/metrics/behavioral-events.ts +14 -0
  98. package/test/unit/spec/services/core/Utils.ts +262 -31
  99. package/test/unit/spec/services/task/TaskManager.ts +748 -5
  100. package/test/unit/spec/services/task/TaskUtils.ts +311 -9
  101. package/test/unit/spec/services/task/index.ts +323 -68
  102. package/umd/contact-center.min.js +2 -2
  103. package/umd/contact-center.min.js.map +1 -1
@@ -39,7 +39,8 @@ describe('Task', () => {
39
39
  let loggerInfoSpy;
40
40
  let loggerLogSpy;
41
41
  let loggerErrorSpy;
42
- let getDestinationAgentIdSpy;
42
+ let calculateDestAgentIdSpy;
43
+ let calculateDestTypeSpy;
43
44
 
44
45
  const taskId = '0ae913a4-c857-4705-8d49-76dd3dde75e4';
45
46
  const mockTrack = {} as MediaStreamTrack;
@@ -119,6 +120,32 @@ describe('Task', () => {
119
120
  interaction: {
120
121
  mediaType: 'telephony',
121
122
  mainInteractionId: taskId,
123
+ participants: {
124
+ '723a8ffb-a26e-496d-b14a-ff44fb83b64f': {
125
+ pType: 'Agent',
126
+ type: 'AGENT',
127
+ id: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
128
+ hasLeft: false,
129
+ hasJoined: true,
130
+ isWrapUp: false,
131
+ },
132
+ 'f520d6b5-28ad-4f2f-b83e-781bb64af617': {
133
+ pType: 'Agent',
134
+ type: 'AGENT',
135
+ id: 'f520d6b5-28ad-4f2f-b83e-781bb64af617',
136
+ hasLeft: false,
137
+ hasJoined: true,
138
+ isWrapUp: false,
139
+ },
140
+ 'ebeb893b-ba67-4f36-8418-95c7492b28c2': {
141
+ pType: 'Agent',
142
+ type: 'AGENT',
143
+ id: 'ebeb893b-ba67-4f36-8418-95c7492b28c2',
144
+ hasLeft: false,
145
+ hasJoined: true,
146
+ isWrapUp: false,
147
+ },
148
+ },
122
149
  media: {
123
150
  '58a45567-4e61-4f4b-a580-5bc86357bef0': {
124
151
  holdTimestamp: null,
@@ -145,13 +172,18 @@ describe('Task', () => {
145
172
  },
146
173
  };
147
174
 
148
- // Mock destination agent id resolution from participants
149
- getDestinationAgentIdSpy = jest
150
- .spyOn(Utils, 'getDestinationAgentId')
151
- .mockReturnValue(taskDataMock.destAgentId);
175
+ // Mock calculateDestAgentId to return the expected destination agent
176
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(taskDataMock.destAgentId);
177
+
178
+ // Mock calculateDestType to return 'agent' by default
179
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('agent');
152
180
 
153
- // Create an instance of Task
154
- task = new Task(contactMock, webCallingService, taskDataMock);
181
+ // Create an instance of Task with wrapupData and agentId
182
+ task = new Task(contactMock, webCallingService, taskDataMock, {
183
+ wrapUpProps: { wrapUpReasonList: [] },
184
+ autoWrapEnabled: false,
185
+ autoWrapAfterSeconds: 0
186
+ }, taskDataMock.agentId);
155
187
 
156
188
  // Mock navigator.mediaDevices
157
189
  global.navigator.mediaDevices = {
@@ -993,15 +1025,16 @@ describe('Task', () => {
993
1025
  );
994
1026
  });
995
1027
 
996
- it('should send DIALNUMBER when task destinationType is DN during consultTransfer', async () => {
1028
+ it('should send DIALNUMBER when calculateDestType returns dialNumber during consultTransfer', async () => {
997
1029
  const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
998
1030
  contactMock.consultTransfer.mockResolvedValue(expectedResponse);
999
1031
 
1000
- // Ensure task data indicates DN scenario
1001
- task.data.destinationType = 'DN' as unknown as string;
1032
+ // Mock calculateDestType to return dialNumber
1033
+ calculateDestTypeSpy.mockReturnValue(CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER);
1002
1034
 
1003
1035
  await task.consultTransfer();
1004
1036
 
1037
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1005
1038
  expect(contactMock.consultTransfer).toHaveBeenCalledWith({
1006
1039
  interactionId: taskId,
1007
1040
  data: {
@@ -1011,15 +1044,16 @@ describe('Task', () => {
1011
1044
  });
1012
1045
  });
1013
1046
 
1014
- it('should send ENTRYPOINT when task destinationType is EPDN during consultTransfer', async () => {
1047
+ it('should send ENTRYPOINT when calculateDestType returns entryPoint during consultTransfer', async () => {
1015
1048
  const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
1016
1049
  contactMock.consultTransfer.mockResolvedValue(expectedResponse);
1017
1050
 
1018
- // Ensure task data indicates EP/EPDN scenario
1019
- task.data.destinationType = 'EPDN' as unknown as string;
1051
+ // Mock calculateDestType to return entryPoint
1052
+ calculateDestTypeSpy.mockReturnValue(CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT);
1020
1053
 
1021
1054
  await task.consultTransfer();
1022
1055
 
1056
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1023
1057
  expect(contactMock.consultTransfer).toHaveBeenCalledWith({
1024
1058
  interactionId: taskId,
1025
1059
  data: {
@@ -1029,15 +1063,16 @@ describe('Task', () => {
1029
1063
  });
1030
1064
  });
1031
1065
 
1032
- it('should keep AGENT when task destinationType is neither DN nor EPDN/ENTRYPOINT', async () => {
1066
+ it('should use AGENT when calculateDestType returns agent during consultTransfer', async () => {
1033
1067
  const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
1034
1068
  contactMock.consultTransfer.mockResolvedValue(expectedResponse);
1035
1069
 
1036
- // Ensure task data indicates non-DN and non-EP/EPDN scenario
1037
- task.data.destinationType = 'SOMETHING_ELSE' as unknown as string;
1070
+ // Mock calculateDestType to return agent (default behavior)
1071
+ calculateDestTypeSpy.mockReturnValue(CONSULT_TRANSFER_DESTINATION_TYPE.AGENT);
1038
1072
 
1039
1073
  await task.consultTransfer();
1040
1074
 
1075
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1041
1076
  expect(contactMock.consultTransfer).toHaveBeenCalledWith({
1042
1077
  interactionId: taskId,
1043
1078
  data: {
@@ -1074,7 +1109,11 @@ describe('Task', () => {
1074
1109
  const taskWithoutDestAgentId = new Task(contactMock, webCallingService, {
1075
1110
  ...taskDataMock,
1076
1111
  destAgentId: undefined,
1077
- });
1112
+ }, {
1113
+ wrapUpProps: { wrapUpReasonList: [] },
1114
+ autoWrapEnabled: false,
1115
+ autoWrapAfterSeconds: 0
1116
+ }, taskDataMock.agentId);
1078
1117
 
1079
1118
  const queueConsultTransferPayload: ConsultTransferPayLoad = {
1080
1119
  to: 'some-queue-id',
@@ -1082,61 +1121,123 @@ describe('Task', () => {
1082
1121
  };
1083
1122
 
1084
1123
  // For this negative case, ensure computed destination is empty
1085
- getDestinationAgentIdSpy.mockReturnValueOnce('');
1124
+ calculateDestAgentIdSpy.mockReturnValueOnce('');
1086
1125
 
1087
1126
  await expect(
1088
1127
  taskWithoutDestAgentId.consultTransfer(queueConsultTransferPayload)
1089
- ).rejects.toThrow('Error while performing consultTransfer');
1128
+ ).rejects.toThrow('No agent has accepted this queue consult yet');
1090
1129
  });
1091
1130
 
1092
- it('should handle errors in consult transfer', async () => {
1093
- const consultPayload = {
1094
- destination: '1234',
1095
- destinationType: DESTINATION_TYPE.AGENT,
1096
- };
1097
- const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
1098
- contactMock.consult.mockResolvedValue(expectedResponse);
1131
+ describe('consultTransfer', () => {
1132
+ it('should successfully perform consult transfer with agent destination', async () => {
1133
+ const expectedResponse: TaskResponse = {
1134
+ data: {interactionId: taskId},
1135
+ trackingId: 'test-tracking-id'
1136
+ } as AgentContact;
1137
+ contactMock.consultTransfer.mockResolvedValue(expectedResponse);
1138
+
1139
+ calculateDestTypeSpy.mockReturnValue(CONSULT_TRANSFER_DESTINATION_TYPE.AGENT);
1099
1140
 
1100
- const response = await task.consult(consultPayload);
1141
+ const result = await task.consultTransfer();
1101
1142
 
1102
- expect(contactMock.consult).toHaveBeenCalledWith({interactionId: taskId, data: consultPayload});
1103
- expect(response).toEqual(expectedResponse);
1143
+ expect(calculateDestAgentIdSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1144
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1145
+ expect(contactMock.consultTransfer).toHaveBeenCalledWith({
1146
+ interactionId: taskId,
1147
+ data: {
1148
+ to: taskDataMock.destAgentId,
1149
+ destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
1150
+ },
1151
+ });
1152
+ expect(result).toEqual(expectedResponse);
1153
+ expect(loggerInfoSpy).toHaveBeenCalledWith(
1154
+ `Initiating consult transfer to ${taskDataMock.destAgentId}`,
1155
+ {
1156
+ module: TASK_FILE,
1157
+ method: 'consultTransfer',
1158
+ interactionId: taskId,
1159
+ }
1160
+ );
1161
+ expect(loggerLogSpy).toHaveBeenCalledWith(
1162
+ `Consult transfer completed successfully to ${taskDataMock.destAgentId}`,
1163
+ {
1164
+ module: TASK_FILE,
1165
+ method: 'consultTransfer',
1166
+ trackingId: expectedResponse.trackingId,
1167
+ interactionId: taskId,
1168
+ }
1169
+ );
1170
+ });
1171
+
1172
+ it('should track metrics on successful consult transfer', async () => {
1173
+ const expectedResponse: TaskResponse = {
1174
+ data: {interactionId: taskId},
1175
+ trackingId: 'test-tracking-id'
1176
+ } as AgentContact;
1177
+ contactMock.consultTransfer.mockResolvedValue(expectedResponse);
1178
+
1179
+ await task.consultTransfer();
1180
+
1181
+ expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
1182
+ METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
1183
+ {
1184
+ taskId: taskDataMock.interactionId,
1185
+ destination: taskDataMock.destAgentId,
1186
+ destinationType: 'agent',
1187
+ isConsultTransfer: true,
1188
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(expectedResponse),
1189
+ },
1190
+ ['operational', 'behavioral', 'business']
1191
+ );
1192
+ });
1104
1193
 
1105
- const error = {details: (global as any).makeFailure('Consult Transfer Failed')};
1106
- contactMock.consultTransfer.mockImplementation(() => {
1107
- throw error;
1194
+ it('should throw error when no destination agent is found', async () => {
1195
+ calculateDestAgentIdSpy.mockReturnValue('');
1196
+
1197
+ await expect(task.consultTransfer()).rejects.toThrow('No agent has accepted this queue consult yet');
1198
+
1199
+ expect(contactMock.consultTransfer).not.toHaveBeenCalled();
1108
1200
  });
1109
1201
 
1110
- const consultTransferPayload: ConsultTransferPayLoad = {
1111
- to: '1234',
1112
- destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
1113
- };
1202
+ it('should handle and rethrow contact method errors', async () => {
1203
+ const mockError = new Error('Consult Transfer Failed');
1204
+ contactMock.consultTransfer.mockRejectedValue(mockError);
1205
+ generateTaskErrorObjectSpy.mockReturnValue(mockError);
1114
1206
 
1115
- await expect(task.consultTransfer(consultTransferPayload)).rejects.toThrow(
1116
- error.details.data.reason
1117
- );
1118
- expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(error, 'consultTransfer', TASK_FILE);
1119
- const expectedTaskErrorFieldsConsultTransfer = {
1120
- trackingId: error.details.trackingId,
1121
- errorMessage: error.details.data.reason,
1122
- errorType: '',
1123
- errorData: '',
1124
- reasonCode: 0,
1125
- };
1126
- expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
1127
- 2,
1128
- METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
1129
- {
1130
- taskId: taskDataMock.interactionId,
1131
- destination: taskDataMock.destAgentId,
1132
- destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
1133
- isConsultTransfer: true,
1134
- error: error.toString(),
1135
- ...expectedTaskErrorFieldsConsultTransfer,
1136
- ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
1137
- },
1138
- ['operational', 'behavioral', 'business']
1139
- );
1207
+ await expect(task.consultTransfer()).rejects.toThrow('Consult Transfer Failed');
1208
+
1209
+ expect(generateTaskErrorObjectSpy).toHaveBeenCalledWith(mockError, 'consultTransfer', TASK_FILE);
1210
+ expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
1211
+ METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
1212
+ expect.objectContaining({
1213
+ taskId: taskDataMock.interactionId,
1214
+ destination: taskDataMock.destAgentId,
1215
+ destinationType: 'agent',
1216
+ isConsultTransfer: true,
1217
+ error: mockError.toString(),
1218
+ }),
1219
+ ['operational', 'behavioral', 'business']
1220
+ );
1221
+ });
1222
+
1223
+ it('should dynamically calculate destAgentId when not available', async () => {
1224
+ const consultedAgentId = 'dynamic-agent-123';
1225
+ calculateDestAgentIdSpy.mockReturnValue(consultedAgentId);
1226
+
1227
+ const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
1228
+ contactMock.consultTransfer.mockResolvedValue(expectedResponse);
1229
+
1230
+ await task.consultTransfer();
1231
+
1232
+ expect(calculateDestAgentIdSpy).toHaveBeenCalledWith(taskDataMock.interaction, taskDataMock.agentId);
1233
+ expect(contactMock.consultTransfer).toHaveBeenCalledWith({
1234
+ interactionId: taskId,
1235
+ data: {
1236
+ to: consultedAgentId,
1237
+ destinationType: 'agent',
1238
+ },
1239
+ });
1240
+ });
1140
1241
  });
1141
1242
 
1142
1243
  it('should do vteamTransfer if destinationType is queue and return the expected response', async () => {
@@ -1759,12 +1860,6 @@ describe('Task', () => {
1759
1860
  conferenceTransfer: jest.fn(),
1760
1861
  };
1761
1862
 
1762
- // Re-setup the getDestinationAgentId spy for conference methods
1763
- getDestinationAgentIdSpy = jest
1764
- .spyOn(Utils, 'getDestinationAgentId')
1765
- .mockReturnValue(taskDataMock.destAgentId);
1766
-
1767
-
1768
1863
  task = new Task(contactMock, webCallingService, taskDataMock, {
1769
1864
  wrapUpProps: { wrapUpReasonList: [] },
1770
1865
  autoWrapEnabled: false,
@@ -1788,7 +1883,7 @@ describe('Task', () => {
1788
1883
  interactionId: taskId,
1789
1884
  data: {
1790
1885
  agentId: taskDataMock.agentId, // From task data agent ID
1791
- to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
1886
+ to: taskDataMock.destAgentId, // From calculateDestAgentId() using task participants
1792
1887
  destinationType: 'agent', // From consultation data
1793
1888
  },
1794
1889
  });
@@ -1830,6 +1925,166 @@ describe('Task', () => {
1830
1925
  interactionId: taskId,
1831
1926
  });
1832
1927
  });
1928
+
1929
+ it('should dynamically calculate destAgentId from participants when this.data.destAgentId is null', async () => {
1930
+ // Simulate scenario where destAgentId is not preserved (e.g., after hold/unhold)
1931
+ task.data.destAgentId = null;
1932
+
1933
+ const consultedAgentId = 'consulted-agent-123';
1934
+ calculateDestAgentIdSpy.mockReturnValue(consultedAgentId);
1935
+
1936
+ const mockResponse = {
1937
+ trackingId: 'test-tracking-dynamic',
1938
+ interactionId: taskId,
1939
+ };
1940
+ contactMock.consultConference.mockResolvedValue(mockResponse);
1941
+
1942
+ const result = await task.consultConference();
1943
+
1944
+ // Verify calculateDestAgentId was called to dynamically calculate the destination
1945
+ expect(calculateDestAgentIdSpy).toHaveBeenCalledWith(
1946
+ taskDataMock.interaction,
1947
+ taskDataMock.agentId
1948
+ );
1949
+
1950
+ // Verify the conference was called with the dynamically calculated destAgentId
1951
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
1952
+ interactionId: taskId,
1953
+ data: {
1954
+ agentId: taskDataMock.agentId,
1955
+ to: consultedAgentId, // Dynamically calculated value
1956
+ destinationType: 'agent',
1957
+ },
1958
+ });
1959
+ expect(result).toEqual(mockResponse);
1960
+ });
1961
+
1962
+ it('should throw error when no destination agent is found (queue consult not accepted)', async () => {
1963
+ // Simulate queue consult scenario where no agent has accepted yet
1964
+ calculateDestAgentIdSpy.mockReturnValue(''); // No agent found
1965
+
1966
+ await expect(task.consultConference()).rejects.toThrow('No agent has accepted this queue consult yet');
1967
+
1968
+ // Verify the conference was NOT called
1969
+ expect(contactMock.consultConference).not.toHaveBeenCalled();
1970
+ });
1971
+
1972
+ it('should calculate destination type from participant type for regular agents', async () => {
1973
+ const destAgentId = 'consulted-agent-456';
1974
+
1975
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
1976
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('agent');
1977
+
1978
+ const mockResponse = {trackingId: 'test-tracking-id', interactionId: taskId};
1979
+ contactMock.consultConference.mockResolvedValue(mockResponse);
1980
+
1981
+ await task.consultConference();
1982
+
1983
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(
1984
+ task.data.interaction,
1985
+ taskDataMock.agentId
1986
+ );
1987
+
1988
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
1989
+ interactionId: taskId,
1990
+ data: {
1991
+ agentId: taskDataMock.agentId,
1992
+ to: destAgentId,
1993
+ destinationType: 'agent',
1994
+ },
1995
+ });
1996
+ });
1997
+
1998
+ it('should use DN destination type for dial number participants', async () => {
1999
+ const destAgentId = 'dn-uuid-123';
2000
+
2001
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
2002
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('dialNumber');
2003
+
2004
+ const mockResponse = {trackingId: 'test-tracking-id-dn', interactionId: taskId};
2005
+ contactMock.consultConference.mockResolvedValue(mockResponse);
2006
+
2007
+ await task.consultConference();
2008
+
2009
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
2010
+ interactionId: taskId,
2011
+ data: {
2012
+ agentId: taskDataMock.agentId,
2013
+ to: destAgentId,
2014
+ destinationType: 'dialNumber',
2015
+ },
2016
+ });
2017
+ });
2018
+
2019
+ it('should use EpDn destination type for entry point dial number participants', async () => {
2020
+ const destAgentId = 'epdn-uuid-456';
2021
+
2022
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
2023
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('entryPoint');
2024
+
2025
+ const mockResponse = {trackingId: 'test-tracking-id-epdn', interactionId: taskId};
2026
+ contactMock.consultConference.mockResolvedValue(mockResponse);
2027
+
2028
+ await task.consultConference();
2029
+
2030
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
2031
+ interactionId: taskId,
2032
+ data: {
2033
+ agentId: taskDataMock.agentId,
2034
+ to: destAgentId,
2035
+ destinationType: 'entryPoint',
2036
+ },
2037
+ });
2038
+ });
2039
+
2040
+ it('should fall back to task.data.destinationType when calculateDestType returns empty', async () => {
2041
+ const destAgentId = 'consulted-agent-789';
2042
+
2043
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
2044
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue(''); // No type found
2045
+
2046
+ task.data.destinationType = 'EPDN';
2047
+
2048
+ const mockResponse = {trackingId: 'test-tracking-id-fallback', interactionId: taskId};
2049
+ contactMock.consultConference.mockResolvedValue(mockResponse);
2050
+
2051
+ await task.consultConference();
2052
+
2053
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
2054
+ interactionId: taskId,
2055
+ data: {
2056
+ agentId: taskDataMock.agentId,
2057
+ to: destAgentId,
2058
+ destinationType: 'EPDN', // Falls back to task.data.destinationType
2059
+ },
2060
+ });
2061
+ });
2062
+
2063
+ it('should handle CBT scenarios with correct destination type', async () => {
2064
+ const destAgentId = 'agent-cbt-uuid';
2065
+
2066
+ calculateDestAgentIdSpy = jest.spyOn(Utils, 'calculateDestAgentId').mockReturnValue(destAgentId);
2067
+ calculateDestTypeSpy = jest.spyOn(Utils, 'calculateDestType').mockReturnValue('dialNumber');
2068
+
2069
+ const mockResponse = {trackingId: 'test-tracking-id-cbt', interactionId: taskId};
2070
+ contactMock.consultConference.mockResolvedValue(mockResponse);
2071
+
2072
+ await task.consultConference();
2073
+
2074
+ expect(calculateDestTypeSpy).toHaveBeenCalledWith(
2075
+ task.data.interaction,
2076
+ taskDataMock.agentId
2077
+ );
2078
+
2079
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
2080
+ interactionId: taskId,
2081
+ data: {
2082
+ agentId: taskDataMock.agentId,
2083
+ to: destAgentId,
2084
+ destinationType: 'dialNumber', // dialNumber for CBT scenarios
2085
+ },
2086
+ });
2087
+ });
1833
2088
  });
1834
2089
 
1835
2090
  describe('exitConference', () => {