@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.3
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.
- package/.sdd/manifest.json +5 -4
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +5 -1
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +440 -10
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +13 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +176 -20
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +135 -37
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +38 -11
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +350 -14
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +77 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +260 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +48 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +506 -9
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/ai-docs/metrics-spec.md +9 -3
- package/src/metrics/behavioral-events.ts +14 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +254 -15
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +117 -2
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +210 -63
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +8 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +17 -8
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +46 -22
- package/src/services/task/state-machine/guards.ts +64 -11
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +462 -12
- package/src/services/task/voice/WebRTC.ts +5 -1
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1274 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +200 -0
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +653 -1
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +854 -72
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +874 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
package/test/unit/spec/cc.ts
CHANGED
|
@@ -169,10 +169,13 @@ describe('webex.cc', () => {
|
|
|
169
169
|
setWrapupData: jest.fn(),
|
|
170
170
|
setAgentId: jest.fn(),
|
|
171
171
|
setWebRtcEnabled: jest.fn(),
|
|
172
|
+
setAnswerCallOnWebexService: jest.fn(),
|
|
172
173
|
registerIncomingCallEvent: jest.fn(),
|
|
173
174
|
registerTaskListeners: jest.fn(),
|
|
174
175
|
getTask: jest.fn(),
|
|
175
176
|
getActiveTasks: jest.fn(),
|
|
177
|
+
applyEnableWxBetterTogether: jest.fn(),
|
|
178
|
+
syncWxAppMuteFromCallDetailsForAllTasks: jest.fn(),
|
|
176
179
|
on: jest.fn(),
|
|
177
180
|
off: jest.fn(),
|
|
178
181
|
emit: jest.fn(),
|
|
@@ -311,6 +314,9 @@ describe('webex.cc', () => {
|
|
|
311
314
|
isEndConsultEnabled: false,
|
|
312
315
|
agentDbId: '',
|
|
313
316
|
allowConsultToQueue: false,
|
|
317
|
+
accessQueue: 'SPECIFIC',
|
|
318
|
+
accessEntryPoint: 'ALL',
|
|
319
|
+
accessBuddyTeam: 'ALL',
|
|
314
320
|
agentPersonalStatsEnabled: false,
|
|
315
321
|
isTimeoutDesktopInactivityEnabled: false,
|
|
316
322
|
webRtcEnabled: true,
|
|
@@ -404,6 +410,13 @@ describe('webex.cc', () => {
|
|
|
404
410
|
webRtcEnabled: mockAgentProfile.webRtcEnabled,
|
|
405
411
|
autoWrapup: mockAgentProfile.wrapUpData.wrapUpProps.autoWrapup ?? false,
|
|
406
412
|
aiFeature: mockAgentProfile.aiFeature,
|
|
413
|
+
consultTransfer: {
|
|
414
|
+
allowConsultToQueue: mockAgentProfile.allowConsultToQueue,
|
|
415
|
+
accessQueue: mockAgentProfile.accessQueue,
|
|
416
|
+
accessEntryPoint: mockAgentProfile.accessEntryPoint,
|
|
417
|
+
accessBuddyTeam: mockAgentProfile.accessBuddyTeam,
|
|
418
|
+
},
|
|
419
|
+
enableWxBetterTogether: false,
|
|
407
420
|
});
|
|
408
421
|
expect(reloadSpy).toHaveBeenCalled();
|
|
409
422
|
expect(result).toEqual(mockAgentProfile);
|
|
@@ -734,6 +747,7 @@ describe('webex.cc', () => {
|
|
|
734
747
|
METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
|
|
735
748
|
]);
|
|
736
749
|
expect(result).toEqual(responseMock);
|
|
750
|
+
expect(webex.cc.agentConfig.deviceType).toBe(LoginOption.BROWSER);
|
|
737
751
|
|
|
738
752
|
const onSpy = jest.spyOn(mockTaskManager, 'on');
|
|
739
753
|
const emitSpy = jest.spyOn(webex.cc, 'trigger');
|
|
@@ -1019,6 +1033,419 @@ describe('webex.cc', () => {
|
|
|
1019
1033
|
{module: CC_FILE, method: 'stationLogin', trackingId: error.details.trackingId}
|
|
1020
1034
|
);
|
|
1021
1035
|
});
|
|
1036
|
+
|
|
1037
|
+
it('should publish usersub and subscribe Mercury on station login when enableWxBetterTogether is true at init', async () => {
|
|
1038
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1039
|
+
webex.internal.device = {
|
|
1040
|
+
userId: 'user-123',
|
|
1041
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
1042
|
+
registered: true,
|
|
1043
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
1044
|
+
};
|
|
1045
|
+
webex.internal.mercury.connected = true;
|
|
1046
|
+
webex.internal.mercury.connect = jest.fn().mockResolvedValue(undefined);
|
|
1047
|
+
webex.cc.agentConfig = {
|
|
1048
|
+
agentId: 'agentId',
|
|
1049
|
+
webRtcEnabled: false,
|
|
1050
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1051
|
+
};
|
|
1052
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1053
|
+
|
|
1054
|
+
const publishSpy = jest
|
|
1055
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1056
|
+
.mockResolvedValue(undefined);
|
|
1057
|
+
const subscribeSpy = jest
|
|
1058
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe')
|
|
1059
|
+
.mockImplementation(() => {});
|
|
1060
|
+
|
|
1061
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1062
|
+
data: {
|
|
1063
|
+
agentId: 'agentId',
|
|
1064
|
+
teamId: 'teamId',
|
|
1065
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1066
|
+
},
|
|
1067
|
+
trackingId: 'track-1',
|
|
1068
|
+
} as StationLoginSuccess);
|
|
1069
|
+
|
|
1070
|
+
await webex.cc.stationLogin({
|
|
1071
|
+
teamId: 'teamId',
|
|
1072
|
+
loginOption: LoginOption.EXTENSION,
|
|
1073
|
+
dialNumber: '1001',
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
expect(publishSpy).toHaveBeenCalledWith(true, {userId: 'user-123'});
|
|
1077
|
+
expect(subscribeSpy).toHaveBeenCalledWith('agentId', expect.any(Function));
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
it('should rollback wxApp config when post-station-login init fails', async () => {
|
|
1081
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1082
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1083
|
+
webex.cc.agentConfig = {
|
|
1084
|
+
agentId: 'agentId',
|
|
1085
|
+
webRtcEnabled: false,
|
|
1086
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1087
|
+
};
|
|
1088
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1089
|
+
mockTaskManager.applyEnableWxBetterTogether(true);
|
|
1090
|
+
|
|
1091
|
+
jest
|
|
1092
|
+
.spyOn(webex.cc as never, 'publishAnswerOnWebexCrossClientState' as never)
|
|
1093
|
+
.mockRejectedValue(new Error('usersub publish failed'));
|
|
1094
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1095
|
+
|
|
1096
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1097
|
+
data: {
|
|
1098
|
+
agentId: 'agentId',
|
|
1099
|
+
teamId: 'teamId',
|
|
1100
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1101
|
+
},
|
|
1102
|
+
trackingId: 'track-1',
|
|
1103
|
+
} as StationLoginSuccess);
|
|
1104
|
+
|
|
1105
|
+
await webex.cc.stationLogin({
|
|
1106
|
+
teamId: 'teamId',
|
|
1107
|
+
loginOption: LoginOption.EXTENSION,
|
|
1108
|
+
dialNumber: '1001',
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1112
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
1113
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(false);
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
it('should reset wxApp config when Mercury fails before usersub publish on station login', async () => {
|
|
1117
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1118
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1119
|
+
webex.cc.agentConfig = {
|
|
1120
|
+
agentId: 'agentId',
|
|
1121
|
+
webRtcEnabled: false,
|
|
1122
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1123
|
+
};
|
|
1124
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1125
|
+
mockTaskManager.applyEnableWxBetterTogether(true);
|
|
1126
|
+
|
|
1127
|
+
const publishSpy = jest
|
|
1128
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1129
|
+
.mockResolvedValue(undefined);
|
|
1130
|
+
jest
|
|
1131
|
+
.spyOn(webex.cc as any, 'ensureWxAppMercuryConnected')
|
|
1132
|
+
.mockRejectedValue(new Error('mercury connect failed'));
|
|
1133
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1134
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1135
|
+
jest
|
|
1136
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
1137
|
+
.mockResolvedValue(undefined);
|
|
1138
|
+
|
|
1139
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1140
|
+
data: {
|
|
1141
|
+
agentId: 'agentId',
|
|
1142
|
+
teamId: 'teamId',
|
|
1143
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1144
|
+
},
|
|
1145
|
+
trackingId: 'track-1',
|
|
1146
|
+
} as StationLoginSuccess);
|
|
1147
|
+
|
|
1148
|
+
await webex.cc.stationLogin({
|
|
1149
|
+
teamId: 'teamId',
|
|
1150
|
+
loginOption: LoginOption.EXTENSION,
|
|
1151
|
+
dialNumber: '1001',
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
1155
|
+
expect(teardownSpy).not.toHaveBeenCalled();
|
|
1156
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1157
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
1158
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(false);
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
it('should register device before publishing usersub true on extension station login', async () => {
|
|
1162
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1163
|
+
webex.internal.device = {
|
|
1164
|
+
userId: 'user-123',
|
|
1165
|
+
registered: false,
|
|
1166
|
+
register: jest.fn().mockImplementation(async function (this: {
|
|
1167
|
+
url?: string;
|
|
1168
|
+
registered?: boolean;
|
|
1169
|
+
}) {
|
|
1170
|
+
this.url = 'https://wdm.example.com/devices/dev-1';
|
|
1171
|
+
this.registered = true;
|
|
1172
|
+
}),
|
|
1173
|
+
};
|
|
1174
|
+
webex.internal.mercury = {
|
|
1175
|
+
connected: false,
|
|
1176
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
1177
|
+
};
|
|
1178
|
+
webex.cc.agentConfig = {
|
|
1179
|
+
agentId: 'agentId',
|
|
1180
|
+
webRtcEnabled: false,
|
|
1181
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1182
|
+
};
|
|
1183
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1184
|
+
jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe').mockImplementation(() => {});
|
|
1185
|
+
|
|
1186
|
+
const callOrder: string[] = [];
|
|
1187
|
+
jest.spyOn(webex.internal.device, 'register').mockImplementation(async function (this: {
|
|
1188
|
+
url?: string;
|
|
1189
|
+
registered?: boolean;
|
|
1190
|
+
}) {
|
|
1191
|
+
callOrder.push('device.register');
|
|
1192
|
+
this.url = 'https://wdm.example.com/devices/dev-1';
|
|
1193
|
+
this.registered = true;
|
|
1194
|
+
});
|
|
1195
|
+
jest
|
|
1196
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1197
|
+
.mockImplementation(async (enable: boolean) => {
|
|
1198
|
+
if (enable === true && !webex.internal.device.url) {
|
|
1199
|
+
throw new Error('Device URL is unavailable for cross-client publish');
|
|
1200
|
+
}
|
|
1201
|
+
callOrder.push(enable ? 'publish:true' : 'publish:false');
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1205
|
+
data: {
|
|
1206
|
+
agentId: 'agentId',
|
|
1207
|
+
teamId: 'teamId',
|
|
1208
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1209
|
+
},
|
|
1210
|
+
trackingId: 'track-1',
|
|
1211
|
+
} as StationLoginSuccess);
|
|
1212
|
+
|
|
1213
|
+
await webex.cc.stationLogin({
|
|
1214
|
+
teamId: 'teamId',
|
|
1215
|
+
loginOption: LoginOption.EXTENSION,
|
|
1216
|
+
dialNumber: '1001',
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
expect(callOrder).toEqual(['device.register', 'publish:true']);
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
it('should register device before publishing forced usersub false when wxApp is disabled at station login', async () => {
|
|
1223
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
1224
|
+
webex.internal.device = {
|
|
1225
|
+
userId: 'user-123',
|
|
1226
|
+
registered: false,
|
|
1227
|
+
register: jest.fn().mockImplementation(async function (this: {
|
|
1228
|
+
url?: string;
|
|
1229
|
+
registered?: boolean;
|
|
1230
|
+
}) {
|
|
1231
|
+
this.url = 'https://wdm.example.com/devices/dev-1';
|
|
1232
|
+
this.registered = true;
|
|
1233
|
+
}),
|
|
1234
|
+
};
|
|
1235
|
+
webex.internal.mercury = {
|
|
1236
|
+
connected: false,
|
|
1237
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
1238
|
+
};
|
|
1239
|
+
webex.cc.agentConfig = {
|
|
1240
|
+
agentId: 'agentId',
|
|
1241
|
+
webRtcEnabled: false,
|
|
1242
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1243
|
+
};
|
|
1244
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1245
|
+
jest
|
|
1246
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
1247
|
+
.mockResolvedValue(undefined);
|
|
1248
|
+
|
|
1249
|
+
const callOrder: string[] = [];
|
|
1250
|
+
jest.spyOn(webex.internal.device, 'register').mockImplementation(async function (this: {
|
|
1251
|
+
url?: string;
|
|
1252
|
+
registered?: boolean;
|
|
1253
|
+
}) {
|
|
1254
|
+
callOrder.push('device.register');
|
|
1255
|
+
this.url = 'https://wdm.example.com/devices/dev-1';
|
|
1256
|
+
this.registered = true;
|
|
1257
|
+
});
|
|
1258
|
+
jest
|
|
1259
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1260
|
+
.mockImplementation(async (enable: boolean) => {
|
|
1261
|
+
if (!webex.internal.device.url) {
|
|
1262
|
+
throw new Error('Device URL is unavailable for cross-client publish');
|
|
1263
|
+
}
|
|
1264
|
+
callOrder.push(enable ? 'publish:true' : 'publish:false');
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1268
|
+
data: {
|
|
1269
|
+
agentId: 'agentId',
|
|
1270
|
+
teamId: 'teamId',
|
|
1271
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1272
|
+
},
|
|
1273
|
+
trackingId: 'track-1',
|
|
1274
|
+
} as StationLoginSuccess);
|
|
1275
|
+
|
|
1276
|
+
await webex.cc.stationLogin({
|
|
1277
|
+
teamId: 'teamId',
|
|
1278
|
+
loginOption: LoginOption.EXTENSION,
|
|
1279
|
+
dialNumber: '1001',
|
|
1280
|
+
});
|
|
1281
|
+
|
|
1282
|
+
expect(callOrder).toEqual(['device.register', 'publish:false']);
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
it('should retry forced false publish when wxApp is disabled at station login', async () => {
|
|
1286
|
+
jest.useFakeTimers();
|
|
1287
|
+
try {
|
|
1288
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
1289
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1290
|
+
webex.cc.agentConfig = {
|
|
1291
|
+
agentId: 'agentId',
|
|
1292
|
+
webRtcEnabled: false,
|
|
1293
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1294
|
+
};
|
|
1295
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1296
|
+
|
|
1297
|
+
const publishSpy = jest
|
|
1298
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1299
|
+
.mockRejectedValueOnce(new Error('usersub publish failed'))
|
|
1300
|
+
.mockResolvedValue(undefined);
|
|
1301
|
+
const scheduleRetrySpy = jest.spyOn(
|
|
1302
|
+
webex.cc as any,
|
|
1303
|
+
'scheduleForcedFalsePublishRetry'
|
|
1304
|
+
);
|
|
1305
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1306
|
+
jest
|
|
1307
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
1308
|
+
.mockResolvedValue(undefined);
|
|
1309
|
+
|
|
1310
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1311
|
+
data: {
|
|
1312
|
+
agentId: 'agentId',
|
|
1313
|
+
teamId: 'teamId',
|
|
1314
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1315
|
+
},
|
|
1316
|
+
trackingId: 'track-1',
|
|
1317
|
+
} as StationLoginSuccess);
|
|
1318
|
+
|
|
1319
|
+
await webex.cc.stationLogin({
|
|
1320
|
+
teamId: 'teamId',
|
|
1321
|
+
loginOption: LoginOption.EXTENSION,
|
|
1322
|
+
dialNumber: '1001',
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
expect(publishSpy).toHaveBeenCalledTimes(1);
|
|
1326
|
+
expect(scheduleRetrySpy).toHaveBeenCalled();
|
|
1327
|
+
expect(teardownSpy).not.toHaveBeenCalled();
|
|
1328
|
+
|
|
1329
|
+
jest.advanceTimersByTime(30_000);
|
|
1330
|
+
await publishSpy.mock.results[1]?.value;
|
|
1331
|
+
|
|
1332
|
+
expect(publishSpy).toHaveBeenCalledTimes(2);
|
|
1333
|
+
expect(publishSpy).toHaveBeenLastCalledWith(false, {userId: 'user-123'});
|
|
1334
|
+
} finally {
|
|
1335
|
+
jest.useRealTimers();
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
it('should not publish usersub on BROWSER station login even when enableWxBetterTogether is true at init', async () => {
|
|
1340
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1341
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1342
|
+
webex.cc.agentConfig = {
|
|
1343
|
+
agentId: 'agentId',
|
|
1344
|
+
webRtcEnabled: true,
|
|
1345
|
+
loginVoiceOptions: ['BROWSER'],
|
|
1346
|
+
};
|
|
1347
|
+
webex.cc.webCallingService.loginOption = LoginOption.BROWSER;
|
|
1348
|
+
|
|
1349
|
+
const publishSpy = jest.spyOn(
|
|
1350
|
+
webex.cc['webexCrossClientService'],
|
|
1351
|
+
'setManageWebexCallingInWxcc'
|
|
1352
|
+
);
|
|
1353
|
+
|
|
1354
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1355
|
+
data: {
|
|
1356
|
+
agentId: 'agentId',
|
|
1357
|
+
teamId: 'teamId',
|
|
1358
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1359
|
+
},
|
|
1360
|
+
trackingId: 'track-1',
|
|
1361
|
+
} as StationLoginSuccess);
|
|
1362
|
+
|
|
1363
|
+
await webex.cc.stationLogin({
|
|
1364
|
+
teamId: 'teamId',
|
|
1365
|
+
loginOption: LoginOption.BROWSER,
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1368
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
it('should force-publish usersub false on station login when enableWxBetterTogether is false at init', async () => {
|
|
1372
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
1373
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1374
|
+
webex.cc.agentConfig = {
|
|
1375
|
+
agentId: 'agentId',
|
|
1376
|
+
webRtcEnabled: false,
|
|
1377
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1378
|
+
};
|
|
1379
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1380
|
+
|
|
1381
|
+
const publishSpy = jest
|
|
1382
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1383
|
+
.mockResolvedValue(undefined);
|
|
1384
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1385
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1386
|
+
|
|
1387
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1388
|
+
data: {
|
|
1389
|
+
agentId: 'agentId',
|
|
1390
|
+
teamId: 'teamId',
|
|
1391
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1392
|
+
},
|
|
1393
|
+
trackingId: 'track-1',
|
|
1394
|
+
} as StationLoginSuccess);
|
|
1395
|
+
|
|
1396
|
+
await webex.cc.stationLogin({
|
|
1397
|
+
teamId: 'teamId',
|
|
1398
|
+
loginOption: LoginOption.EXTENSION,
|
|
1399
|
+
dialNumber: '1001',
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
1403
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
1404
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
it('should clear stale usersub on login after prior session enabled wxApp then hard refresh', async () => {
|
|
1408
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
1409
|
+
webex.cc.agentConfig = {
|
|
1410
|
+
agentId: 'agentId',
|
|
1411
|
+
webRtcEnabled: false,
|
|
1412
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1413
|
+
};
|
|
1414
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1415
|
+
webex.request = jest.fn().mockResolvedValue({body: {}});
|
|
1416
|
+
|
|
1417
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1418
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1419
|
+
data: {
|
|
1420
|
+
agentId: 'agentId',
|
|
1421
|
+
teamId: 'teamId',
|
|
1422
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1423
|
+
},
|
|
1424
|
+
trackingId: 'track-1',
|
|
1425
|
+
} as StationLoginSuccess);
|
|
1426
|
+
|
|
1427
|
+
await webex.cc.stationLogin({
|
|
1428
|
+
teamId: 'teamId',
|
|
1429
|
+
loginOption: LoginOption.EXTENSION,
|
|
1430
|
+
dialNumber: '1001',
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
webex.cc['webexCrossClientService'].teardown();
|
|
1434
|
+
webex.cc['wxAppTelephonyMercurySync'].unsubscribe();
|
|
1435
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
1436
|
+
|
|
1437
|
+
const publishSpy = jest
|
|
1438
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1439
|
+
.mockResolvedValue(undefined);
|
|
1440
|
+
|
|
1441
|
+
await webex.cc.stationLogin({
|
|
1442
|
+
teamId: 'teamId',
|
|
1443
|
+
loginOption: LoginOption.EXTENSION,
|
|
1444
|
+
dialNumber: '1001',
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
1448
|
+
});
|
|
1022
1449
|
});
|
|
1023
1450
|
|
|
1024
1451
|
describe('stationLogout', () => {
|
|
@@ -1061,6 +1488,214 @@ describe('webex.cc', () => {
|
|
|
1061
1488
|
]);
|
|
1062
1489
|
});
|
|
1063
1490
|
|
|
1491
|
+
it('should not publish usersub false on logout when wxApp was never enabled', async () => {
|
|
1492
|
+
webex.internal.device = {userId: 'user-123'};
|
|
1493
|
+
const publishSpy = jest
|
|
1494
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1495
|
+
.mockResolvedValue(undefined);
|
|
1496
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1497
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1498
|
+
|
|
1499
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
1500
|
+
trackingId: 'track-1',
|
|
1501
|
+
} as StationLogoutResponse);
|
|
1502
|
+
|
|
1503
|
+
await webex.cc.stationLogout({logoutReason: 'Logout reason'});
|
|
1504
|
+
|
|
1505
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
1506
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
1507
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
it('should publish usersub false and teardown wxApp sync on logout when wxApp was enabled', async () => {
|
|
1511
|
+
webex.internal.device = {
|
|
1512
|
+
userId: 'user-123',
|
|
1513
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
1514
|
+
registered: false,
|
|
1515
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
1516
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
1517
|
+
};
|
|
1518
|
+
webex.internal.mercury = {
|
|
1519
|
+
connected: false,
|
|
1520
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
1521
|
+
disconnect: jest.fn().mockResolvedValue(undefined),
|
|
1522
|
+
};
|
|
1523
|
+
jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe').mockImplementation(() => {});
|
|
1524
|
+
webex.request = jest.fn().mockResolvedValue({body: {}});
|
|
1525
|
+
webex.cc['agentConfig'] = {
|
|
1526
|
+
agentId: 'agent-123',
|
|
1527
|
+
deviceType: LoginOption.EXTENSION,
|
|
1528
|
+
} as Profile;
|
|
1529
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1530
|
+
|
|
1531
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
1532
|
+
|
|
1533
|
+
const publishSpy = jest
|
|
1534
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1535
|
+
.mockResolvedValue(undefined);
|
|
1536
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1537
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1538
|
+
|
|
1539
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
1540
|
+
trackingId: 'track-1',
|
|
1541
|
+
} as StationLogoutResponse);
|
|
1542
|
+
|
|
1543
|
+
await webex.cc.stationLogout({logoutReason: 'Logout reason'});
|
|
1544
|
+
|
|
1545
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
1546
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
1547
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
it('should teardown wxApp state on logout even when usersub publish fails', async () => {
|
|
1551
|
+
webex.internal.device = {userId: 'user-123'};
|
|
1552
|
+
webex.cc['agentConfig'] = {
|
|
1553
|
+
agentId: 'agent-123',
|
|
1554
|
+
deviceType: LoginOption.EXTENSION,
|
|
1555
|
+
} as Profile;
|
|
1556
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1557
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1558
|
+
mockTaskManager.applyEnableWxBetterTogether(true);
|
|
1559
|
+
|
|
1560
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
1561
|
+
trackingId: 'track-1',
|
|
1562
|
+
} as StationLogoutResponse);
|
|
1563
|
+
jest
|
|
1564
|
+
.spyOn(webex.cc as never, 'publishAnswerOnWebexCrossClientState' as never)
|
|
1565
|
+
.mockRejectedValue(new Error('usersub publish failed'));
|
|
1566
|
+
const scheduleRetrySpy = jest.spyOn(
|
|
1567
|
+
webex.cc as any,
|
|
1568
|
+
'scheduleCompensatingFalsePublishRetry'
|
|
1569
|
+
);
|
|
1570
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1571
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1572
|
+
|
|
1573
|
+
const result = await webex.cc.stationLogout({logoutReason: 'Logout reason'});
|
|
1574
|
+
|
|
1575
|
+
expect(result).toEqual({trackingId: 'track-1'});
|
|
1576
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
1577
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1578
|
+
expect(scheduleRetrySpy).toHaveBeenCalled();
|
|
1579
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(true);
|
|
1580
|
+
});
|
|
1581
|
+
|
|
1582
|
+
it('should retry compensating false publish when teardown usersub publish fails on logout', async () => {
|
|
1583
|
+
jest.useFakeTimers();
|
|
1584
|
+
try {
|
|
1585
|
+
webex.internal.device = {
|
|
1586
|
+
userId: 'user-123',
|
|
1587
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
1588
|
+
};
|
|
1589
|
+
webex.cc['agentConfig'] = {
|
|
1590
|
+
agentId: 'agent-123',
|
|
1591
|
+
deviceType: LoginOption.EXTENSION,
|
|
1592
|
+
} as Profile;
|
|
1593
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1594
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1595
|
+
mockTaskManager.applyEnableWxBetterTogether(true);
|
|
1596
|
+
webex.cc['webexCrossClientService'].answerCallsState = true;
|
|
1597
|
+
|
|
1598
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
1599
|
+
trackingId: 'track-1',
|
|
1600
|
+
} as StationLogoutResponse);
|
|
1601
|
+
|
|
1602
|
+
const publishSpy = jest
|
|
1603
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1604
|
+
.mockRejectedValueOnce(new Error('usersub publish failed'))
|
|
1605
|
+
.mockResolvedValue(undefined);
|
|
1606
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1607
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
1608
|
+
jest
|
|
1609
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
1610
|
+
.mockResolvedValue(undefined);
|
|
1611
|
+
|
|
1612
|
+
const result = await webex.cc.stationLogout({logoutReason: 'Logout reason'});
|
|
1613
|
+
|
|
1614
|
+
expect(result).toEqual({trackingId: 'track-1'});
|
|
1615
|
+
expect(publishSpy).toHaveBeenCalledTimes(1);
|
|
1616
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
1617
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
1618
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
1619
|
+
|
|
1620
|
+
jest.advanceTimersByTime(30_000);
|
|
1621
|
+
await publishSpy.mock.results[1]?.value;
|
|
1622
|
+
|
|
1623
|
+
expect(publishSpy).toHaveBeenCalledTimes(2);
|
|
1624
|
+
expect(publishSpy).toHaveBeenLastCalledWith(false, {userId: 'user-123'});
|
|
1625
|
+
} finally {
|
|
1626
|
+
jest.useRealTimers();
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
it('should cancel compensating retry when station login succeeds before retry fires', async () => {
|
|
1631
|
+
jest.useFakeTimers();
|
|
1632
|
+
try {
|
|
1633
|
+
webex.internal.device = {
|
|
1634
|
+
userId: 'user-123',
|
|
1635
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
1636
|
+
registered: false,
|
|
1637
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
1638
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
1639
|
+
};
|
|
1640
|
+
webex.internal.mercury = {
|
|
1641
|
+
connected: false,
|
|
1642
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
1643
|
+
disconnect: jest.fn().mockResolvedValue(undefined),
|
|
1644
|
+
};
|
|
1645
|
+
jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe').mockImplementation(() => {});
|
|
1646
|
+
webex.cc['agentConfig'] = {
|
|
1647
|
+
agentId: 'agent-123',
|
|
1648
|
+
deviceType: LoginOption.EXTENSION,
|
|
1649
|
+
webRtcEnabled: false,
|
|
1650
|
+
loginVoiceOptions: ['EXTENSION'],
|
|
1651
|
+
} as Profile;
|
|
1652
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
1653
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
1654
|
+
mockTaskManager.applyEnableWxBetterTogether(true);
|
|
1655
|
+
webex.cc['webexCrossClientService'].answerCallsState = true;
|
|
1656
|
+
|
|
1657
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
1658
|
+
trackingId: 'track-1',
|
|
1659
|
+
} as StationLogoutResponse);
|
|
1660
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
1661
|
+
data: {
|
|
1662
|
+
agentId: 'agent-123',
|
|
1663
|
+
teamId: 'team-123',
|
|
1664
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
1665
|
+
},
|
|
1666
|
+
trackingId: 'track-2',
|
|
1667
|
+
} as StationLoginSuccess);
|
|
1668
|
+
|
|
1669
|
+
const publishSpy = jest
|
|
1670
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
1671
|
+
.mockRejectedValueOnce(new Error('usersub publish failed'))
|
|
1672
|
+
.mockResolvedValue(undefined);
|
|
1673
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
1674
|
+
jest
|
|
1675
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
1676
|
+
.mockResolvedValue(undefined);
|
|
1677
|
+
|
|
1678
|
+
await webex.cc.stationLogout({logoutReason: 'Logout reason'});
|
|
1679
|
+
await webex.cc.stationLogin({
|
|
1680
|
+
teamId: 'team-123',
|
|
1681
|
+
loginOption: LoginOption.EXTENSION,
|
|
1682
|
+
dialNumber: '1001',
|
|
1683
|
+
});
|
|
1684
|
+
|
|
1685
|
+
expect(publishSpy).toHaveBeenCalledTimes(2);
|
|
1686
|
+
expect(publishSpy).toHaveBeenNthCalledWith(1, false, {userId: 'user-123'});
|
|
1687
|
+
expect(publishSpy).toHaveBeenNthCalledWith(2, true, {userId: 'user-123'});
|
|
1688
|
+
expect(teardownSpy).toHaveBeenCalledTimes(1);
|
|
1689
|
+
|
|
1690
|
+
jest.advanceTimersByTime(30_000);
|
|
1691
|
+
|
|
1692
|
+
expect(publishSpy).toHaveBeenCalledTimes(2);
|
|
1693
|
+
expect(teardownSpy).toHaveBeenCalledTimes(1);
|
|
1694
|
+
} finally {
|
|
1695
|
+
jest.useRealTimers();
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1064
1699
|
it('should handle error during stationLogout', async () => {
|
|
1065
1700
|
const data = {logoutReason: 'Logout reason'};
|
|
1066
1701
|
const error = {
|
|
@@ -1276,6 +1911,41 @@ describe('webex.cc', () => {
|
|
|
1276
1911
|
]);
|
|
1277
1912
|
});
|
|
1278
1913
|
|
|
1914
|
+
it('should map Transfer action to an Available backend state filter', async () => {
|
|
1915
|
+
webex.cc.agentConfig = {agentProfileID: 'test-agent-profile-id'};
|
|
1916
|
+
const buddyAgentsResponse = {data: {agentList: []}};
|
|
1917
|
+
const buddyAgentsSpy = jest
|
|
1918
|
+
.spyOn(webex.cc.services.agent, 'buddyAgents')
|
|
1919
|
+
.mockResolvedValue(buddyAgentsResponse);
|
|
1920
|
+
|
|
1921
|
+
await webex.cc.getBuddyAgents({action: 'Transfer', mediaType: 'chat'});
|
|
1922
|
+
|
|
1923
|
+
expect(buddyAgentsSpy).toHaveBeenCalledWith({
|
|
1924
|
+
data: {
|
|
1925
|
+
agentProfileId: 'test-agent-profile-id',
|
|
1926
|
+
mediaType: 'chat',
|
|
1927
|
+
state: 'Available',
|
|
1928
|
+
},
|
|
1929
|
+
});
|
|
1930
|
+
});
|
|
1931
|
+
|
|
1932
|
+
it('should omit the backend state filter for Consult and default media type to telephony', async () => {
|
|
1933
|
+
webex.cc.agentConfig = {agentProfileID: 'test-agent-profile-id'};
|
|
1934
|
+
const buddyAgentsResponse = {data: {agentList: []}};
|
|
1935
|
+
const buddyAgentsSpy = jest
|
|
1936
|
+
.spyOn(webex.cc.services.agent, 'buddyAgents')
|
|
1937
|
+
.mockResolvedValue(buddyAgentsResponse);
|
|
1938
|
+
|
|
1939
|
+
await webex.cc.getBuddyAgents({action: 'Consult'});
|
|
1940
|
+
|
|
1941
|
+
expect(buddyAgentsSpy).toHaveBeenCalledWith({
|
|
1942
|
+
data: {
|
|
1943
|
+
agentProfileId: 'test-agent-profile-id',
|
|
1944
|
+
mediaType: 'telephony',
|
|
1945
|
+
},
|
|
1946
|
+
});
|
|
1947
|
+
});
|
|
1948
|
+
|
|
1279
1949
|
it('should handle error', async () => {
|
|
1280
1950
|
const data: BuddyAgents = {state: 'Available', mediaType: 'telephony'};
|
|
1281
1951
|
webex.cc.agentConfig = {
|
|
@@ -1503,6 +2173,81 @@ describe('webex.cc', () => {
|
|
|
1503
2173
|
expect(webex.cc.agentConfig.deviceType).toBe(LoginOption.AGENT_DN);
|
|
1504
2174
|
expect(webex.cc.agentConfig.dn).toBe('67890');
|
|
1505
2175
|
});
|
|
2176
|
+
|
|
2177
|
+
it('should publish usersub true on silent relogin when enableWxBetterTogether is true at init', async () => {
|
|
2178
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
2179
|
+
webex.internal.device = {
|
|
2180
|
+
userId: 'user-123',
|
|
2181
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
2182
|
+
registered: true,
|
|
2183
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
2184
|
+
};
|
|
2185
|
+
webex.internal.mercury.connected = true;
|
|
2186
|
+
webex.internal.mercury.connect = jest.fn().mockResolvedValue(undefined);
|
|
2187
|
+
webex.cc.agentConfig = {
|
|
2188
|
+
agentId: 'agentId',
|
|
2189
|
+
agentProfileID: 'test-agent-profile-id',
|
|
2190
|
+
isAgentLoggedIn: false,
|
|
2191
|
+
} as Profile;
|
|
2192
|
+
|
|
2193
|
+
jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue({
|
|
2194
|
+
data: {
|
|
2195
|
+
auxCodeId: 'auxCodeId',
|
|
2196
|
+
agentId: 'agentId',
|
|
2197
|
+
deviceType: LoginOption.EXTENSION,
|
|
2198
|
+
dn: '1001',
|
|
2199
|
+
teamId: 'teamId',
|
|
2200
|
+
lastStateChangeTimestamp: 1738575135188,
|
|
2201
|
+
lastIdleCodeChangeTimestamp: 1738575135189,
|
|
2202
|
+
},
|
|
2203
|
+
});
|
|
2204
|
+
|
|
2205
|
+
const publishSpy = jest
|
|
2206
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
2207
|
+
.mockResolvedValue(undefined);
|
|
2208
|
+
const subscribeSpy = jest
|
|
2209
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe')
|
|
2210
|
+
.mockImplementation(() => {});
|
|
2211
|
+
|
|
2212
|
+
await webex.cc['silentRelogin']();
|
|
2213
|
+
|
|
2214
|
+
expect(publishSpy).toHaveBeenCalledWith(true, {userId: 'user-123'});
|
|
2215
|
+
expect(subscribeSpy).toHaveBeenCalledWith('agentId', expect.any(Function));
|
|
2216
|
+
});
|
|
2217
|
+
|
|
2218
|
+
it('should force-publish usersub false on silent relogin when enableWxBetterTogether is false at init', async () => {
|
|
2219
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
2220
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
2221
|
+
webex.cc.agentConfig = {
|
|
2222
|
+
agentId: 'agentId',
|
|
2223
|
+
agentProfileID: 'test-agent-profile-id',
|
|
2224
|
+
isAgentLoggedIn: false,
|
|
2225
|
+
} as Profile;
|
|
2226
|
+
|
|
2227
|
+
jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue({
|
|
2228
|
+
data: {
|
|
2229
|
+
auxCodeId: 'auxCodeId',
|
|
2230
|
+
agentId: 'agentId',
|
|
2231
|
+
deviceType: LoginOption.EXTENSION,
|
|
2232
|
+
dn: '1001',
|
|
2233
|
+
teamId: 'teamId',
|
|
2234
|
+
lastStateChangeTimestamp: 1738575135188,
|
|
2235
|
+
lastIdleCodeChangeTimestamp: 1738575135189,
|
|
2236
|
+
},
|
|
2237
|
+
});
|
|
2238
|
+
|
|
2239
|
+
const publishSpy = jest
|
|
2240
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
2241
|
+
.mockResolvedValue(undefined);
|
|
2242
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
2243
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
2244
|
+
|
|
2245
|
+
await webex.cc['silentRelogin']();
|
|
2246
|
+
|
|
2247
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
2248
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
2249
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
2250
|
+
});
|
|
1506
2251
|
});
|
|
1507
2252
|
|
|
1508
2253
|
describe('setupEventListeners()', () => {
|
|
@@ -1741,6 +2486,18 @@ describe('webex.cc', () => {
|
|
|
1741
2486
|
on: jest.fn(),
|
|
1742
2487
|
} as any;
|
|
1743
2488
|
|
|
2489
|
+
webex.internal.device = {
|
|
2490
|
+
...webex.internal.device,
|
|
2491
|
+
userId: 'user-123',
|
|
2492
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
2493
|
+
};
|
|
2494
|
+
deviceUnregisterSpy = jest.spyOn(webex.internal.device, 'unregister');
|
|
2495
|
+
const publishSpy = jest
|
|
2496
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
2497
|
+
.mockResolvedValue(undefined);
|
|
2498
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
2499
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
2500
|
+
|
|
1744
2501
|
await webex.cc.deregister();
|
|
1745
2502
|
|
|
1746
2503
|
expect(mockTaskManager.off).toHaveBeenCalledWith(
|
|
@@ -1829,6 +2586,39 @@ describe('webex.cc', () => {
|
|
|
1829
2586
|
expect(connectionCalls).toHaveLength(1);
|
|
1830
2587
|
const [, connectionCallback] = connectionCalls[0];
|
|
1831
2588
|
expect(connectionCallback).toBe(webex.cc['handleConnectionLost']);
|
|
2589
|
+
|
|
2590
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
2591
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
2592
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
2593
|
+
});
|
|
2594
|
+
|
|
2595
|
+
it('should publish usersub false before device unregister when wxApp is active on deregister', async () => {
|
|
2596
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
2597
|
+
webex.cc['webexCrossClientService'].answerCallsState = true;
|
|
2598
|
+
webex.internal.device = {
|
|
2599
|
+
userId: 'user-123',
|
|
2600
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
2601
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
2602
|
+
};
|
|
2603
|
+
deviceUnregisterSpy = jest.spyOn(webex.internal.device, 'unregister');
|
|
2604
|
+
|
|
2605
|
+
const callOrder: string[] = [];
|
|
2606
|
+
jest
|
|
2607
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
2608
|
+
.mockImplementation(async (enable: boolean) => {
|
|
2609
|
+
if (enable === false && !webex.internal.device.url) {
|
|
2610
|
+
throw new Error('Device URL is unavailable for cross-client publish');
|
|
2611
|
+
}
|
|
2612
|
+
callOrder.push(enable ? 'publish:true' : 'publish:false');
|
|
2613
|
+
});
|
|
2614
|
+
deviceUnregisterSpy.mockImplementation(async () => {
|
|
2615
|
+
callOrder.push('device.unregister');
|
|
2616
|
+
webex.internal.device.url = undefined;
|
|
2617
|
+
});
|
|
2618
|
+
|
|
2619
|
+
await webex.cc.deregister();
|
|
2620
|
+
|
|
2621
|
+
expect(callOrder).toEqual(['publish:false', 'device.unregister']);
|
|
1832
2622
|
});
|
|
1833
2623
|
|
|
1834
2624
|
it('should skip webCallingService and internal cleanup when webrtc is disabled', async () => {
|
|
@@ -1878,6 +2668,135 @@ describe('webex.cc', () => {
|
|
|
1878
2668
|
expect(webex.cc.agentConfig).toBeNull();
|
|
1879
2669
|
});
|
|
1880
2670
|
|
|
2671
|
+
it('should teardown wxApp state on deregister even when usersub publish fails', async () => {
|
|
2672
|
+
webex.cc.agentConfig = {
|
|
2673
|
+
agentId: 'agentId',
|
|
2674
|
+
webRtcEnabled: false,
|
|
2675
|
+
loginVoiceOptions: [LoginOption.EXTENSION],
|
|
2676
|
+
};
|
|
2677
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
2678
|
+
webex.cc['webexCrossClientService'].answerCallsState = true;
|
|
2679
|
+
webex.internal.device = {
|
|
2680
|
+
userId: 'user-123',
|
|
2681
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
2682
|
+
};
|
|
2683
|
+
|
|
2684
|
+
jest
|
|
2685
|
+
.spyOn(webex.cc as never, 'publishAnswerOnWebexCrossClientState' as never)
|
|
2686
|
+
.mockRejectedValue(new Error('usersub publish failed'));
|
|
2687
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
2688
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
2689
|
+
|
|
2690
|
+
await expect(webex.cc.deregister()).rejects.toThrow('usersub publish failed');
|
|
2691
|
+
|
|
2692
|
+
expect(teardownSpy).toHaveBeenCalled();
|
|
2693
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
2694
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
2695
|
+
expect(mockWebSocketManager.close).toHaveBeenCalledWith(false, 'Unregistering the SDK');
|
|
2696
|
+
expect(webex.cc.agentConfig).toBeNull();
|
|
2697
|
+
});
|
|
2698
|
+
|
|
2699
|
+
it('should publish forced false during teardown when enable publish is still in flight', async () => {
|
|
2700
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
2701
|
+
webex.internal.device = {
|
|
2702
|
+
userId: 'user-123',
|
|
2703
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
2704
|
+
};
|
|
2705
|
+
|
|
2706
|
+
let resolveEnable: () => void = () => {};
|
|
2707
|
+
const enableGate = new Promise<void>((resolve) => {
|
|
2708
|
+
resolveEnable = resolve;
|
|
2709
|
+
});
|
|
2710
|
+
|
|
2711
|
+
const publishSpy = jest
|
|
2712
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
2713
|
+
.mockImplementation(async (enable: boolean) => {
|
|
2714
|
+
if (enable) {
|
|
2715
|
+
await enableGate;
|
|
2716
|
+
}
|
|
2717
|
+
});
|
|
2718
|
+
jest
|
|
2719
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
2720
|
+
.mockResolvedValue(undefined);
|
|
2721
|
+
|
|
2722
|
+
expect(webex.cc['webexCrossClientService'].answerCallsState).toBe(false);
|
|
2723
|
+
|
|
2724
|
+
const enableInFlight = (webex.cc as any).publishAnswerOnWebexCrossClientState(true);
|
|
2725
|
+
|
|
2726
|
+
await (webex.cc as any).teardownWxAppLocalState();
|
|
2727
|
+
|
|
2728
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
2729
|
+
|
|
2730
|
+
resolveEnable();
|
|
2731
|
+
await enableInFlight;
|
|
2732
|
+
});
|
|
2733
|
+
|
|
2734
|
+
it('should release wxApp-owned Mercury and device on deregister', async () => {
|
|
2735
|
+
webex.cc.agentConfig = {
|
|
2736
|
+
agentId: 'agentId',
|
|
2737
|
+
webRtcEnabled: false,
|
|
2738
|
+
loginVoiceOptions: [LoginOption.EXTENSION],
|
|
2739
|
+
};
|
|
2740
|
+
webex.cc['wxAppMercuryConnectedByCc'] = true;
|
|
2741
|
+
webex.cc['wxAppDeviceRegisteredByCc'] = true;
|
|
2742
|
+
webex.internal.mercury.connected = true;
|
|
2743
|
+
webex.internal.device.registered = true;
|
|
2744
|
+
|
|
2745
|
+
const mercuryDisconnectSpy = jest
|
|
2746
|
+
.spyOn(webex.internal.mercury, 'disconnect')
|
|
2747
|
+
.mockResolvedValue(undefined);
|
|
2748
|
+
const deviceUnregisterSpy = jest
|
|
2749
|
+
.spyOn(webex.internal.device, 'unregister')
|
|
2750
|
+
.mockResolvedValue(undefined);
|
|
2751
|
+
|
|
2752
|
+
await webex.cc.deregister();
|
|
2753
|
+
|
|
2754
|
+
expect(mercuryDisconnectSpy).toHaveBeenCalled();
|
|
2755
|
+
expect(deviceUnregisterSpy).toHaveBeenCalled();
|
|
2756
|
+
expect(webex.cc['wxAppMercuryConnectedByCc']).toBe(false);
|
|
2757
|
+
expect(webex.cc['wxAppDeviceRegisteredByCc']).toBe(false);
|
|
2758
|
+
});
|
|
2759
|
+
|
|
2760
|
+
it('should retain wxApp Mercury ownership when disconnect fails and retry cleanup', async () => {
|
|
2761
|
+
webex.cc['wxAppMercuryConnectedByCc'] = true;
|
|
2762
|
+
webex.internal.mercury.connected = true;
|
|
2763
|
+
|
|
2764
|
+
const mercuryDisconnectSpy = jest
|
|
2765
|
+
.spyOn(webex.internal.mercury, 'disconnect')
|
|
2766
|
+
.mockRejectedValueOnce(new Error('disconnect failed'))
|
|
2767
|
+
.mockResolvedValueOnce(undefined);
|
|
2768
|
+
|
|
2769
|
+
await webex.cc['releaseWxAppMercuryResources']();
|
|
2770
|
+
|
|
2771
|
+
expect(mercuryDisconnectSpy).toHaveBeenCalledTimes(1);
|
|
2772
|
+
expect(webex.cc['wxAppMercuryConnectedByCc']).toBe(true);
|
|
2773
|
+
|
|
2774
|
+
await webex.cc['releaseWxAppMercuryResources']();
|
|
2775
|
+
|
|
2776
|
+
expect(mercuryDisconnectSpy).toHaveBeenCalledTimes(2);
|
|
2777
|
+
expect(webex.cc['wxAppMercuryConnectedByCc']).toBe(false);
|
|
2778
|
+
});
|
|
2779
|
+
|
|
2780
|
+
it('should retain wxApp device ownership when unregister fails and retry cleanup', async () => {
|
|
2781
|
+
webex.cc['wxAppDeviceRegisteredByCc'] = true;
|
|
2782
|
+
webex.internal.device.registered = true;
|
|
2783
|
+
|
|
2784
|
+
const deviceUnregisterSpy = jest
|
|
2785
|
+
.spyOn(webex.internal.device, 'unregister')
|
|
2786
|
+
.mockRejectedValueOnce(new Error('unregister failed'))
|
|
2787
|
+
.mockResolvedValueOnce(undefined);
|
|
2788
|
+
|
|
2789
|
+
await webex.cc['releaseWxAppMercuryResources']();
|
|
2790
|
+
|
|
2791
|
+
expect(deviceUnregisterSpy).toHaveBeenCalledTimes(1);
|
|
2792
|
+
expect(webex.cc['wxAppDeviceRegisteredByCc']).toBe(true);
|
|
2793
|
+
|
|
2794
|
+
await webex.cc['releaseWxAppMercuryResources']();
|
|
2795
|
+
|
|
2796
|
+
expect(deviceUnregisterSpy).toHaveBeenCalledTimes(2);
|
|
2797
|
+
expect(webex.cc['wxAppDeviceRegisteredByCc']).toBe(false);
|
|
2798
|
+
});
|
|
2799
|
+
|
|
1881
2800
|
it('should handle errors during unregister and track metrics', async () => {
|
|
1882
2801
|
const mockError = new Error('Failed to deregister device');
|
|
1883
2802
|
webex.internal.device.unregister.mockRejectedValue(mockError);
|
|
@@ -2128,6 +3047,54 @@ describe('webex.cc', () => {
|
|
|
2128
3047
|
expect(result).toEqual(mockResp);
|
|
2129
3048
|
});
|
|
2130
3049
|
|
|
3050
|
+
it('should preserve enableWxBetterTogether init flag across profile update logout/login', async () => {
|
|
3051
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
3052
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
3053
|
+
webex.cc.agentConfig = {
|
|
3054
|
+
...webex.cc.agentConfig,
|
|
3055
|
+
agentId: 'agentId',
|
|
3056
|
+
webRtcEnabled: false,
|
|
3057
|
+
loginVoiceOptions: ['BROWSER', 'EXTENSION'],
|
|
3058
|
+
} as Profile;
|
|
3059
|
+
webex.cc.webCallingService.loginOption = LoginOption.BROWSER;
|
|
3060
|
+
webex.cc.webCallingService.setLoginOption = jest.fn((loginOption: LoginOption) => {
|
|
3061
|
+
webex.cc.webCallingService.loginOption = loginOption;
|
|
3062
|
+
});
|
|
3063
|
+
webex.cc['webexCrossClientService'].answerCallsState = true;
|
|
3064
|
+
|
|
3065
|
+
const publishSpy = jest
|
|
3066
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3067
|
+
.mockResolvedValue(undefined);
|
|
3068
|
+
jest
|
|
3069
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe')
|
|
3070
|
+
.mockImplementation(() => {});
|
|
3071
|
+
jest.spyOn(webex.cc as any, 'releaseWxAppMercuryResources').mockResolvedValue(undefined);
|
|
3072
|
+
|
|
3073
|
+
jest.spyOn(webex.cc.services.agent, 'logout').mockResolvedValue({
|
|
3074
|
+
trackingId: 'track-logout',
|
|
3075
|
+
} as StationLogoutResponse);
|
|
3076
|
+
jest.spyOn(webex.cc.services.agent, 'stationLogin').mockResolvedValue({
|
|
3077
|
+
data: {
|
|
3078
|
+
agentId: 'agentId',
|
|
3079
|
+
teamId: 'teamId',
|
|
3080
|
+
channelsMap: {chat: [], email: [], social: [], telephony: []},
|
|
3081
|
+
},
|
|
3082
|
+
trackingId: 'track-login',
|
|
3083
|
+
} as StationLoginSuccess);
|
|
3084
|
+
|
|
3085
|
+
webex.internal.mercury.connected = true;
|
|
3086
|
+
|
|
3087
|
+
await webex.cc.updateAgentProfile({
|
|
3088
|
+
teamId: 'teamId',
|
|
3089
|
+
loginOption: LoginOption.EXTENSION,
|
|
3090
|
+
dialNumber: '1001',
|
|
3091
|
+
});
|
|
3092
|
+
|
|
3093
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(true);
|
|
3094
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
3095
|
+
expect(publishSpy).toHaveBeenCalledWith(true, {userId: 'user-123'});
|
|
3096
|
+
});
|
|
3097
|
+
|
|
2131
3098
|
it('should use provided teamId if passed in payload', async () => {
|
|
2132
3099
|
const dataWithTeam = {
|
|
2133
3100
|
teamId: 'newTeam',
|
|
@@ -2640,4 +3607,311 @@ describe('webex.cc', () => {
|
|
|
2640
3607
|
expect(getErrorDetailsSpy).toHaveBeenCalledWith(error, 'removePreviewContact', CC_FILE);
|
|
2641
3608
|
});
|
|
2642
3609
|
});
|
|
3610
|
+
|
|
3611
|
+
describe('private setManageWebexCallingInWxcc (runtime toggle impl)', () => {
|
|
3612
|
+
beforeEach(() => {
|
|
3613
|
+
webex.internal.device = {
|
|
3614
|
+
userId: 'user-123',
|
|
3615
|
+
registered: false,
|
|
3616
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
3617
|
+
unregister: jest.fn().mockResolvedValue(undefined),
|
|
3618
|
+
};
|
|
3619
|
+
webex.internal.mercury = {
|
|
3620
|
+
connected: false,
|
|
3621
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
3622
|
+
disconnect: jest.fn().mockResolvedValue(undefined),
|
|
3623
|
+
};
|
|
3624
|
+
jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe').mockImplementation(() => {});
|
|
3625
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
3626
|
+
webex.cc['agentConfig'] = {
|
|
3627
|
+
agentId: 'agent-123',
|
|
3628
|
+
deviceType: LoginOption.EXTENSION,
|
|
3629
|
+
} as Profile;
|
|
3630
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
3631
|
+
webex.cc.webCallingService.setLoginOption = jest.fn((loginOption: LoginOption) => {
|
|
3632
|
+
webex.cc.webCallingService.loginOption = loginOption;
|
|
3633
|
+
});
|
|
3634
|
+
});
|
|
3635
|
+
|
|
3636
|
+
afterEach(() => {
|
|
3637
|
+
jest.restoreAllMocks();
|
|
3638
|
+
});
|
|
3639
|
+
|
|
3640
|
+
it('should update config, task manager, and publish usersub when enabled', async () => {
|
|
3641
|
+
const publishSpy = jest
|
|
3642
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3643
|
+
.mockResolvedValue(undefined);
|
|
3644
|
+
|
|
3645
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
3646
|
+
|
|
3647
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(true);
|
|
3648
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(true);
|
|
3649
|
+
expect(publishSpy).toHaveBeenCalledWith(true, {userId: 'user-123'});
|
|
3650
|
+
});
|
|
3651
|
+
|
|
3652
|
+
it('should publish false and update config when disabled after wxApp was enabled', async () => {
|
|
3653
|
+
webex.internal.device = {
|
|
3654
|
+
userId: 'user-123',
|
|
3655
|
+
url: 'https://wdm.example.com/devices/dev-1',
|
|
3656
|
+
};
|
|
3657
|
+
webex.request = jest.fn().mockResolvedValue({body: {}});
|
|
3658
|
+
|
|
3659
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
3660
|
+
|
|
3661
|
+
const publishSpy = jest
|
|
3662
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3663
|
+
.mockResolvedValue(undefined);
|
|
3664
|
+
|
|
3665
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(false);
|
|
3666
|
+
|
|
3667
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3668
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(false);
|
|
3669
|
+
expect(publishSpy).toHaveBeenCalledWith(false, {userId: 'user-123'});
|
|
3670
|
+
});
|
|
3671
|
+
|
|
3672
|
+
it('should skip usersub publish when disabling without prior wxApp publish', async () => {
|
|
3673
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
3674
|
+
const publishSpy = jest
|
|
3675
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3676
|
+
.mockResolvedValue(undefined);
|
|
3677
|
+
|
|
3678
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(false);
|
|
3679
|
+
|
|
3680
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3681
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(false);
|
|
3682
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3683
|
+
});
|
|
3684
|
+
|
|
3685
|
+
it('should throw when enabling before login', async () => {
|
|
3686
|
+
webex.internal.device = undefined;
|
|
3687
|
+
|
|
3688
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3689
|
+
'Cannot publish answer-calls-on-wxcc: user is not logged in'
|
|
3690
|
+
);
|
|
3691
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3692
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).not.toHaveBeenCalled();
|
|
3693
|
+
});
|
|
3694
|
+
|
|
3695
|
+
it('should throw when enabling on BROWSER (Desktop) login', async () => {
|
|
3696
|
+
webex.cc['agentConfig'] = {deviceType: LoginOption.BROWSER} as Profile;
|
|
3697
|
+
webex.cc.webCallingService.loginOption = LoginOption.BROWSER;
|
|
3698
|
+
const publishSpy = jest
|
|
3699
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3700
|
+
.mockResolvedValue(undefined);
|
|
3701
|
+
|
|
3702
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3703
|
+
'setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login'
|
|
3704
|
+
);
|
|
3705
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3706
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).not.toHaveBeenCalled();
|
|
3707
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3708
|
+
});
|
|
3709
|
+
|
|
3710
|
+
it('should throw when enabling before station login', async () => {
|
|
3711
|
+
webex.cc['agentConfig'] = undefined as unknown as Profile;
|
|
3712
|
+
webex.cc.webCallingService.loginOption = undefined as unknown as LoginOption;
|
|
3713
|
+
const publishSpy = jest
|
|
3714
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3715
|
+
.mockResolvedValue(undefined);
|
|
3716
|
+
|
|
3717
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3718
|
+
'setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login'
|
|
3719
|
+
);
|
|
3720
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3721
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).not.toHaveBeenCalled();
|
|
3722
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3723
|
+
});
|
|
3724
|
+
|
|
3725
|
+
it('should throw when webCallingService is BROWSER even if agentConfig deviceType is stale', async () => {
|
|
3726
|
+
webex.cc['agentConfig'] = {deviceType: LoginOption.EXTENSION} as Profile;
|
|
3727
|
+
webex.cc.webCallingService.loginOption = LoginOption.BROWSER;
|
|
3728
|
+
const publishSpy = jest
|
|
3729
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3730
|
+
.mockResolvedValue(undefined);
|
|
3731
|
+
|
|
3732
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3733
|
+
'setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login'
|
|
3734
|
+
);
|
|
3735
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3736
|
+
});
|
|
3737
|
+
|
|
3738
|
+
it('should publish usersub when enabling on AGENT_DN login', async () => {
|
|
3739
|
+
webex.cc['agentConfig'] = {
|
|
3740
|
+
agentId: 'agent-123',
|
|
3741
|
+
deviceType: LoginOption.AGENT_DN,
|
|
3742
|
+
} as Profile;
|
|
3743
|
+
const publishSpy = jest
|
|
3744
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3745
|
+
.mockResolvedValue(undefined);
|
|
3746
|
+
|
|
3747
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
3748
|
+
|
|
3749
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(true);
|
|
3750
|
+
expect(publishSpy).toHaveBeenCalledWith(true, {userId: 'user-123'});
|
|
3751
|
+
});
|
|
3752
|
+
|
|
3753
|
+
it('should no-op usersub publish when disabling before login', async () => {
|
|
3754
|
+
webex.internal.device = undefined;
|
|
3755
|
+
const publishSpy = jest
|
|
3756
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3757
|
+
.mockResolvedValue(undefined);
|
|
3758
|
+
|
|
3759
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(false);
|
|
3760
|
+
|
|
3761
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3762
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(false);
|
|
3763
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3764
|
+
});
|
|
3765
|
+
|
|
3766
|
+
it('should subscribe to wxApp Mercury mute sync when enabled', async () => {
|
|
3767
|
+
webex.cc['agentConfig'] = {agentId: 'agent-123'} as Profile;
|
|
3768
|
+
webex.internal.device = {
|
|
3769
|
+
...webex.internal.device,
|
|
3770
|
+
registered: true,
|
|
3771
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
3772
|
+
};
|
|
3773
|
+
webex.internal.mercury.connected = true;
|
|
3774
|
+
webex.internal.mercury.connect = jest.fn().mockResolvedValue(undefined);
|
|
3775
|
+
jest
|
|
3776
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3777
|
+
.mockResolvedValue(undefined);
|
|
3778
|
+
const subscribeSpy = jest
|
|
3779
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe')
|
|
3780
|
+
.mockImplementation(() => {});
|
|
3781
|
+
|
|
3782
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
3783
|
+
|
|
3784
|
+
expect(subscribeSpy).toHaveBeenCalledWith('agent-123', expect.any(Function));
|
|
3785
|
+
});
|
|
3786
|
+
|
|
3787
|
+
it('should unsubscribe from wxApp Mercury mute sync when disabled', async () => {
|
|
3788
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
3789
|
+
jest
|
|
3790
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3791
|
+
.mockResolvedValue(undefined);
|
|
3792
|
+
const unsubscribeSpy = jest
|
|
3793
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe')
|
|
3794
|
+
.mockImplementation(() => {});
|
|
3795
|
+
|
|
3796
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(false);
|
|
3797
|
+
|
|
3798
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
3799
|
+
});
|
|
3800
|
+
|
|
3801
|
+
it('should register device and connect mercury when enabling wxApp sync', async () => {
|
|
3802
|
+
webex.cc['agentConfig'] = {agentId: 'agent-123'} as Profile;
|
|
3803
|
+
webex.internal.device = {
|
|
3804
|
+
userId: 'user-123',
|
|
3805
|
+
registered: false,
|
|
3806
|
+
register: jest.fn().mockResolvedValue(undefined),
|
|
3807
|
+
};
|
|
3808
|
+
webex.internal.mercury = {
|
|
3809
|
+
connected: false,
|
|
3810
|
+
connect: jest.fn().mockResolvedValue(undefined),
|
|
3811
|
+
};
|
|
3812
|
+
jest
|
|
3813
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3814
|
+
.mockResolvedValue(undefined);
|
|
3815
|
+
const subscribeSpy = jest
|
|
3816
|
+
.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe')
|
|
3817
|
+
.mockImplementation(() => {});
|
|
3818
|
+
|
|
3819
|
+
await (webex.cc as any).setManageWebexCallingInWxcc(true);
|
|
3820
|
+
|
|
3821
|
+
expect(webex.internal.device.register).toHaveBeenCalled();
|
|
3822
|
+
expect(webex.internal.mercury.connect).toHaveBeenCalled();
|
|
3823
|
+
expect(subscribeSpy).toHaveBeenCalledWith('agent-123', expect.any(Function));
|
|
3824
|
+
});
|
|
3825
|
+
|
|
3826
|
+
it('should rollback config and task manager when usersub publish fails', async () => {
|
|
3827
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
3828
|
+
jest
|
|
3829
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3830
|
+
.mockRejectedValue(new Error('usersub failed'));
|
|
3831
|
+
|
|
3832
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow('usersub failed');
|
|
3833
|
+
|
|
3834
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3835
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenCalledWith(true);
|
|
3836
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenLastCalledWith(false);
|
|
3837
|
+
});
|
|
3838
|
+
|
|
3839
|
+
it('should rollback config and release Mercury resources when Mercury connect fails', async () => {
|
|
3840
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: false};
|
|
3841
|
+
const publishSpy = jest
|
|
3842
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3843
|
+
.mockResolvedValue(undefined);
|
|
3844
|
+
jest
|
|
3845
|
+
.spyOn(webex.cc as any, 'ensureWxAppMercuryConnected')
|
|
3846
|
+
.mockRejectedValue(new Error('mercury connect failed'));
|
|
3847
|
+
const releaseSpy = jest
|
|
3848
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
3849
|
+
.mockResolvedValue(undefined);
|
|
3850
|
+
const unsubscribeSpy = jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'unsubscribe');
|
|
3851
|
+
const teardownSpy = jest.spyOn(webex.cc['webexCrossClientService'], 'teardown');
|
|
3852
|
+
|
|
3853
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3854
|
+
'mercury connect failed'
|
|
3855
|
+
);
|
|
3856
|
+
|
|
3857
|
+
expect(webex.cc.isWxBetterTogetherEnabled()).toBe(false);
|
|
3858
|
+
expect(mockTaskManager.applyEnableWxBetterTogether).toHaveBeenLastCalledWith(false);
|
|
3859
|
+
expect(publishSpy).not.toHaveBeenCalled();
|
|
3860
|
+
expect(teardownSpy).not.toHaveBeenCalled();
|
|
3861
|
+
expect(unsubscribeSpy).toHaveBeenCalled();
|
|
3862
|
+
expect(releaseSpy).toHaveBeenCalled();
|
|
3863
|
+
});
|
|
3864
|
+
|
|
3865
|
+
it('should schedule compensating false retry when rollback publish fails after enable error', async () => {
|
|
3866
|
+
jest.useFakeTimers();
|
|
3867
|
+
try {
|
|
3868
|
+
webex.cc.$config = {...webex.cc.$config, enableWxBetterTogether: true};
|
|
3869
|
+
webex.internal.device = {userId: 'user-123', url: 'https://wdm.example.com/devices/dev-1'};
|
|
3870
|
+
webex.cc.agentConfig = {
|
|
3871
|
+
agentId: 'agent-123',
|
|
3872
|
+
deviceType: LoginOption.EXTENSION,
|
|
3873
|
+
};
|
|
3874
|
+
webex.cc.webCallingService.loginOption = LoginOption.EXTENSION;
|
|
3875
|
+
|
|
3876
|
+
const publishSpy = jest
|
|
3877
|
+
.spyOn(webex.cc['webexCrossClientService'], 'setManageWebexCallingInWxcc')
|
|
3878
|
+
.mockResolvedValueOnce(undefined)
|
|
3879
|
+
.mockRejectedValueOnce(new Error('compensating false failed'))
|
|
3880
|
+
.mockResolvedValue(undefined);
|
|
3881
|
+
jest.spyOn(webex.cc['wxAppTelephonyMercurySync'], 'subscribe').mockImplementation(() => {});
|
|
3882
|
+
jest
|
|
3883
|
+
.spyOn(webex.cc as any, 'ensureWxAppMercuryConnected')
|
|
3884
|
+
.mockResolvedValue(undefined);
|
|
3885
|
+
jest
|
|
3886
|
+
.spyOn(webex.cc as any, 'releaseWxAppMercuryResources')
|
|
3887
|
+
.mockResolvedValue(undefined);
|
|
3888
|
+
jest
|
|
3889
|
+
.spyOn(mockTaskManager, 'syncWxAppMuteFromCallDetailsForAllTasks')
|
|
3890
|
+
.mockImplementation(() => {
|
|
3891
|
+
throw new Error('sync failed');
|
|
3892
|
+
});
|
|
3893
|
+
const scheduleRetrySpy = jest.spyOn(
|
|
3894
|
+
webex.cc as any,
|
|
3895
|
+
'scheduleCompensatingFalsePublishRetry'
|
|
3896
|
+
);
|
|
3897
|
+
|
|
3898
|
+
await expect((webex.cc as any).setManageWebexCallingInWxcc(true)).rejects.toThrow(
|
|
3899
|
+
'sync failed'
|
|
3900
|
+
);
|
|
3901
|
+
|
|
3902
|
+
expect(scheduleRetrySpy).toHaveBeenCalled();
|
|
3903
|
+
expect(publishSpy).toHaveBeenCalledTimes(2);
|
|
3904
|
+
expect(publishSpy).toHaveBeenNthCalledWith(1, true, {userId: 'user-123'});
|
|
3905
|
+
expect(publishSpy).toHaveBeenNthCalledWith(2, false, {userId: 'user-123'});
|
|
3906
|
+
|
|
3907
|
+
jest.advanceTimersByTime(30_000);
|
|
3908
|
+
await publishSpy.mock.results[2]?.value;
|
|
3909
|
+
|
|
3910
|
+
expect(publishSpy).toHaveBeenCalledTimes(3);
|
|
3911
|
+
expect(publishSpy).toHaveBeenLastCalledWith(false, {userId: 'user-123'});
|
|
3912
|
+
} finally {
|
|
3913
|
+
jest.useRealTimers();
|
|
3914
|
+
}
|
|
3915
|
+
});
|
|
3916
|
+
});
|
|
2643
3917
|
});
|