@webex/plugin-meetings 3.7.0-next.2 → 3.7.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
- package/dist/common/errors/join-webinar-error.js.map +1 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +29 -6
- package/dist/constants.js.map +1 -1
- package/dist/index.js +8 -15
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +5 -2
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +11 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +115 -150
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +3 -8
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -17
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +6 -3
- package/dist/meetings/index.js.map +1 -1
- package/dist/members/util.js +4 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMedia.js +30 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/reachability/clusterReachability.js +12 -11
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/recording-controller/enums.js +8 -4
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +18 -9
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +13 -9
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
- package/dist/types/constants.d.ts +21 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
- package/dist/types/meeting/index.d.ts +1 -10
- package/dist/types/meeting/util.d.ts +1 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +4 -4
- package/dist/types/meetings/index.d.ts +3 -0
- package/dist/types/members/util.d.ts +2 -0
- package/dist/types/metrics/constants.d.ts +3 -1
- package/dist/types/recording-controller/enums.d.ts +5 -2
- package/dist/types/recording-controller/index.d.ts +1 -0
- package/dist/types/recording-controller/util.d.ts +2 -1
- package/dist/webinar/index.js +390 -7
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -22
- package/src/common/errors/join-webinar-error.ts +24 -0
- package/src/config.ts +1 -1
- package/src/constants.ts +26 -3
- package/src/index.ts +2 -3
- package/src/locus-info/index.ts +4 -2
- package/src/meeting/in-meeting-actions.ts +21 -0
- package/src/meeting/index.ts +86 -54
- package/src/meeting/util.ts +3 -9
- package/src/meeting-info/meeting-info-v2.ts +23 -11
- package/src/meetings/index.ts +8 -2
- package/src/members/util.ts +1 -0
- package/src/metrics/constants.ts +3 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/reachability/clusterReachability.ts +4 -1
- package/src/recording-controller/enums.ts +5 -2
- package/src/recording-controller/index.ts +17 -4
- package/src/recording-controller/util.ts +20 -5
- package/src/webinar/index.ts +235 -9
- package/test/unit/spec/locus-info/index.js +129 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +13 -1
- package/test/unit/spec/meeting/index.js +179 -81
- package/test/unit/spec/meeting/utils.js +11 -19
- package/test/unit/spec/meeting-info/meetinginfov2.js +9 -4
- package/test/unit/spec/meetings/index.js +9 -5
- package/test/unit/spec/members/utils.js +95 -0
- package/test/unit/spec/multistream/remoteMedia.ts +11 -7
- package/test/unit/spec/reachability/clusterReachability.ts +7 -0
- package/test/unit/spec/recording-controller/index.js +61 -5
- package/test/unit/spec/recording-controller/util.js +39 -3
- package/test/unit/spec/webinar/index.ts +504 -0
- package/dist/common/errors/webinar-registration-error.js.map +0 -1
- package/src/common/errors/webinar-registration-error.ts +0 -27
|
@@ -91,14 +91,14 @@ import ParameterError from '../../../../src/common/errors/parameter';
|
|
|
91
91
|
import PasswordError from '../../../../src/common/errors/password-error';
|
|
92
92
|
import CaptchaError from '../../../../src/common/errors/captcha-error';
|
|
93
93
|
import PermissionError from '../../../../src/common/errors/permission';
|
|
94
|
-
import
|
|
94
|
+
import JoinWebinarError from '../../../../src/common/errors/join-webinar-error';
|
|
95
95
|
import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
|
|
96
96
|
import testUtils from '../../../utils/testUtils';
|
|
97
97
|
import {
|
|
98
98
|
MeetingInfoV2CaptchaError,
|
|
99
99
|
MeetingInfoV2PasswordError,
|
|
100
100
|
MeetingInfoV2PolicyError,
|
|
101
|
-
|
|
101
|
+
MeetingInfoV2JoinWebinarError,
|
|
102
102
|
} from '../../../../src/meeting-info/meeting-info-v2';
|
|
103
103
|
import {
|
|
104
104
|
DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
|
|
@@ -1705,6 +1705,12 @@ describe('plugin-meetings', () => {
|
|
|
1705
1705
|
sinon.assert.called(setCorrelationIdSpy);
|
|
1706
1706
|
assert.equal(meeting.correlationId, '123');
|
|
1707
1707
|
});
|
|
1708
|
+
|
|
1709
|
+
it('should not send client.call.initiated if told not to', async () => {
|
|
1710
|
+
await meeting.join({sendCallInitiated: false});
|
|
1711
|
+
|
|
1712
|
+
sinon.assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
1713
|
+
});
|
|
1708
1714
|
});
|
|
1709
1715
|
|
|
1710
1716
|
describe('failure', () => {
|
|
@@ -2492,9 +2498,11 @@ describe('plugin-meetings', () => {
|
|
|
2492
2498
|
mediaSettings: {},
|
|
2493
2499
|
});
|
|
2494
2500
|
|
|
2495
|
-
const checkLogCounter = (
|
|
2501
|
+
const checkLogCounter = (delayInMinutes, expectedCounter) => {
|
|
2502
|
+
const delayInMilliseconds = delayInMinutes * 60 * 1000;
|
|
2503
|
+
|
|
2496
2504
|
// first check that the counter is not increased just before the delay
|
|
2497
|
-
clock.tick(
|
|
2505
|
+
clock.tick(delayInMilliseconds - 50);
|
|
2498
2506
|
assert.equal(logUploadCounter, expectedCounter - 1);
|
|
2499
2507
|
|
|
2500
2508
|
// and now check that it has reached expected value after the delay
|
|
@@ -2502,22 +2510,18 @@ describe('plugin-meetings', () => {
|
|
|
2502
2510
|
assert.equal(logUploadCounter, expectedCounter);
|
|
2503
2511
|
};
|
|
2504
2512
|
|
|
2505
|
-
checkLogCounter(
|
|
2506
|
-
checkLogCounter(
|
|
2507
|
-
checkLogCounter(
|
|
2508
|
-
checkLogCounter(
|
|
2509
|
-
checkLogCounter(
|
|
2510
|
-
checkLogCounter(30000, 6);
|
|
2511
|
-
checkLogCounter(30000, 7);
|
|
2512
|
-
checkLogCounter(60000, 8);
|
|
2513
|
-
checkLogCounter(60000, 9);
|
|
2514
|
-
checkLogCounter(60000, 10);
|
|
2513
|
+
checkLogCounter(0.1, 1);
|
|
2514
|
+
checkLogCounter(15, 2);
|
|
2515
|
+
checkLogCounter(30, 3);
|
|
2516
|
+
checkLogCounter(60, 4);
|
|
2517
|
+
checkLogCounter(60, 5);
|
|
2515
2518
|
|
|
2516
|
-
// simulate media connection being removed ->
|
|
2519
|
+
// simulate media connection being removed -> 1 more upload should happen, but nothing more afterwards
|
|
2517
2520
|
meeting.mediaProperties.webrtcMediaConnection = undefined;
|
|
2521
|
+
checkLogCounter(60, 6);
|
|
2518
2522
|
|
|
2519
|
-
clock.tick(
|
|
2520
|
-
assert.equal(logUploadCounter,
|
|
2523
|
+
clock.tick(120 * 1000 * 60);
|
|
2524
|
+
assert.equal(logUploadCounter, 6);
|
|
2521
2525
|
|
|
2522
2526
|
clock.restore();
|
|
2523
2527
|
});
|
|
@@ -3552,14 +3556,6 @@ describe('plugin-meetings', () => {
|
|
|
3552
3556
|
});
|
|
3553
3557
|
});
|
|
3554
3558
|
|
|
3555
|
-
it('succeeds even if getDevices() throws', async () => {
|
|
3556
|
-
meeting.meetingState = 'ACTIVE';
|
|
3557
|
-
|
|
3558
|
-
sinon.stub(InternalMediaCoreModule, 'getDevices').rejects(new Error('fake error'));
|
|
3559
|
-
|
|
3560
|
-
await meeting.addMedia();
|
|
3561
|
-
});
|
|
3562
|
-
|
|
3563
3559
|
describe('CA ice failures checks', () => {
|
|
3564
3560
|
[
|
|
3565
3561
|
{
|
|
@@ -3743,8 +3739,12 @@ describe('plugin-meetings', () => {
|
|
|
3743
3739
|
meeting.setMercuryListener = sinon.stub();
|
|
3744
3740
|
meeting.locusInfo.onFullLocus = sinon.stub();
|
|
3745
3741
|
meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
|
|
3746
|
-
meeting.webex.meetings.reachability.getReachabilityReportToAttachToRoap = sinon
|
|
3747
|
-
|
|
3742
|
+
meeting.webex.meetings.reachability.getReachabilityReportToAttachToRoap = sinon
|
|
3743
|
+
.stub()
|
|
3744
|
+
.resolves({id: 'fake reachability'});
|
|
3745
|
+
meeting.webex.meetings.reachability.getClientMediaPreferences = sinon
|
|
3746
|
+
.stub()
|
|
3747
|
+
.resolves({id: 'fake clientMediaPreferences'});
|
|
3748
3748
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
|
3749
3749
|
turnServerInfo: {
|
|
3750
3750
|
url: 'turns:turn-server-url:443?transport=tcp',
|
|
@@ -3930,8 +3930,14 @@ describe('plugin-meetings', () => {
|
|
|
3930
3930
|
const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
|
|
3931
3931
|
const {sdp, seq, tieBreaker} = roapOfferMessage;
|
|
3932
3932
|
|
|
3933
|
-
assert.calledWith(
|
|
3934
|
-
|
|
3933
|
+
assert.calledWith(
|
|
3934
|
+
meeting.webex.meetings.reachability.getClientMediaPreferences,
|
|
3935
|
+
meeting.isMultistream,
|
|
3936
|
+
0
|
|
3937
|
+
);
|
|
3938
|
+
assert.calledWith(
|
|
3939
|
+
meeting.webex.meetings.reachability.getReachabilityReportToAttachToRoap
|
|
3940
|
+
);
|
|
3935
3941
|
|
|
3936
3942
|
assert.calledWith(locusMediaRequestStub, {
|
|
3937
3943
|
method: 'PUT',
|
|
@@ -4176,7 +4182,6 @@ describe('plugin-meetings', () => {
|
|
|
4176
4182
|
});
|
|
4177
4183
|
|
|
4178
4184
|
it('addMedia() works correctly when media is enabled with streams to publish', async () => {
|
|
4179
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4180
4185
|
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
4181
4186
|
await simulateRoapOffer();
|
|
4182
4187
|
await simulateRoapOk();
|
|
@@ -4207,12 +4212,9 @@ describe('plugin-meetings', () => {
|
|
|
4207
4212
|
|
|
4208
4213
|
// and that these were the only /media requests that were sent
|
|
4209
4214
|
assert.calledTwice(locusMediaRequestStub);
|
|
4210
|
-
|
|
4211
|
-
assert.calledOnce(handleDeviceLoggingSpy);
|
|
4212
4215
|
});
|
|
4213
4216
|
|
|
4214
4217
|
it('addMedia() works correctly when media is enabled with streams to publish and stream is user muted', async () => {
|
|
4215
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4216
4218
|
fakeMicrophoneStream.userMuted = true;
|
|
4217
4219
|
|
|
4218
4220
|
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
@@ -4244,7 +4246,6 @@ describe('plugin-meetings', () => {
|
|
|
4244
4246
|
|
|
4245
4247
|
// and that these were the only /media requests that were sent
|
|
4246
4248
|
assert.calledTwice(locusMediaRequestStub);
|
|
4247
|
-
assert.calledOnce(handleDeviceLoggingSpy);
|
|
4248
4249
|
});
|
|
4249
4250
|
|
|
4250
4251
|
it('addMedia() works correctly when media is enabled with tracks to publish and track is ended', async () => {
|
|
@@ -4316,7 +4317,6 @@ describe('plugin-meetings', () => {
|
|
|
4316
4317
|
});
|
|
4317
4318
|
|
|
4318
4319
|
it('addMedia() works correctly when media is disabled with streams to publish', async () => {
|
|
4319
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4320
4320
|
await meeting.addMedia({
|
|
4321
4321
|
localStreams: {microphone: fakeMicrophoneStream},
|
|
4322
4322
|
audioEnabled: false,
|
|
@@ -4350,20 +4350,6 @@ describe('plugin-meetings', () => {
|
|
|
4350
4350
|
|
|
4351
4351
|
// and that these were the only /media requests that were sent
|
|
4352
4352
|
assert.calledTwice(locusMediaRequestStub);
|
|
4353
|
-
assert.calledOnce(handleDeviceLoggingSpy);
|
|
4354
|
-
});
|
|
4355
|
-
|
|
4356
|
-
it('handleDeviceLogging not called when media is disabled', async () => {
|
|
4357
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4358
|
-
await meeting.addMedia({
|
|
4359
|
-
localStreams: {microphone: fakeMicrophoneStream},
|
|
4360
|
-
audioEnabled: false,
|
|
4361
|
-
videoEnabled: false,
|
|
4362
|
-
});
|
|
4363
|
-
await simulateRoapOffer();
|
|
4364
|
-
await simulateRoapOk();
|
|
4365
|
-
|
|
4366
|
-
assert.notCalled(handleDeviceLoggingSpy);
|
|
4367
4353
|
});
|
|
4368
4354
|
|
|
4369
4355
|
it('addMedia() works correctly when media is disabled with no streams to publish', async () => {
|
|
@@ -4399,20 +4385,6 @@ describe('plugin-meetings', () => {
|
|
|
4399
4385
|
assert.calledTwice(locusMediaRequestStub);
|
|
4400
4386
|
});
|
|
4401
4387
|
|
|
4402
|
-
it('addMedia() works correctly when media is disabled with no streams to publish', async () => {
|
|
4403
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4404
|
-
await meeting.addMedia({audioEnabled: false});
|
|
4405
|
-
//calling handleDeviceLogging with audioEnaled as true adn videoEnabled as false
|
|
4406
|
-
assert.calledWith(handleDeviceLoggingSpy, false, true);
|
|
4407
|
-
});
|
|
4408
|
-
|
|
4409
|
-
it('addMedia() works correctly when video is disabled with no streams to publish', async () => {
|
|
4410
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4411
|
-
await meeting.addMedia({videoEnabled: false});
|
|
4412
|
-
//calling handleDeviceLogging audioEnabled as true videoEnabled as false
|
|
4413
|
-
assert.calledWith(handleDeviceLoggingSpy, true, false);
|
|
4414
|
-
});
|
|
4415
|
-
|
|
4416
4388
|
it('addMedia() works correctly when video is disabled with no streams to publish', async () => {
|
|
4417
4389
|
await meeting.addMedia({videoEnabled: false});
|
|
4418
4390
|
await simulateRoapOffer();
|
|
@@ -4479,13 +4451,6 @@ describe('plugin-meetings', () => {
|
|
|
4479
4451
|
assert.calledTwice(locusMediaRequestStub);
|
|
4480
4452
|
});
|
|
4481
4453
|
|
|
4482
|
-
it('addMedia() works correctly when both shareAudio and shareVideo is disabled with no streams publish', async () => {
|
|
4483
|
-
const handleDeviceLoggingSpy = sinon.spy(Meeting, 'handleDeviceLogging');
|
|
4484
|
-
await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
|
|
4485
|
-
//calling handleDeviceLogging with audioEnabled true and videoEnabled as true
|
|
4486
|
-
assert.calledWith(handleDeviceLoggingSpy, true, true);
|
|
4487
|
-
});
|
|
4488
|
-
|
|
4489
4454
|
describe('publishStreams()/unpublishStreams() calls', () => {
|
|
4490
4455
|
[
|
|
4491
4456
|
{mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
|
|
@@ -6332,29 +6297,74 @@ describe('plugin-meetings', () => {
|
|
|
6332
6297
|
assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
|
|
6333
6298
|
});
|
|
6334
6299
|
|
|
6335
|
-
it('handles
|
|
6300
|
+
it('handles MeetingInfoV2JoinWebinarError webinar need registration', async () => {
|
|
6336
6301
|
meeting.destination = FAKE_DESTINATION;
|
|
6337
6302
|
meeting.destinationType = FAKE_TYPE;
|
|
6338
6303
|
meeting.attrs.meetingInfoProvider = {
|
|
6339
6304
|
fetchMeetingInfo: sinon
|
|
6340
6305
|
.stub()
|
|
6341
6306
|
.throws(
|
|
6342
|
-
new
|
|
6307
|
+
new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')
|
|
6343
6308
|
),
|
|
6344
6309
|
};
|
|
6345
6310
|
|
|
6346
6311
|
await assert.isRejected(
|
|
6347
6312
|
meeting.fetchMeetingInfo({sendCAevents: true}),
|
|
6348
|
-
|
|
6313
|
+
JoinWebinarError
|
|
6349
6314
|
);
|
|
6350
6315
|
|
|
6351
6316
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
6352
|
-
assert.equal(meeting.meetingInfoFailureCode, 403021);
|
|
6353
6317
|
assert.equal(
|
|
6354
6318
|
meeting.meetingInfoFailureReason,
|
|
6355
6319
|
MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION
|
|
6356
6320
|
);
|
|
6357
6321
|
});
|
|
6322
|
+
|
|
6323
|
+
it('handles MeetingInfoV2JoinWebinarError webinar need join with webcast', async () => {
|
|
6324
|
+
meeting.destination = FAKE_DESTINATION;
|
|
6325
|
+
meeting.destinationType = FAKE_TYPE;
|
|
6326
|
+
meeting.attrs.meetingInfoProvider = {
|
|
6327
|
+
fetchMeetingInfo: sinon
|
|
6328
|
+
.stub()
|
|
6329
|
+
.throws(
|
|
6330
|
+
new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')
|
|
6331
|
+
),
|
|
6332
|
+
};
|
|
6333
|
+
|
|
6334
|
+
await assert.isRejected(
|
|
6335
|
+
meeting.fetchMeetingInfo({sendCAevents: true}),
|
|
6336
|
+
JoinWebinarError
|
|
6337
|
+
);
|
|
6338
|
+
|
|
6339
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
6340
|
+
assert.equal(
|
|
6341
|
+
meeting.meetingInfoFailureReason,
|
|
6342
|
+
MEETING_INFO_FAILURE_REASON.NEED_JOIN_WITH_WEBCAST
|
|
6343
|
+
);
|
|
6344
|
+
});
|
|
6345
|
+
|
|
6346
|
+
it('handles MeetingInfoV2JoinWebinarError webinar need registrationId', async () => {
|
|
6347
|
+
meeting.destination = FAKE_DESTINATION;
|
|
6348
|
+
meeting.destinationType = FAKE_TYPE;
|
|
6349
|
+
meeting.attrs.meetingInfoProvider = {
|
|
6350
|
+
fetchMeetingInfo: sinon
|
|
6351
|
+
.stub()
|
|
6352
|
+
.throws(
|
|
6353
|
+
new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')
|
|
6354
|
+
),
|
|
6355
|
+
};
|
|
6356
|
+
|
|
6357
|
+
await assert.isRejected(
|
|
6358
|
+
meeting.fetchMeetingInfo({sendCAevents: true}),
|
|
6359
|
+
JoinWebinarError
|
|
6360
|
+
);
|
|
6361
|
+
|
|
6362
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
6363
|
+
assert.equal(
|
|
6364
|
+
meeting.meetingInfoFailureReason,
|
|
6365
|
+
MEETING_INFO_FAILURE_REASON.WEBINAR_NEED_REGISTRATIONID
|
|
6366
|
+
);
|
|
6367
|
+
});
|
|
6358
6368
|
});
|
|
6359
6369
|
|
|
6360
6370
|
describe('#refreshPermissionToken', () => {
|
|
@@ -7817,7 +7827,9 @@ describe('plugin-meetings', () => {
|
|
|
7817
7827
|
});
|
|
7818
7828
|
|
|
7819
7829
|
it('should collect ice candidates', () => {
|
|
7820
|
-
eventListeners[MediaConnectionEventNames.ICE_CANDIDATE]({
|
|
7830
|
+
eventListeners[MediaConnectionEventNames.ICE_CANDIDATE]({
|
|
7831
|
+
candidate: {candidate: 'candidate'},
|
|
7832
|
+
});
|
|
7821
7833
|
|
|
7822
7834
|
assert.equal(meeting.iceCandidatesCount, 1);
|
|
7823
7835
|
});
|
|
@@ -8123,10 +8135,10 @@ describe('plugin-meetings', () => {
|
|
|
8123
8135
|
meeting.statsAnalyzer.stopAnalyzer = sinon.stub().resolves();
|
|
8124
8136
|
meeting.reconnectionManager = {
|
|
8125
8137
|
reconnect: sinon.stub().resolves(),
|
|
8126
|
-
resetReconnectionTimer: () => {}
|
|
8138
|
+
resetReconnectionTimer: () => {},
|
|
8127
8139
|
};
|
|
8128
8140
|
meeting.currentMediaStatus = {
|
|
8129
|
-
video: true
|
|
8141
|
+
video: true,
|
|
8130
8142
|
};
|
|
8131
8143
|
|
|
8132
8144
|
await mockFailedEvent();
|
|
@@ -8677,6 +8689,13 @@ describe('plugin-meetings', () => {
|
|
|
8677
8689
|
{payload: test1}
|
|
8678
8690
|
);
|
|
8679
8691
|
assert.calledOnce(meeting.updateLLMConnection);
|
|
8692
|
+
assert.calledOnceWithExactly(
|
|
8693
|
+
Metrics.sendBehavioralMetric,
|
|
8694
|
+
BEHAVIORAL_METRICS.GUEST_ENTERED_LOBBY,
|
|
8695
|
+
{
|
|
8696
|
+
correlation_id: meeting.correlationId,
|
|
8697
|
+
}
|
|
8698
|
+
);
|
|
8680
8699
|
done();
|
|
8681
8700
|
});
|
|
8682
8701
|
it('listens to the self admitted guest event', (done) => {
|
|
@@ -8698,6 +8717,13 @@ describe('plugin-meetings', () => {
|
|
|
8698
8717
|
assert.calledOnce(meeting.updateLLMConnection);
|
|
8699
8718
|
assert.calledOnceWithExactly(meeting.rtcMetrics.sendNextMetrics);
|
|
8700
8719
|
|
|
8720
|
+
assert.calledOnceWithExactly(
|
|
8721
|
+
Metrics.sendBehavioralMetric,
|
|
8722
|
+
BEHAVIORAL_METRICS.GUEST_EXITED_LOBBY,
|
|
8723
|
+
{
|
|
8724
|
+
correlation_id: meeting.correlationId,
|
|
8725
|
+
}
|
|
8726
|
+
);
|
|
8701
8727
|
done();
|
|
8702
8728
|
});
|
|
8703
8729
|
|
|
@@ -9030,6 +9056,8 @@ describe('plugin-meetings', () => {
|
|
|
9030
9056
|
});
|
|
9031
9057
|
|
|
9032
9058
|
it('listens to MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED', async () => {
|
|
9059
|
+
meeting.webinar.updatePracticeSessionStatus = sinon.stub();
|
|
9060
|
+
|
|
9033
9061
|
const state = {example: 'value'};
|
|
9034
9062
|
|
|
9035
9063
|
await meeting.locusInfo.emitScoped(
|
|
@@ -9038,6 +9066,7 @@ describe('plugin-meetings', () => {
|
|
|
9038
9066
|
{state}
|
|
9039
9067
|
);
|
|
9040
9068
|
|
|
9069
|
+
assert.calledOnceWithExactly(meeting.webinar.updatePracticeSessionStatus, state);
|
|
9041
9070
|
assert.calledWith(
|
|
9042
9071
|
TriggerProxy.trigger,
|
|
9043
9072
|
meeting,
|
|
@@ -10657,6 +10686,7 @@ describe('plugin-meetings', () => {
|
|
|
10657
10686
|
meeting.webex.internal.llm.on = sinon.stub();
|
|
10658
10687
|
meeting.webex.internal.llm.off = sinon.stub();
|
|
10659
10688
|
meeting.processRelayEvent = sinon.stub();
|
|
10689
|
+
meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(false);
|
|
10660
10690
|
});
|
|
10661
10691
|
|
|
10662
10692
|
it('does not connect if the call is not joined yet', async () => {
|
|
@@ -10788,6 +10818,19 @@ describe('plugin-meetings', () => {
|
|
|
10788
10818
|
meeting.processRelayEvent
|
|
10789
10819
|
);
|
|
10790
10820
|
});
|
|
10821
|
+
|
|
10822
|
+
|
|
10823
|
+
it('connect ps data channel if ps started in webinar', async () => {
|
|
10824
|
+
meeting.joinedWith = {state: 'JOINED'};
|
|
10825
|
+
meeting.locusInfo = {url: 'a url', info: {datachannelUrl: 'a datachannel url', practiceSessionDatachannelUrl: 'a ps datachannel url'}};
|
|
10826
|
+
meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(true);
|
|
10827
|
+
await meeting.updateLLMConnection();
|
|
10828
|
+
|
|
10829
|
+
assert.notCalled(webex.internal.llm.disconnectLLM);
|
|
10830
|
+
assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a ps datachannel url');
|
|
10831
|
+
|
|
10832
|
+
});
|
|
10833
|
+
|
|
10791
10834
|
});
|
|
10792
10835
|
|
|
10793
10836
|
describe('#setLocus', () => {
|
|
@@ -10979,6 +11022,7 @@ describe('plugin-meetings', () => {
|
|
|
10979
11022
|
beforeEach(() => {
|
|
10980
11023
|
meeting.selfId = '9528d952-e4de-46cf-8157-fd4823b98377';
|
|
10981
11024
|
meeting.deviceUrl = 'my-web-url';
|
|
11025
|
+
meeting.locusInfo.info = {isWebinar: false};
|
|
10982
11026
|
});
|
|
10983
11027
|
|
|
10984
11028
|
const USER_IDS = {
|
|
@@ -11204,13 +11248,24 @@ describe('plugin-meetings', () => {
|
|
|
11204
11248
|
|
|
11205
11249
|
activeSharingId.whiteboard = beneficiaryId;
|
|
11206
11250
|
|
|
11207
|
-
eventTrigger.share.push({
|
|
11251
|
+
eventTrigger.share.push(meeting.webinar.selfIsAttendee ? {
|
|
11252
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
11253
|
+
functionName: 'remoteShare',
|
|
11254
|
+
eventPayload: {
|
|
11255
|
+
memberId: null,
|
|
11256
|
+
url,
|
|
11257
|
+
shareInstanceId,
|
|
11258
|
+
annotationInfo: undefined,
|
|
11259
|
+
resourceType: undefined,
|
|
11260
|
+
},
|
|
11261
|
+
} : {
|
|
11208
11262
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
11209
11263
|
functionName: 'startWhiteboardShare',
|
|
11210
11264
|
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
|
11211
11265
|
});
|
|
11212
11266
|
|
|
11213
|
-
shareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
11267
|
+
shareStatus = meeting.webinar.selfIsAttendee ? SHARE_STATUS.REMOTE_SHARE_ACTIVE : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
11268
|
+
|
|
11214
11269
|
}
|
|
11215
11270
|
|
|
11216
11271
|
if (eventTrigger.member) {
|
|
@@ -11242,13 +11297,24 @@ describe('plugin-meetings', () => {
|
|
|
11242
11297
|
newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
|
|
11243
11298
|
newPayload.current.content.beneficiaryId = otherBeneficiaryId;
|
|
11244
11299
|
|
|
11245
|
-
eventTrigger.share.push({
|
|
11300
|
+
eventTrigger.share.push(meeting.webinar.selfIsAttendee ? {
|
|
11301
|
+
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
11302
|
+
functionName: 'remoteShare',
|
|
11303
|
+
eventPayload: {
|
|
11304
|
+
memberId: null,
|
|
11305
|
+
url,
|
|
11306
|
+
shareInstanceId,
|
|
11307
|
+
annotationInfo: undefined,
|
|
11308
|
+
resourceType: undefined,
|
|
11309
|
+
},
|
|
11310
|
+
} : {
|
|
11246
11311
|
eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
11247
11312
|
functionName: 'startWhiteboardShare',
|
|
11248
11313
|
eventPayload: {resourceUrl, memberId: beneficiaryId},
|
|
11249
11314
|
});
|
|
11250
11315
|
|
|
11251
|
-
shareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
11316
|
+
shareStatus = meeting.webinar.selfIsAttendee ? SHARE_STATUS.REMOTE_SHARE_ACTIVE : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
11317
|
+
|
|
11252
11318
|
} else {
|
|
11253
11319
|
eventTrigger.share.push({
|
|
11254
11320
|
eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
|
|
@@ -11375,6 +11441,38 @@ describe('plugin-meetings', () => {
|
|
|
11375
11441
|
assert.exists(meeting.setUpLocusMediaSharesListener);
|
|
11376
11442
|
});
|
|
11377
11443
|
|
|
11444
|
+
describe('Whiteboard Share - Webinar Attendee', () => {
|
|
11445
|
+
it('Scenario #1: Whiteboard sharing as a webinar attendee', () => {
|
|
11446
|
+
// Set the webinar attendee flag
|
|
11447
|
+
meeting.webinar = { selfIsAttendee: true };
|
|
11448
|
+
meeting.locusInfo.info.isWebinar = true;
|
|
11449
|
+
|
|
11450
|
+
// Step 1: Start sharing whiteboard A
|
|
11451
|
+
const data1 = generateData(
|
|
11452
|
+
blankPayload, // Initial payload
|
|
11453
|
+
true, // isGranting: Granting share
|
|
11454
|
+
false, // isContent: Whiteboard (not content)
|
|
11455
|
+
USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
|
|
11456
|
+
RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
|
|
11457
|
+
);
|
|
11458
|
+
|
|
11459
|
+
// Step 2: Stop sharing whiteboard A
|
|
11460
|
+
const data2 = generateData(
|
|
11461
|
+
data1.payload, // Updated payload from Step 1
|
|
11462
|
+
false, // isGranting: Stopping share
|
|
11463
|
+
false, // isContent: Whiteboard
|
|
11464
|
+
USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
|
|
11465
|
+
);
|
|
11466
|
+
|
|
11467
|
+
// Validate the payload changes and status updates
|
|
11468
|
+
payloadTestHelper([data1]);
|
|
11469
|
+
|
|
11470
|
+
// Specific assertions for webinar attendee status
|
|
11471
|
+
assert.equal(meeting.shareStatus, SHARE_STATUS.REMOTE_SHARE_ACTIVE);
|
|
11472
|
+
});
|
|
11473
|
+
});
|
|
11474
|
+
|
|
11475
|
+
|
|
11378
11476
|
describe('Whiteboard A --> Whiteboard B', () => {
|
|
11379
11477
|
it('Scenario #1: you share both whiteboards', () => {
|
|
11380
11478
|
const data1 = generateData(
|
|
@@ -26,7 +26,7 @@ describe('plugin-meetings', () => {
|
|
|
26
26
|
webex.meetings.reachability = {
|
|
27
27
|
getReachabilityReportToAttachToRoap: sinon.stub().resolves({}),
|
|
28
28
|
getClientMediaPreferences: sinon.stub().resolves({}),
|
|
29
|
-
};
|
|
29
|
+
};
|
|
30
30
|
|
|
31
31
|
const logger = {
|
|
32
32
|
info: sandbox.stub(),
|
|
@@ -165,21 +165,6 @@ describe('plugin-meetings', () => {
|
|
|
165
165
|
assert(LoggerProxy.logger.log.called, 'log called');
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
|
-
|
|
169
|
-
describe('#handleDeviceLogging', () => {
|
|
170
|
-
it('should not log if called without devices', () => {
|
|
171
|
-
MeetingUtil.handleDeviceLogging();
|
|
172
|
-
assert(!LoggerProxy.logger.log.called, 'log not called');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('should log device settings', () => {
|
|
176
|
-
const mockDevices = [{deviceId: 'device-1'}, {deviceId: 'device-2'}];
|
|
177
|
-
|
|
178
|
-
assert(MeetingUtil.handleDeviceLogging, 'is defined');
|
|
179
|
-
MeetingUtil.handleDeviceLogging(mockDevices);
|
|
180
|
-
assert(LoggerProxy.logger.log.called, 'log called');
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
168
|
});
|
|
184
169
|
|
|
185
170
|
describe('addSequence', () => {
|
|
@@ -424,17 +409,17 @@ describe('plugin-meetings', () => {
|
|
|
424
409
|
const FAKE_CLIENT_MEDIA_PREFERENCES = {
|
|
425
410
|
id: 'fake client media preferences',
|
|
426
411
|
};
|
|
427
|
-
|
|
412
|
+
|
|
428
413
|
webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
|
|
429
414
|
webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
|
|
430
|
-
|
|
415
|
+
|
|
431
416
|
sinon
|
|
432
417
|
.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
|
|
433
418
|
.get(() => true);
|
|
434
419
|
sinon
|
|
435
420
|
.stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
|
|
436
421
|
.get(() => true);
|
|
437
|
-
|
|
422
|
+
|
|
438
423
|
await MeetingUtil.joinMeeting(meeting, {
|
|
439
424
|
reachability: 'reachability',
|
|
440
425
|
roapMessage: 'roapMessage',
|
|
@@ -775,6 +760,13 @@ describe('plugin-meetings', () => {
|
|
|
775
760
|
});
|
|
776
761
|
});
|
|
777
762
|
|
|
763
|
+
describe('canStartBreakout', () => {
|
|
764
|
+
it('works as expected', () => {
|
|
765
|
+
assert.deepEqual(MeetingUtil.canStartBreakout(['DISABLE_BREAKOUT_START']), false);
|
|
766
|
+
assert.deepEqual(MeetingUtil.canStartBreakout([]), true);
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
|
|
778
770
|
describe('canBroadcastMessageToBreakout', () => {
|
|
779
771
|
it('works as expected', () => {
|
|
780
772
|
assert.deepEqual(
|
|
@@ -18,7 +18,7 @@ import MeetingInfo, {
|
|
|
18
18
|
MeetingInfoV2CaptchaError,
|
|
19
19
|
MeetingInfoV2AdhocMeetingError,
|
|
20
20
|
MeetingInfoV2PolicyError,
|
|
21
|
-
|
|
21
|
+
MeetingInfoV2JoinWebinarError,
|
|
22
22
|
} from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
|
|
23
23
|
import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
|
|
24
24
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
@@ -895,9 +895,14 @@ describe('plugin-meetings', () => {
|
|
|
895
895
|
{errorCode: 403021},
|
|
896
896
|
{errorCode: 403022},
|
|
897
897
|
{errorCode: 403024},
|
|
898
|
+
{errorCode: 403137},
|
|
899
|
+
{errorCode: 423007},
|
|
900
|
+
{errorCode: 403026},
|
|
901
|
+
{errorCode: 403037},
|
|
902
|
+
{errorCode: 403137},
|
|
898
903
|
],
|
|
899
904
|
({errorCode}) => {
|
|
900
|
-
it(`should throw a
|
|
905
|
+
it(`should throw a MeetingInfoV2JoinWebinarError for error code ${errorCode}`, async () => {
|
|
901
906
|
const message = 'a message';
|
|
902
907
|
const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
|
|
903
908
|
|
|
@@ -909,7 +914,7 @@ describe('plugin-meetings', () => {
|
|
|
909
914
|
await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
|
|
910
915
|
assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
|
|
911
916
|
} catch (err) {
|
|
912
|
-
assert.instanceOf(err,
|
|
917
|
+
assert.instanceOf(err, MeetingInfoV2JoinWebinarError);
|
|
913
918
|
assert.deepEqual(err.message, `${message}, code=${errorCode}`);
|
|
914
919
|
assert.equal(err.wbxAppApiCode, errorCode);
|
|
915
920
|
assert.deepEqual(err.meetingInfo, meetingInfoData);
|
|
@@ -917,7 +922,7 @@ describe('plugin-meetings', () => {
|
|
|
917
922
|
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
918
923
|
assert.calledWith(
|
|
919
924
|
Metrics.sendBehavioralMetric,
|
|
920
|
-
BEHAVIORAL_METRICS.
|
|
925
|
+
BEHAVIORAL_METRICS.JOIN_WEBINAR_ERROR,
|
|
921
926
|
{code: errorCode}
|
|
922
927
|
);
|
|
923
928
|
|
|
@@ -131,9 +131,9 @@ describe('plugin-meetings', () => {
|
|
|
131
131
|
logger,
|
|
132
132
|
people: {
|
|
133
133
|
_getMe: sinon.stub().resolves({
|
|
134
|
-
type: 'validuser',
|
|
134
|
+
type: 'validuser',
|
|
135
135
|
}),
|
|
136
|
-
}
|
|
136
|
+
},
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
startReachabilityStub = sinon.stub(webex.meetings, 'startReachability').resolves();
|
|
@@ -1985,6 +1985,8 @@ describe('plugin-meetings', () => {
|
|
|
1985
1985
|
const meetingIds = {
|
|
1986
1986
|
meetingId: meeting.id,
|
|
1987
1987
|
correlationId: meeting.correlationId,
|
|
1988
|
+
roles: meeting.roles,
|
|
1989
|
+
callStateForMetrics: meeting.callStateForMetrics,
|
|
1988
1990
|
};
|
|
1989
1991
|
|
|
1990
1992
|
webex.meetings.destroy(meeting, test1);
|
|
@@ -2021,6 +2023,8 @@ describe('plugin-meetings', () => {
|
|
|
2021
2023
|
|
|
2022
2024
|
assert.equal(deletedMeetingInfo.id, meetingIds.meetingId);
|
|
2023
2025
|
assert.equal(deletedMeetingInfo.correlationId, meetingIds.correlationId);
|
|
2026
|
+
assert.equal(deletedMeetingInfo.roles, meetingIds.roles);
|
|
2027
|
+
assert.equal(deletedMeetingInfo.callStateForMetrics, meetingIds.callStateForMetrics);
|
|
2024
2028
|
});
|
|
2025
2029
|
});
|
|
2026
2030
|
|
|
@@ -2092,7 +2096,7 @@ describe('plugin-meetings', () => {
|
|
|
2092
2096
|
);
|
|
2093
2097
|
});
|
|
2094
2098
|
|
|
2095
|
-
const setup = ({me = {
|
|
2099
|
+
const setup = ({me = {type: 'validuser'}, user} = {}) => {
|
|
2096
2100
|
loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
|
|
2097
2101
|
assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
|
|
2098
2102
|
|
|
@@ -2113,9 +2117,9 @@ describe('plugin-meetings', () => {
|
|
|
2113
2117
|
|
|
2114
2118
|
it('should not call request.getMeetingPreferences if user is a guest', async () => {
|
|
2115
2119
|
setup({me: {type: 'appuser'}});
|
|
2116
|
-
|
|
2120
|
+
|
|
2117
2121
|
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2118
|
-
|
|
2122
|
+
|
|
2119
2123
|
assert.equal(webex.meetings.preferredWebexSite, '');
|
|
2120
2124
|
assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
|
|
2121
2125
|
assert.notCalled(webex.internal.services.getMeetingPreferences);
|