@webex/plugin-meetings 3.7.0-web-workers-keepalive.1 → 3.7.0-wxcc.1
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/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/join-forbidden-error.js +52 -0
- package/dist/common/errors/join-forbidden-error.js.map +1 -0
- package/dist/constants.js +22 -2
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +1 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +2 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +66 -41
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +70 -19
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.js +102 -53
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +2 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/types/common/errors/join-forbidden-error.d.ts +15 -0
- package/dist/types/constants.d.ts +18 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +23 -0
- package/dist/types/meetings/index.d.ts +16 -1
- package/dist/types/meetings/meetings.types.d.ts +8 -0
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/common/errors/join-forbidden-error.ts +26 -0
- package/src/constants.ts +20 -0
- package/src/locus-info/index.ts +3 -1
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +25 -0
- package/src/meeting-info/meeting-info-v2.ts +51 -0
- package/src/meeting-info/utilv2.ts +3 -1
- package/src/meetings/index.ts +72 -19
- package/src/meetings/meetings.types.ts +10 -0
- package/src/metrics/constants.ts +1 -0
- package/test/unit/spec/locus-info/index.js +70 -60
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +42 -5
- package/test/unit/spec/meeting-info/meetinginfov2.js +37 -0
- package/test/unit/spec/meeting-info/utilv2.js +17 -0
- package/test/unit/spec/meetings/index.js +150 -13
package/src/meetings/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint no-shadow: ["error", { "allow": ["eventType"] }] */
|
|
2
|
-
import {cloneDeep} from 'lodash';
|
|
2
|
+
import {cloneDeep, clone} from 'lodash';
|
|
3
3
|
import '@webex/internal-plugin-mercury';
|
|
4
4
|
import '@webex/internal-plugin-conversation';
|
|
5
5
|
import '@webex/internal-plugin-metrics';
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
_ON_HOLD_LOBBY_,
|
|
43
43
|
_WAIT_,
|
|
44
44
|
DESTINATION_TYPE,
|
|
45
|
+
INITIAL_REGISTRATION_STATUS,
|
|
45
46
|
} from '../constants';
|
|
46
47
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
47
48
|
import MeetingInfo from '../meeting-info';
|
|
@@ -53,12 +54,18 @@ import Request from './request';
|
|
|
53
54
|
import PasswordError from '../common/errors/password-error';
|
|
54
55
|
import CaptchaError from '../common/errors/captcha-error';
|
|
55
56
|
import MeetingCollection from './collection';
|
|
56
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
MEETING_KEY,
|
|
59
|
+
INoiseReductionEffect,
|
|
60
|
+
IVirtualBackgroundEffect,
|
|
61
|
+
MeetingRegistrationStatus,
|
|
62
|
+
} from './meetings.types';
|
|
57
63
|
import MeetingsUtil from './util';
|
|
58
64
|
import PermissionError from '../common/errors/permission';
|
|
59
65
|
import JoinWebinarError from '../common/errors/join-webinar-error';
|
|
60
66
|
import {SpaceIDDeprecatedError} from '../common/errors/webex-errors';
|
|
61
67
|
import NoMeetingInfoError from '../common/errors/no-meeting-info';
|
|
68
|
+
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
62
69
|
|
|
63
70
|
let mediaLogger;
|
|
64
71
|
|
|
@@ -179,6 +186,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
179
186
|
mediaHelpers: any;
|
|
180
187
|
breakoutLocusForHandleLater: any;
|
|
181
188
|
namespace = MEETINGS;
|
|
189
|
+
registrationStatus: MeetingRegistrationStatus;
|
|
182
190
|
|
|
183
191
|
/**
|
|
184
192
|
* Initializes the Meetings Plugin
|
|
@@ -692,6 +700,20 @@ export default class Meetings extends WebexPlugin {
|
|
|
692
700
|
});
|
|
693
701
|
}
|
|
694
702
|
|
|
703
|
+
/**
|
|
704
|
+
* API to change log upload interval. Setting the factor to 0 will disable periodic log uploads.
|
|
705
|
+
*
|
|
706
|
+
* @param {number} factor new factor value
|
|
707
|
+
* @returns {void}
|
|
708
|
+
*/
|
|
709
|
+
private _setLogUploadIntervalMultiplicationFactor(factor: number) {
|
|
710
|
+
if (typeof factor !== 'number') {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
// @ts-ignore
|
|
714
|
+
this.config.logUploadIntervalMultiplicationFactor = factor;
|
|
715
|
+
}
|
|
716
|
+
|
|
695
717
|
/**
|
|
696
718
|
* API to toggle unified meetings
|
|
697
719
|
* @param {Boolean} changeState
|
|
@@ -785,6 +807,18 @@ export default class Meetings extends WebexPlugin {
|
|
|
785
807
|
}
|
|
786
808
|
}
|
|
787
809
|
|
|
810
|
+
/**
|
|
811
|
+
* Executes a registration step and updates the registration status.
|
|
812
|
+
* @param {Function} step - The registration step to execute.
|
|
813
|
+
* @param {string} stepName - The name of the registration step.
|
|
814
|
+
* @returns {Promise} A promise that resolves when the step is completed.
|
|
815
|
+
*/
|
|
816
|
+
executeRegistrationStep(step: () => Promise<any>, stepName: string) {
|
|
817
|
+
return step().then(() => {
|
|
818
|
+
this.registrationStatus[stepName] = true;
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
|
|
788
822
|
/**
|
|
789
823
|
* Explicitly sets up the meetings plugin by registering
|
|
790
824
|
* the device, connecting to mercury, and listening for locus events.
|
|
@@ -795,6 +829,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
795
829
|
* @memberof Meetings
|
|
796
830
|
*/
|
|
797
831
|
public register(deviceRegistrationOptions?: DeviceRegistrationOptions): Promise<any> {
|
|
832
|
+
this.registrationStatus = clone(INITIAL_REGISTRATION_STATUS);
|
|
833
|
+
|
|
798
834
|
// @ts-ignore
|
|
799
835
|
if (!this.webex.canAuthorize) {
|
|
800
836
|
LoggerProxy.logger.error(
|
|
@@ -813,24 +849,39 @@ export default class Meetings extends WebexPlugin {
|
|
|
813
849
|
}
|
|
814
850
|
|
|
815
851
|
return Promise.all([
|
|
816
|
-
this.fetchUserPreferredWebexSite(),
|
|
817
|
-
this.getGeoHint(),
|
|
818
|
-
this.
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
852
|
+
this.executeRegistrationStep(() => this.fetchUserPreferredWebexSite(), 'fetchWebexSite'),
|
|
853
|
+
this.executeRegistrationStep(() => this.getGeoHint(), 'getGeoHint'),
|
|
854
|
+
this.executeRegistrationStep(
|
|
855
|
+
() =>
|
|
856
|
+
this.startReachability('registration').catch((error) => {
|
|
857
|
+
LoggerProxy.logger.error(`Meetings:index#register --> GDM error, ${error.message}`);
|
|
858
|
+
}),
|
|
859
|
+
'startReachability'
|
|
860
|
+
),
|
|
861
|
+
this.executeRegistrationStep(
|
|
862
|
+
() =>
|
|
863
|
+
// @ts-ignore
|
|
864
|
+
this.webex.internal.device
|
|
865
|
+
.register(deviceRegistrationOptions)
|
|
827
866
|
// @ts-ignore
|
|
828
|
-
|
|
829
|
-
|
|
867
|
+
.then(() => {
|
|
868
|
+
LoggerProxy.logger.info(
|
|
869
|
+
// @ts-ignore
|
|
870
|
+
`Meetings:index#register --> INFO, Device registered ${this.webex.internal.device.url}`
|
|
871
|
+
);
|
|
872
|
+
}),
|
|
873
|
+
'deviceRegister'
|
|
874
|
+
).then(() =>
|
|
875
|
+
this.executeRegistrationStep(
|
|
876
|
+
// @ts-ignore
|
|
877
|
+
() => this.webex.internal.mercury.connect(),
|
|
878
|
+
'mercuryConnect'
|
|
830
879
|
)
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
880
|
+
),
|
|
881
|
+
this.executeRegistrationStep(
|
|
882
|
+
() => Promise.resolve(MeetingsUtil.checkH264Support.call(this)),
|
|
883
|
+
'checkH264Support'
|
|
884
|
+
),
|
|
834
885
|
])
|
|
835
886
|
.then(() => {
|
|
836
887
|
this.listenForEvents();
|
|
@@ -894,6 +945,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
894
945
|
EVENT_TRIGGERS.MEETINGS_UNREGISTERED
|
|
895
946
|
);
|
|
896
947
|
this.registered = false;
|
|
948
|
+
this.registrationStatus = clone(INITIAL_REGISTRATION_STATUS);
|
|
897
949
|
})
|
|
898
950
|
);
|
|
899
951
|
}
|
|
@@ -1412,7 +1464,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1412
1464
|
!(err instanceof CaptchaError) &&
|
|
1413
1465
|
!(err instanceof PasswordError) &&
|
|
1414
1466
|
!(err instanceof PermissionError) &&
|
|
1415
|
-
!(err instanceof JoinWebinarError)
|
|
1467
|
+
!(err instanceof JoinWebinarError) &&
|
|
1468
|
+
!(err instanceof JoinForbiddenError)
|
|
1416
1469
|
) {
|
|
1417
1470
|
LoggerProxy.logger.info(
|
|
1418
1471
|
`Meetings:index#createMeeting --> Info Unable to fetch meeting info for ${destination}.`
|
|
@@ -21,3 +21,13 @@ export const MEETING_KEY = {
|
|
|
21
21
|
} as const;
|
|
22
22
|
|
|
23
23
|
export type MEETING_KEY = Enum<typeof MEETING_KEY>;
|
|
24
|
+
|
|
25
|
+
// finer grained status for registration steps
|
|
26
|
+
export type MeetingRegistrationStatus = {
|
|
27
|
+
fetchWebexSite: boolean;
|
|
28
|
+
getGeoHint: boolean;
|
|
29
|
+
startReachability: boolean;
|
|
30
|
+
deviceRegister: boolean;
|
|
31
|
+
mercuryConnect: boolean;
|
|
32
|
+
checkH264Support: boolean;
|
|
33
|
+
};
|
package/src/metrics/constants.ts
CHANGED
|
@@ -73,6 +73,7 @@ const BEHAVIORAL_METRICS = {
|
|
|
73
73
|
JOIN_WEBINAR_ERROR: 'js_sdk_join_webinar_error',
|
|
74
74
|
GUEST_ENTERED_LOBBY: 'js_sdk_guest_entered_lobby',
|
|
75
75
|
GUEST_EXITED_LOBBY: 'js_sdk_guest_exited_lobby',
|
|
76
|
+
JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',
|
|
76
77
|
};
|
|
77
78
|
|
|
78
79
|
export {BEHAVIORAL_METRICS as default};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'jsdom-global/register';
|
|
2
2
|
import sinon from 'sinon';
|
|
3
|
-
import {cloneDeep} from 'lodash';
|
|
3
|
+
import {cloneDeep, forEach} from 'lodash';
|
|
4
4
|
import {assert} from '@webex/test-helper-chai';
|
|
5
5
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
6
6
|
import testUtils from '../../../utils/testUtils';
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
LOCUS,
|
|
24
24
|
MEETING_STATE,
|
|
25
25
|
_MEETING_,
|
|
26
|
+
_SIP_BRIDGE_,
|
|
27
|
+
_SPACE_SHARE_,
|
|
26
28
|
} from '../../../../src/constants';
|
|
27
29
|
|
|
28
30
|
import {self, selfWithInactivity} from './selfConstant';
|
|
@@ -102,7 +104,11 @@ describe('plugin-meetings', () => {
|
|
|
102
104
|
},
|
|
103
105
|
entryExitTone: {enabled: true, mode: 'foo'},
|
|
104
106
|
video: {enabled: true},
|
|
105
|
-
videoLayout: {
|
|
107
|
+
videoLayout: {
|
|
108
|
+
overrideDefault: true,
|
|
109
|
+
lockAttendeeViewOnStageOnly: false,
|
|
110
|
+
stageParameters: {},
|
|
111
|
+
},
|
|
106
112
|
webcastControl: {streaming: false},
|
|
107
113
|
practiceSession: {enabled: true},
|
|
108
114
|
};
|
|
@@ -529,7 +535,7 @@ describe('plugin-meetings', () => {
|
|
|
529
535
|
manualCaptionControl: {enabled: false},
|
|
530
536
|
};
|
|
531
537
|
|
|
532
|
-
locusInfo.updateControls({manualCaptionControl: {
|
|
538
|
+
locusInfo.updateControls({manualCaptionControl: {enabled: true}});
|
|
533
539
|
|
|
534
540
|
assert.calledWith(
|
|
535
541
|
locusInfo.emitScoped,
|
|
@@ -2636,65 +2642,69 @@ describe('plugin-meetings', () => {
|
|
|
2636
2642
|
});
|
|
2637
2643
|
|
|
2638
2644
|
describe('#isMeetingActive', () => {
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
2662
|
-
locusInfo.parsedLocus = {
|
|
2663
|
-
fullState: {
|
|
2664
|
-
type: _CALL_,
|
|
2665
|
-
},
|
|
2666
|
-
self: {
|
|
2667
|
-
state: MEETING_STATE.STATES.DECLINED,
|
|
2668
|
-
},
|
|
2669
|
-
};
|
|
2670
|
-
locusInfo.isMeetingActive();
|
|
2671
|
-
|
|
2672
|
-
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
2673
|
-
name: 'client.call.remote-ended',
|
|
2674
|
-
options: {
|
|
2675
|
-
meetingId: locusInfo.meetingId,
|
|
2676
|
-
},
|
|
2677
|
-
});
|
|
2678
|
-
});
|
|
2679
|
-
|
|
2680
|
-
it('sends client event correctly for state = SELF_LEFT', () => {
|
|
2681
|
-
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
2682
|
-
locusInfo.parsedLocus = {
|
|
2683
|
-
fullState: {
|
|
2684
|
-
type: _CALL_,
|
|
2685
|
-
},
|
|
2686
|
-
self: {
|
|
2687
|
-
state: MEETING_STATE.STATES.LEFT,
|
|
2688
|
-
},
|
|
2689
|
-
};
|
|
2645
|
+
forEach([_CALL_, _SIP_BRIDGE_, _SPACE_SHARE_], (type) => {
|
|
2646
|
+
describe(`type = ${type}`, () => {
|
|
2647
|
+
it('sends client event correctly for state = inactive', () => {
|
|
2648
|
+
locusInfo.parsedLocus = {
|
|
2649
|
+
fullState: {
|
|
2650
|
+
type: type,
|
|
2651
|
+
},
|
|
2652
|
+
};
|
|
2653
|
+
|
|
2654
|
+
locusInfo.fullState = {
|
|
2655
|
+
state: LOCUS.STATE.INACTIVE,
|
|
2656
|
+
};
|
|
2657
|
+
|
|
2658
|
+
locusInfo.isMeetingActive();
|
|
2659
|
+
|
|
2660
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
2661
|
+
name: 'client.call.remote-ended',
|
|
2662
|
+
options: {
|
|
2663
|
+
meetingId: locusInfo.meetingId,
|
|
2664
|
+
},
|
|
2665
|
+
});
|
|
2666
|
+
});
|
|
2690
2667
|
|
|
2691
|
-
|
|
2668
|
+
it('sends client event correctly for state = PARTNER_LEFT', () => {
|
|
2669
|
+
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
2670
|
+
locusInfo.parsedLocus = {
|
|
2671
|
+
fullState: {
|
|
2672
|
+
type: type,
|
|
2673
|
+
},
|
|
2674
|
+
self: {
|
|
2675
|
+
state: MEETING_STATE.STATES.DECLINED,
|
|
2676
|
+
},
|
|
2677
|
+
};
|
|
2678
|
+
locusInfo.isMeetingActive();
|
|
2679
|
+
|
|
2680
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
2681
|
+
name: 'client.call.remote-ended',
|
|
2682
|
+
options: {
|
|
2683
|
+
meetingId: locusInfo.meetingId,
|
|
2684
|
+
},
|
|
2685
|
+
});
|
|
2686
|
+
});
|
|
2692
2687
|
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2688
|
+
it('sends client event correctly for state = SELF_LEFT', () => {
|
|
2689
|
+
locusInfo.getLocusPartner = sinon.stub().returns({state: MEETING_STATE.STATES.LEFT});
|
|
2690
|
+
locusInfo.parsedLocus = {
|
|
2691
|
+
fullState: {
|
|
2692
|
+
type: type,
|
|
2693
|
+
},
|
|
2694
|
+
self: {
|
|
2695
|
+
state: MEETING_STATE.STATES.LEFT,
|
|
2696
|
+
},
|
|
2697
|
+
};
|
|
2698
|
+
|
|
2699
|
+
locusInfo.isMeetingActive();
|
|
2700
|
+
|
|
2701
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
2702
|
+
name: 'client.call.remote-ended',
|
|
2703
|
+
options: {
|
|
2704
|
+
meetingId: locusInfo.meetingId,
|
|
2705
|
+
},
|
|
2706
|
+
});
|
|
2707
|
+
});
|
|
2698
2708
|
});
|
|
2699
2709
|
});
|
|
2700
2710
|
|
|
@@ -42,6 +42,7 @@ describe('plugin-meetings', () => {
|
|
|
42
42
|
waitingForOthersToJoin: null,
|
|
43
43
|
canSendReactions: null,
|
|
44
44
|
canManageBreakout: null,
|
|
45
|
+
canStartBreakout: null,
|
|
45
46
|
canBroadcastMessageToBreakout: null,
|
|
46
47
|
canAdmitLobbyToBreakout: null,
|
|
47
48
|
canUserAskForHelp: null,
|
|
@@ -141,6 +142,7 @@ describe('plugin-meetings', () => {
|
|
|
141
142
|
'waitingForOthersToJoin',
|
|
142
143
|
'canSendReactions',
|
|
143
144
|
'canManageBreakout',
|
|
145
|
+
'canStartBreakout',
|
|
144
146
|
'canBroadcastMessageToBreakout',
|
|
145
147
|
'canAdmitLobbyToBreakout',
|
|
146
148
|
'canUserAskForHelp',
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
MeetingInfoV2CaptchaError,
|
|
100
100
|
MeetingInfoV2PasswordError,
|
|
101
101
|
MeetingInfoV2PolicyError,
|
|
102
|
-
MeetingInfoV2JoinWebinarError,
|
|
102
|
+
MeetingInfoV2JoinWebinarError, MeetingInfoV2JoinForbiddenError,
|
|
103
103
|
} from '../../../../src/meeting-info/meeting-info-v2';
|
|
104
104
|
import {
|
|
105
105
|
DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
|
|
@@ -114,6 +114,7 @@ import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagno
|
|
|
114
114
|
import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
|
|
115
115
|
|
|
116
116
|
import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea';
|
|
117
|
+
import JoinForbiddenError from '../../../../src/common/errors/join-forbidden-error';
|
|
117
118
|
|
|
118
119
|
describe('plugin-meetings', () => {
|
|
119
120
|
const logger = {
|
|
@@ -6339,6 +6340,38 @@ describe('plugin-meetings', () => {
|
|
|
6339
6340
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
6340
6341
|
});
|
|
6341
6342
|
|
|
6343
|
+
it('handles meetingInfoProvider not reach JBH', async () => {
|
|
6344
|
+
meeting.destination = FAKE_DESTINATION;
|
|
6345
|
+
meeting.destinationType = FAKE_TYPE;
|
|
6346
|
+
meeting.attrs.meetingInfoProvider = {
|
|
6347
|
+
fetchMeetingInfo: sinon
|
|
6348
|
+
.stub()
|
|
6349
|
+
.throws(new MeetingInfoV2JoinForbiddenError(403003, FAKE_MEETING_INFO)),
|
|
6350
|
+
};
|
|
6351
|
+
|
|
6352
|
+
await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinForbiddenError);
|
|
6353
|
+
|
|
6354
|
+
assert.calledWith(
|
|
6355
|
+
meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
|
|
6356
|
+
FAKE_DESTINATION,
|
|
6357
|
+
FAKE_TYPE,
|
|
6358
|
+
null,
|
|
6359
|
+
null,
|
|
6360
|
+
undefined,
|
|
6361
|
+
'locus-id',
|
|
6362
|
+
{},
|
|
6363
|
+
{meetingId: meeting.id, sendCAevents: true}
|
|
6364
|
+
);
|
|
6365
|
+
|
|
6366
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
6367
|
+
assert.equal(meeting.meetingInfoFailureCode, 403003);
|
|
6368
|
+
assert.equal(
|
|
6369
|
+
meeting.meetingInfoFailureReason,
|
|
6370
|
+
MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH
|
|
6371
|
+
);
|
|
6372
|
+
assert.equal(meeting.requiredCaptcha, null);
|
|
6373
|
+
});
|
|
6374
|
+
|
|
6342
6375
|
it('handles meetingInfoProvider policy error', async () => {
|
|
6343
6376
|
meeting.destination = FAKE_DESTINATION;
|
|
6344
6377
|
meeting.destinationType = FAKE_TYPE;
|
|
@@ -9996,7 +10029,8 @@ describe('plugin-meetings', () => {
|
|
|
9996
10029
|
describe('#closePeerConnections', () => {
|
|
9997
10030
|
it('should close the webrtc media connection, and return a promise', async () => {
|
|
9998
10031
|
const setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
|
|
9999
|
-
|
|
10032
|
+
const fakeWebrtcMediaConnection = {close: sinon.stub()};
|
|
10033
|
+
meeting.mediaProperties.webrtcMediaConnection = fakeWebrtcMediaConnection;
|
|
10000
10034
|
|
|
10001
10035
|
meeting.audio = {id: 'fakeAudioMuteState'};
|
|
10002
10036
|
meeting.video = {id: 'fakeVideoMuteState'};
|
|
@@ -10005,15 +10039,17 @@ describe('plugin-meetings', () => {
|
|
|
10005
10039
|
|
|
10006
10040
|
assert.exists(pcs.then);
|
|
10007
10041
|
await pcs;
|
|
10008
|
-
assert.calledOnce(
|
|
10042
|
+
assert.calledOnce(fakeWebrtcMediaConnection.close);
|
|
10009
10043
|
assert.calledOnceWithExactly(setNetworkStatusSpy, undefined);
|
|
10010
10044
|
assert.equal(meeting.audio, null);
|
|
10011
10045
|
assert.equal(meeting.video, null);
|
|
10046
|
+
assert.equal(meeting.mediaProperties.webrtcMediaConnection, null);
|
|
10012
10047
|
});
|
|
10013
10048
|
|
|
10014
10049
|
it('should close the webrtc media connection, but keep audio and video props unchanged if called with resetMuteStates=false', async () => {
|
|
10015
10050
|
const setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
|
|
10016
|
-
|
|
10051
|
+
const fakeWebrtcMediaConnection = {close: sinon.stub()};
|
|
10052
|
+
meeting.mediaProperties.webrtcMediaConnection = fakeWebrtcMediaConnection;
|
|
10017
10053
|
|
|
10018
10054
|
const fakeAudio = {id: 'fakeAudioMuteState'};
|
|
10019
10055
|
const fakeVideo = {id: 'fakeVideoMuteState'};
|
|
@@ -10023,10 +10059,11 @@ describe('plugin-meetings', () => {
|
|
|
10023
10059
|
|
|
10024
10060
|
await meeting.closePeerConnections(false);
|
|
10025
10061
|
|
|
10026
|
-
assert.calledOnce(
|
|
10062
|
+
assert.calledOnce(fakeWebrtcMediaConnection.close);
|
|
10027
10063
|
assert.calledOnceWithExactly(setNetworkStatusSpy, undefined);
|
|
10028
10064
|
assert.equal(meeting.audio, fakeAudio);
|
|
10029
10065
|
assert.equal(meeting.video, fakeVideo);
|
|
10066
|
+
assert.equal(meeting.mediaProperties.webrtcMediaConnection, null);
|
|
10030
10067
|
});
|
|
10031
10068
|
});
|
|
10032
10069
|
|
|
@@ -19,6 +19,7 @@ import MeetingInfo, {
|
|
|
19
19
|
MeetingInfoV2AdhocMeetingError,
|
|
20
20
|
MeetingInfoV2PolicyError,
|
|
21
21
|
MeetingInfoV2JoinWebinarError,
|
|
22
|
+
MeetingInfoV2JoinForbiddenError,
|
|
22
23
|
} from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
|
|
23
24
|
import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
|
|
24
25
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
@@ -930,6 +931,42 @@ describe('plugin-meetings', () => {
|
|
|
930
931
|
});
|
|
931
932
|
}
|
|
932
933
|
);
|
|
934
|
+
|
|
935
|
+
forEach(
|
|
936
|
+
[
|
|
937
|
+
{errorCode: 403003},
|
|
938
|
+
],
|
|
939
|
+
({errorCode}) => {
|
|
940
|
+
it(`should throw a MeetingInfoV2JoinForbiddenError for error code ${errorCode}`, async () => {
|
|
941
|
+
const message = 'a message';
|
|
942
|
+
const meetingInfoData = 'meeting info';
|
|
943
|
+
|
|
944
|
+
webex.request = sinon.stub().rejects({
|
|
945
|
+
statusCode: 403,
|
|
946
|
+
body: {message, code: errorCode, data: {meetingInfo: meetingInfoData}},
|
|
947
|
+
});
|
|
948
|
+
try {
|
|
949
|
+
await meetingInfo.fetchMeetingInfo('1234323', DESTINATION_TYPE.MEETING_ID, 'abc', {
|
|
950
|
+
id: '999',
|
|
951
|
+
code: 'aabbcc11',
|
|
952
|
+
});
|
|
953
|
+
} catch (err) {
|
|
954
|
+
assert.instanceOf(err, MeetingInfoV2JoinForbiddenError);
|
|
955
|
+
assert.deepEqual(err.message, `${message}, code=${errorCode}`);
|
|
956
|
+
assert.equal(err.wbxAppApiCode, errorCode);
|
|
957
|
+
assert.deepEqual(err.meetingInfo, meetingInfoData);
|
|
958
|
+
|
|
959
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
960
|
+
assert.calledWith(
|
|
961
|
+
Metrics.sendBehavioralMetric,
|
|
962
|
+
BEHAVIORAL_METRICS.JOIN_FORBIDDEN_ERROR,
|
|
963
|
+
{code: errorCode}
|
|
964
|
+
);
|
|
965
|
+
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
);
|
|
933
970
|
});
|
|
934
971
|
});
|
|
935
972
|
});
|
|
@@ -345,5 +345,22 @@ describe('plugin-meetings', () => {
|
|
|
345
345
|
);
|
|
346
346
|
});
|
|
347
347
|
});
|
|
348
|
+
|
|
349
|
+
describe('#isMeetingLink', () => {
|
|
350
|
+
it('should return true for valid join meeting link with MTID', () => {
|
|
351
|
+
const result = MeetingInfoUtil.isMeetingLink('https://cisco.webex.com/cisco/j.php?MTID=m9fe0afd8c435e892afcce9ea25b97046');
|
|
352
|
+
expect(result).to.be.true;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should return true for valid join meeting link without cisco domain', () => {
|
|
356
|
+
const result = MeetingInfoUtil.isMeetingLink('https://test.webex.com/test/j.php?MTID=m9fe0afd8c435e892afcce9ea25b97046');
|
|
357
|
+
expect(result).to.be.true;
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should return false for an invalid meeting link', () => {
|
|
361
|
+
const result = MeetingInfoUtil.isMeetingLink('https://test.webex.com/test/j.php?MiD=m9fe0afd8c435e892afcce9ea25b97046');
|
|
362
|
+
expect(result).to.be.false;
|
|
363
|
+
});
|
|
364
|
+
});
|
|
348
365
|
});
|
|
349
366
|
});
|