@webex/plugin-meetings 3.11.0 → 3.12.0
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/aiEnableRequest/index.js +184 -0
- package/dist/aiEnableRequest/index.js.map +1 -0
- package/dist/aiEnableRequest/utils.js +36 -0
- package/dist/aiEnableRequest/utils.js.map +1 -0
- package/dist/annotation/index.js +14 -5
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +28 -6
- package/dist/constants.js.map +1 -1
- package/dist/hashTree/constants.js +3 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTree.js +18 -0
- package/dist/hashTree/hashTree.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +709 -380
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/types.js +4 -2
- package/dist/hashTree/types.js.map +1 -1
- package/dist/hashTree/utils.js +10 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/constant.js +12 -0
- package/dist/interceptors/constant.js.map +1 -0
- package/dist/interceptors/dataChannelAuthToken.js +290 -0
- package/dist/interceptors/dataChannelAuthToken.js.map +1 -0
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/utils.js +27 -0
- package/dist/interceptors/utils.js.map +1 -0
- package/dist/interpretation/index.js +2 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +5 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +217 -79
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +1 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/locus-info/types.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.js +57 -1
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/properties.js +4 -2
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +7 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1082 -861
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +50 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +133 -3
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +100 -45
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +9 -60
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +11 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/reachability/index.js +18 -10
- package/dist/reachability/index.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +0 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/types/aiEnableRequest/index.d.ts +5 -0
- package/dist/types/aiEnableRequest/utils.d.ts +2 -0
- package/dist/types/config.d.ts +3 -0
- package/dist/types/constants.d.ts +23 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTree.d.ts +7 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +99 -14
- package/dist/types/hashTree/types.d.ts +3 -0
- package/dist/types/hashTree/utils.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/interceptors/constant.d.ts +5 -0
- package/dist/types/interceptors/dataChannelAuthToken.d.ts +43 -0
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/utils.d.ts +1 -0
- package/dist/types/locus-info/index.d.ts +21 -2
- package/dist/types/locus-info/types.d.ts +1 -0
- package/dist/types/media/MediaConnectionAwaiter.d.ts +10 -1
- package/dist/types/media/properties.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +6 -0
- package/dist/types/meeting/index.d.ts +38 -6
- package/dist/types/meeting/request.d.ts +16 -1
- package/dist/types/meeting/request.type.d.ts +5 -0
- package/dist/types/meeting/util.d.ts +31 -0
- package/dist/types/meetings/index.d.ts +4 -2
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/util.d.ts +5 -0
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +0 -23
- package/dist/types/reactions/reactions.type.d.ts +1 -0
- package/dist/types/webinar/utils.d.ts +6 -0
- package/dist/webinar/index.js +260 -90
- package/dist/webinar/index.js.map +1 -1
- package/dist/webinar/utils.js +25 -0
- package/dist/webinar/utils.js.map +1 -0
- package/package.json +24 -23
- package/src/aiEnableRequest/README.md +84 -0
- package/src/aiEnableRequest/index.ts +170 -0
- package/src/aiEnableRequest/utils.ts +25 -0
- package/src/annotation/index.ts +27 -7
- package/src/config.ts +3 -0
- package/src/constants.ts +29 -1
- package/src/hashTree/constants.ts +1 -0
- package/src/hashTree/hashTree.ts +17 -0
- package/src/hashTree/hashTreeParser.ts +627 -249
- package/src/hashTree/types.ts +4 -0
- package/src/hashTree/utils.ts +9 -0
- package/src/index.ts +8 -1
- package/src/interceptors/constant.ts +6 -0
- package/src/interceptors/dataChannelAuthToken.ts +170 -0
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/utils.ts +16 -0
- package/src/interpretation/index.ts +2 -2
- package/src/locus-info/controlsUtils.ts +11 -0
- package/src/locus-info/index.ts +231 -61
- package/src/locus-info/selfUtils.ts +1 -0
- package/src/locus-info/types.ts +1 -0
- package/src/media/MediaConnectionAwaiter.ts +41 -1
- package/src/media/properties.ts +3 -1
- package/src/meeting/in-meeting-actions.ts +12 -0
- package/src/meeting/index.ts +205 -44
- package/src/meeting/request.ts +42 -0
- package/src/meeting/request.type.ts +6 -0
- package/src/meeting/util.ts +160 -2
- package/src/meetings/index.ts +135 -41
- package/src/member/index.ts +10 -0
- package/src/member/util.ts +12 -0
- package/src/metrics/constants.ts +1 -0
- package/src/multistream/mediaRequestManager.ts +4 -54
- package/src/multistream/remoteMediaManager.ts +13 -0
- package/src/reachability/index.ts +9 -0
- package/src/reactions/reactions.type.ts +1 -0
- package/src/reconnection-manager/index.ts +0 -1
- package/src/webinar/index.ts +162 -5
- package/src/webinar/utils.ts +16 -0
- package/test/unit/spec/aiEnableRequest/index.ts +981 -0
- package/test/unit/spec/aiEnableRequest/utils.ts +130 -0
- package/test/unit/spec/annotation/index.ts +69 -7
- package/test/unit/spec/hashTree/hashTree.ts +66 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1869 -189
- package/test/unit/spec/interceptors/dataChannelAuthToken.ts +210 -0
- package/test/unit/spec/interceptors/utils.ts +75 -0
- package/test/unit/spec/locus-info/controlsUtils.js +29 -0
- package/test/unit/spec/locus-info/index.js +383 -46
- package/test/unit/spec/media/MediaConnectionAwaiter.ts +41 -1
- package/test/unit/spec/media/properties.ts +12 -3
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -2
- package/test/unit/spec/meeting/index.js +716 -115
- package/test/unit/spec/meeting/request.js +70 -0
- package/test/unit/spec/meeting/utils.js +438 -26
- package/test/unit/spec/meetings/index.js +652 -31
- package/test/unit/spec/member/index.js +28 -4
- package/test/unit/spec/member/util.js +65 -27
- package/test/unit/spec/multistream/mediaRequestManager.ts +2 -85
- package/test/unit/spec/multistream/remoteMediaManager.ts +30 -0
- package/test/unit/spec/reachability/index.ts +23 -0
- package/test/unit/spec/reconnection-manager/index.js +4 -8
- package/test/unit/spec/webinar/index.ts +348 -36
- package/test/unit/spec/webinar/utils.ts +39 -0
|
@@ -115,6 +115,7 @@ describe('plugin-meetings', () => {
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
describe('#changeVideoLayout', () => {
|
|
118
|
+
|
|
118
119
|
const locusUrl = 'locusURL';
|
|
119
120
|
const deviceUrl = 'deviceUrl';
|
|
120
121
|
const layoutType = 'Equal';
|
|
@@ -918,4 +919,73 @@ describe('plugin-meetings', () => {
|
|
|
918
919
|
});
|
|
919
920
|
});
|
|
920
921
|
});
|
|
922
|
+
|
|
923
|
+
describe('#fetchDatachannelToken', () => {
|
|
924
|
+
const locusUrl = 'https://locus.example.com/locus/api/v1/loci/123';
|
|
925
|
+
const participantId = 'participant-123';
|
|
926
|
+
|
|
927
|
+
beforeEach(() => {
|
|
928
|
+
sinon.restore();
|
|
929
|
+
locusDeltaRequestSpy = sinon.stub(meetingsRequest, 'locusDeltaRequest');
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
it('sends GET request to regular datachannel token endpoint', async () => {
|
|
933
|
+
locusDeltaRequestSpy.resolves({body: {}});
|
|
934
|
+
|
|
935
|
+
await meetingsRequest.fetchDatachannelToken({
|
|
936
|
+
locusUrl,
|
|
937
|
+
requestingParticipantId: participantId,
|
|
938
|
+
isPracticeSession: false,
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
assert.calledOnceWithExactly(locusDeltaRequestSpy, {
|
|
942
|
+
method: 'GET',
|
|
943
|
+
uri: `${locusUrl}/participant/${participantId}/datachannel/token`,
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
it('sends GET request to practice session datachannel token endpoint', async () => {
|
|
948
|
+
locusDeltaRequestSpy.resolves({body: {}});
|
|
949
|
+
|
|
950
|
+
await meetingsRequest.fetchDatachannelToken({
|
|
951
|
+
locusUrl,
|
|
952
|
+
requestingParticipantId: participantId,
|
|
953
|
+
isPracticeSession: true,
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
assert.calledOnceWithExactly(locusDeltaRequestSpy, {
|
|
957
|
+
method: 'GET',
|
|
958
|
+
uri: `${locusUrl}/participant/${participantId}/practiceSession/datachannel/token`,
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
it('rejects when locusUrl or participantId is missing', async () => {
|
|
963
|
+
await assert.isRejected(
|
|
964
|
+
meetingsRequest.fetchDatachannelToken({
|
|
965
|
+
locusUrl: null,
|
|
966
|
+
requestingParticipantId: participantId,
|
|
967
|
+
}),
|
|
968
|
+
/locusUrl and participantId are required/
|
|
969
|
+
);
|
|
970
|
+
|
|
971
|
+
await assert.isRejected(
|
|
972
|
+
meetingsRequest.fetchDatachannelToken({
|
|
973
|
+
locusUrl,
|
|
974
|
+
requestingParticipantId: null,
|
|
975
|
+
}),
|
|
976
|
+
/locusUrl and participantId are required/
|
|
977
|
+
);
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
it('returns null when locusDeltaRequest fails', async () => {
|
|
981
|
+
locusDeltaRequestSpy.rejects(new Error('network error'));
|
|
982
|
+
|
|
983
|
+
const result = await meetingsRequest.fetchDatachannelToken({
|
|
984
|
+
locusUrl,
|
|
985
|
+
requestingParticipantId: participantId,
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
assert.equal(result, null);
|
|
989
|
+
});
|
|
990
|
+
});
|
|
921
991
|
});
|
|
@@ -11,6 +11,7 @@ import MockWebex from '@webex/test-helper-mock-webex';
|
|
|
11
11
|
import * as BrowserDetectionModule from '@webex/plugin-meetings/src/common/browser-detection';
|
|
12
12
|
import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
|
|
13
13
|
import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
|
|
14
|
+
import {ServerRoles} from '@webex/plugin-meetings/src/member/types';
|
|
14
15
|
|
|
15
16
|
describe('plugin-meetings', () => {
|
|
16
17
|
let webex;
|
|
@@ -53,16 +54,18 @@ describe('plugin-meetings', () => {
|
|
|
53
54
|
meeting.unsetPeerConnections = sinon.stub();
|
|
54
55
|
meeting.reconnectionManager = {cleanUp: sinon.stub()};
|
|
55
56
|
meeting.stopKeepAlive = sinon.stub();
|
|
56
|
-
meeting.
|
|
57
|
+
meeting.cleanupLLMConneciton = sinon.stub().resolves();
|
|
57
58
|
meeting.breakouts = {cleanUp: sinon.stub()};
|
|
59
|
+
meeting.webinar = {cleanUp: sinon.stub()};
|
|
58
60
|
meeting.annotaion = {cleanUp: sinon.stub()};
|
|
59
61
|
meeting.getWebexObject = sinon.stub().returns(webex);
|
|
60
62
|
meeting.simultaneousInterpretation = {cleanUp: sinon.stub()};
|
|
61
63
|
meeting.trigger = sinon.stub();
|
|
62
64
|
meeting.webex = webex;
|
|
63
65
|
meeting.webex.internal.newMetrics.callDiagnosticMetrics =
|
|
64
|
-
|
|
65
|
-
meeting.webex.internal.newMetrics.callDiagnosticMetrics.clearEventLimitsForCorrelationId =
|
|
66
|
+
meeting.webex.internal.newMetrics.callDiagnosticMetrics || {};
|
|
67
|
+
meeting.webex.internal.newMetrics.callDiagnosticMetrics.clearEventLimitsForCorrelationId =
|
|
68
|
+
sinon.stub();
|
|
66
69
|
});
|
|
67
70
|
|
|
68
71
|
afterEach(() => {
|
|
@@ -83,7 +86,7 @@ describe('plugin-meetings', () => {
|
|
|
83
86
|
assert.calledOnce(meeting.unsetPeerConnections);
|
|
84
87
|
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
85
88
|
assert.calledOnce(meeting.stopKeepAlive);
|
|
86
|
-
assert.
|
|
89
|
+
assert.calledOnceWithExactly(meeting.cleanupLLMConneciton, {throwOnError: false});
|
|
87
90
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
88
91
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
89
92
|
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
@@ -104,7 +107,7 @@ describe('plugin-meetings', () => {
|
|
|
104
107
|
assert.calledOnce(meeting.unsetPeerConnections);
|
|
105
108
|
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
106
109
|
assert.calledOnce(meeting.stopKeepAlive);
|
|
107
|
-
assert.notCalled(meeting.
|
|
110
|
+
assert.notCalled(meeting.cleanupLLMConneciton);
|
|
108
111
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
109
112
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
110
113
|
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
@@ -124,7 +127,7 @@ describe('plugin-meetings', () => {
|
|
|
124
127
|
assert.calledOnce(meeting.unsetPeerConnections);
|
|
125
128
|
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
126
129
|
assert.calledOnce(meeting.stopKeepAlive);
|
|
127
|
-
assert.notCalled(meeting.
|
|
130
|
+
assert.notCalled(meeting.cleanupLLMConneciton);
|
|
128
131
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
129
132
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
130
133
|
assert.calledOnce(webex.internal.device.meetingEnded);
|
|
@@ -245,7 +248,11 @@ describe('plugin-meetings', () => {
|
|
|
245
248
|
const response = MeetingUtil.updateLocusFromApiResponse(meeting, originalResponse);
|
|
246
249
|
|
|
247
250
|
assert.deepEqual(response, originalResponse);
|
|
248
|
-
assert.calledOnceWithExactly(
|
|
251
|
+
assert.calledOnceWithExactly(
|
|
252
|
+
meeting.locusInfo.handleLocusAPIResponse,
|
|
253
|
+
meeting,
|
|
254
|
+
originalResponse.body
|
|
255
|
+
);
|
|
249
256
|
});
|
|
250
257
|
|
|
251
258
|
it('should handle locus being missing from the response', () => {
|
|
@@ -361,8 +368,8 @@ describe('plugin-meetings', () => {
|
|
|
361
368
|
describe('remoteUpdateAudioVideo', () => {
|
|
362
369
|
it('#Should call meetingRequest.locusMediaRequest with correct parameters and return the full response', async () => {
|
|
363
370
|
const fakeResponse = {
|
|
364
|
-
body: {
|
|
365
|
-
headers: {
|
|
371
|
+
body: {locus: {url: 'locusUrl'}},
|
|
372
|
+
headers: {},
|
|
366
373
|
};
|
|
367
374
|
const meeting = {
|
|
368
375
|
id: 'meeting-id',
|
|
@@ -480,6 +487,11 @@ describe('plugin-meetings', () => {
|
|
|
480
487
|
identifiers: {
|
|
481
488
|
trackingId: 'trackingId',
|
|
482
489
|
},
|
|
490
|
+
eventData: {
|
|
491
|
+
hasMismatchedSocket: false,
|
|
492
|
+
mercurySocketUrl: '',
|
|
493
|
+
deviceSocketUrl: 'ws://example.com',
|
|
494
|
+
},
|
|
483
495
|
},
|
|
484
496
|
options: {
|
|
485
497
|
meetingId: meeting.id,
|
|
@@ -649,21 +661,26 @@ describe('plugin-meetings', () => {
|
|
|
649
661
|
it('should post client event with error when join fails', async () => {
|
|
650
662
|
const joinError = new Error('Join failed');
|
|
651
663
|
meeting.meetingRequest.joinMeeting.rejects(joinError);
|
|
652
|
-
meeting.meetingInfo = {
|
|
664
|
+
meeting.meetingInfo = {meetingLookupUrl: 'test-lookup-url'};
|
|
653
665
|
|
|
654
666
|
try {
|
|
655
667
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
656
668
|
assert.fail('Expected joinMeeting to throw an error');
|
|
657
669
|
} catch (error) {
|
|
658
670
|
assert.equal(error, joinError);
|
|
659
|
-
|
|
671
|
+
|
|
660
672
|
// Verify error client event was submitted
|
|
661
673
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
662
674
|
name: 'client.locus.join.response',
|
|
663
675
|
payload: {
|
|
664
|
-
identifiers: {
|
|
676
|
+
identifiers: {meetingLookupUrl: 'test-lookup-url'},
|
|
677
|
+
eventData: {
|
|
678
|
+
hasMismatchedSocket: false,
|
|
679
|
+
mercurySocketUrl: '',
|
|
680
|
+
deviceSocketUrl: 'ws://example.com',
|
|
681
|
+
},
|
|
665
682
|
},
|
|
666
|
-
options: {
|
|
683
|
+
options: {meetingId: meeting.id, rawError: joinError},
|
|
667
684
|
});
|
|
668
685
|
}
|
|
669
686
|
});
|
|
@@ -721,7 +738,7 @@ describe('plugin-meetings', () => {
|
|
|
721
738
|
assert.fail('Expected joinMeetingOptions to throw PasswordError');
|
|
722
739
|
} catch (error) {
|
|
723
740
|
assert.instanceOf(error, PasswordError);
|
|
724
|
-
|
|
741
|
+
|
|
725
742
|
// Verify client event was submitted with error details
|
|
726
743
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
727
744
|
name: 'client.meetinginfo.response',
|
|
@@ -759,7 +776,7 @@ describe('plugin-meetings', () => {
|
|
|
759
776
|
assert.fail('Expected joinMeetingOptions to throw CaptchaError');
|
|
760
777
|
} catch (error) {
|
|
761
778
|
assert.instanceOf(error, CaptchaError);
|
|
762
|
-
|
|
779
|
+
|
|
763
780
|
// Verify client event was submitted with error details
|
|
764
781
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
765
782
|
name: 'client.meetinginfo.response',
|
|
@@ -921,6 +938,104 @@ describe('plugin-meetings', () => {
|
|
|
921
938
|
});
|
|
922
939
|
});
|
|
923
940
|
|
|
941
|
+
describe('canAttendeeRequestAiAssistantEnabled', () => {
|
|
942
|
+
it('returns false when user is a cohost', () => {
|
|
943
|
+
assert.deepEqual(
|
|
944
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
945
|
+
['ATTENDEE_REQUEST_AI_ASSISTANT_ENABLED'],
|
|
946
|
+
[ServerRoles.Cohost]
|
|
947
|
+
),
|
|
948
|
+
false
|
|
949
|
+
);
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
it('returns false when user is a moderator', () => {
|
|
953
|
+
assert.deepEqual(
|
|
954
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
955
|
+
['ATTENDEE_REQUEST_AI_ASSISTANT_ENABLED'],
|
|
956
|
+
[ServerRoles.Moderator]
|
|
957
|
+
),
|
|
958
|
+
false
|
|
959
|
+
);
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
it('returns false when user is both cohost and moderator', () => {
|
|
963
|
+
assert.deepEqual(
|
|
964
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
965
|
+
['ATTENDEE_REQUEST_AI_ASSISTANT_ENABLED'],
|
|
966
|
+
[ServerRoles.Cohost, ServerRoles.Moderator]
|
|
967
|
+
),
|
|
968
|
+
false
|
|
969
|
+
);
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
it('returns true when user is an attendee and display hint is present', () => {
|
|
973
|
+
assert.deepEqual(
|
|
974
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
975
|
+
['ATTENDEE_REQUEST_AI_ASSISTANT_ENABLED'],
|
|
976
|
+
[]
|
|
977
|
+
),
|
|
978
|
+
true
|
|
979
|
+
);
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
it('returns true when user has other roles (not host/cohost) and display hint is present', () => {
|
|
983
|
+
assert.deepEqual(
|
|
984
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(
|
|
985
|
+
['ATTENDEE_REQUEST_AI_ASSISTANT_ENABLED'],
|
|
986
|
+
['SomeOtherRole']
|
|
987
|
+
),
|
|
988
|
+
true
|
|
989
|
+
);
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
it('returns false when user is an attendee but display hint is not present', () => {
|
|
993
|
+
assert.deepEqual(MeetingUtil.canAttendeeRequestAiAssistantEnabled([], []), false);
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
it('returns false when user is an attendee with other display hints but not the AI assistant one', () => {
|
|
997
|
+
assert.deepEqual(
|
|
998
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled(['SOME_OTHER_HINT', 'ANOTHER_HINT'], []),
|
|
999
|
+
false
|
|
1000
|
+
);
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
it('returns false when host/cohost even if display hint is not present', () => {
|
|
1004
|
+
assert.deepEqual(
|
|
1005
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled([], [ServerRoles.Cohost]),
|
|
1006
|
+
false
|
|
1007
|
+
);
|
|
1008
|
+
assert.deepEqual(
|
|
1009
|
+
MeetingUtil.canAttendeeRequestAiAssistantEnabled([], [ServerRoles.Moderator]),
|
|
1010
|
+
false
|
|
1011
|
+
);
|
|
1012
|
+
});
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
describe('attendeeRequestAiAssistantDeclinedAll', () => {
|
|
1016
|
+
it('returns true when display hint is present', () => {
|
|
1017
|
+
assert.isTrue(
|
|
1018
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll([
|
|
1019
|
+
'ATTENDEE_REQUEST_AI_ASSISTANT_DECLINED_ALL',
|
|
1020
|
+
])
|
|
1021
|
+
);
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
it('returns false when display hint is not present', () => {
|
|
1025
|
+
assert.isFalse(MeetingUtil.attendeeRequestAiAssistantDeclinedAll([]));
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
it('returns false when display hint is absent among other hints', () => {
|
|
1029
|
+
assert.isFalse(
|
|
1030
|
+
MeetingUtil.attendeeRequestAiAssistantDeclinedAll(['SOME_OTHER_HINT', 'ANOTHER_HINT'])
|
|
1031
|
+
);
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
it('returns false when called with no arguments', () => {
|
|
1035
|
+
assert.isFalse(MeetingUtil.attendeeRequestAiAssistantDeclinedAll());
|
|
1036
|
+
});
|
|
1037
|
+
});
|
|
1038
|
+
|
|
924
1039
|
describe('bothLeaveAndEndMeetingAvailable', () => {
|
|
925
1040
|
it('works as expected', () => {
|
|
926
1041
|
assert.deepEqual(
|
|
@@ -939,6 +1054,46 @@ describe('plugin-meetings', () => {
|
|
|
939
1054
|
});
|
|
940
1055
|
});
|
|
941
1056
|
|
|
1057
|
+
describe('requireHostEndMeetingBeforeLeave', () => {
|
|
1058
|
+
it('works as expected', () => {
|
|
1059
|
+
assert.deepEqual(
|
|
1060
|
+
MeetingUtil.requireHostEndMeetingBeforeLeave(['REQUIRE_HOST_END_MEETING_BEFORE_LEAVE']),
|
|
1061
|
+
true
|
|
1062
|
+
);
|
|
1063
|
+
assert.deepEqual(
|
|
1064
|
+
MeetingUtil.requireHostEndMeetingBeforeLeave([
|
|
1065
|
+
'LEAVE_TRANSFER_HOST_END_MEETING',
|
|
1066
|
+
'END_MEETING',
|
|
1067
|
+
]),
|
|
1068
|
+
false
|
|
1069
|
+
);
|
|
1070
|
+
assert.deepEqual(
|
|
1071
|
+
MeetingUtil.requireHostEndMeetingBeforeLeave([
|
|
1072
|
+
'REQUIRE_HOST_END_MEETING_BEFORE_LEAVE',
|
|
1073
|
+
'END_MEETING',
|
|
1074
|
+
]),
|
|
1075
|
+
true
|
|
1076
|
+
);
|
|
1077
|
+
assert.deepEqual(
|
|
1078
|
+
MeetingUtil.requireHostEndMeetingBeforeLeave([
|
|
1079
|
+
'REQUIRE_HOST_END_MEETING_BEFORE_LEAVE',
|
|
1080
|
+
'LEAVE_MEETING',
|
|
1081
|
+
]),
|
|
1082
|
+
true
|
|
1083
|
+
);
|
|
1084
|
+
assert.deepEqual(
|
|
1085
|
+
MeetingUtil.requireHostEndMeetingBeforeLeave([
|
|
1086
|
+
'REQUIRE_HOST_END_MEETING_BEFORE_LEAVE',
|
|
1087
|
+
'LEAVE_MEETING',
|
|
1088
|
+
'END_MEETING',
|
|
1089
|
+
]),
|
|
1090
|
+
true
|
|
1091
|
+
);
|
|
1092
|
+
assert.deepEqual(MeetingUtil.requireHostEndMeetingBeforeLeave(['END_MEETING']), true);
|
|
1093
|
+
assert.deepEqual(MeetingUtil.requireHostEndMeetingBeforeLeave([]), false);
|
|
1094
|
+
});
|
|
1095
|
+
});
|
|
1096
|
+
|
|
942
1097
|
describe('canUserLock', () => {
|
|
943
1098
|
it('works as expected', () => {
|
|
944
1099
|
assert.deepEqual(
|
|
@@ -972,15 +1127,18 @@ describe('plugin-meetings', () => {
|
|
|
972
1127
|
{functionName: 'canStartManualCaption', displayHint: 'MANUAL_CAPTION_START'},
|
|
973
1128
|
{functionName: 'canStopManualCaption', displayHint: 'MANUAL_CAPTION_STOP'},
|
|
974
1129
|
|
|
975
|
-
{functionName: 'isLocalRecordingStarted',displayHint:'LOCAL_RECORDING_STATUS_STARTED'},
|
|
1130
|
+
{functionName: 'isLocalRecordingStarted', displayHint: 'LOCAL_RECORDING_STATUS_STARTED'},
|
|
976
1131
|
{functionName: 'isLocalRecordingStopped', displayHint: 'LOCAL_RECORDING_STATUS_STOPPED'},
|
|
977
1132
|
{functionName: 'isLocalRecordingPaused', displayHint: 'LOCAL_RECORDING_STATUS_PAUSED'},
|
|
978
|
-
{functionName: 'isLocalStreamingStarted',displayHint:'STREAMING_STATUS_STARTED'},
|
|
1133
|
+
{functionName: 'isLocalStreamingStarted', displayHint: 'STREAMING_STATUS_STARTED'},
|
|
979
1134
|
{functionName: 'isLocalStreamingStopped', displayHint: 'STREAMING_STATUS_STOPPED'},
|
|
980
1135
|
|
|
981
1136
|
{functionName: 'isManualCaptionActive', displayHint: 'MANUAL_CAPTION_STATUS_ACTIVE'},
|
|
982
1137
|
|
|
983
|
-
{
|
|
1138
|
+
{
|
|
1139
|
+
functionName: 'isSpokenLanguageAutoDetectionEnabled',
|
|
1140
|
+
displayHint: 'SPOKEN_LANGUAGE_AUTO_DETECTION_ENABLED',
|
|
1141
|
+
},
|
|
984
1142
|
|
|
985
1143
|
{functionName: 'isWebexAssistantActive', displayHint: 'WEBEX_ASSISTANT_STATUS_ACTIVE'},
|
|
986
1144
|
{functionName: 'canViewCaptionPanel', displayHint: 'ENABLE_CAPTION_PANEL'},
|
|
@@ -1446,11 +1604,9 @@ describe('plugin-meetings', () => {
|
|
|
1446
1604
|
id: 'selfId123',
|
|
1447
1605
|
},
|
|
1448
1606
|
},
|
|
1607
|
+
metaData: {id: 'some hash tree metadata'},
|
|
1449
1608
|
dataSets: [{name: 'dataset1', url: 'http://dataset.com'}],
|
|
1450
|
-
mediaConnections: [
|
|
1451
|
-
{mediaId: 'mediaId456'},
|
|
1452
|
-
{someOtherField: 'value'},
|
|
1453
|
-
],
|
|
1609
|
+
mediaConnections: [{mediaId: 'mediaId456'}, {someOtherField: 'value'}],
|
|
1454
1610
|
},
|
|
1455
1611
|
};
|
|
1456
1612
|
});
|
|
@@ -1466,6 +1622,7 @@ describe('plugin-meetings', () => {
|
|
|
1466
1622
|
locusId: '12345',
|
|
1467
1623
|
selfId: 'selfId123',
|
|
1468
1624
|
mediaId: 'mediaId456',
|
|
1625
|
+
metadata: {id: 'some hash tree metadata'},
|
|
1469
1626
|
});
|
|
1470
1627
|
});
|
|
1471
1628
|
|
|
@@ -1495,20 +1652,275 @@ describe('plugin-meetings', () => {
|
|
|
1495
1652
|
locusUrl: 'https://locus-a.wbx2.com/locus/api/v1/loci/12345',
|
|
1496
1653
|
locusId: '12345',
|
|
1497
1654
|
selfId: 'selfId123',
|
|
1655
|
+
metadata: {id: 'some hash tree metadata'},
|
|
1498
1656
|
});
|
|
1499
1657
|
assert.isUndefined(result.mediaId);
|
|
1500
1658
|
});
|
|
1501
1659
|
|
|
1502
1660
|
it('handles mediaConnections without mediaId', () => {
|
|
1503
|
-
response.body.mediaConnections = [
|
|
1504
|
-
{someField: 'value1'},
|
|
1505
|
-
{anotherField: 'value2'},
|
|
1506
|
-
];
|
|
1661
|
+
response.body.mediaConnections = [{someField: 'value1'}, {anotherField: 'value2'}];
|
|
1507
1662
|
|
|
1508
1663
|
const result = MeetingUtil.parseLocusJoin(response);
|
|
1509
1664
|
|
|
1510
1665
|
assert.isUndefined(result.mediaId);
|
|
1511
1666
|
});
|
|
1512
1667
|
});
|
|
1668
|
+
|
|
1669
|
+
describe('#sanitizeWebSocketUrl', () => {
|
|
1670
|
+
it('extracts protocol, host, and pathname from URL', () => {
|
|
1671
|
+
const url = 'wss://example.com:443/mercury/path?token=secret&key=value#fragment';
|
|
1672
|
+
const result = MeetingUtil.sanitizeWebSocketUrl(url);
|
|
1673
|
+
|
|
1674
|
+
assert.equal(result, 'wss://example.com:443/mercury/path');
|
|
1675
|
+
});
|
|
1676
|
+
|
|
1677
|
+
it('handles URL without query string or hash', () => {
|
|
1678
|
+
const url = 'wss://example.com/path';
|
|
1679
|
+
const result = MeetingUtil.sanitizeWebSocketUrl(url);
|
|
1680
|
+
|
|
1681
|
+
assert.equal(result, 'wss://example.com/path');
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
it('removes authentication from URL', () => {
|
|
1685
|
+
const url = 'wss://user:password@example.com/path?token=secret';
|
|
1686
|
+
const result = MeetingUtil.sanitizeWebSocketUrl(url);
|
|
1687
|
+
|
|
1688
|
+
assert.equal(result, 'wss://example.com/path');
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
it('returns empty string for null or undefined', () => {
|
|
1692
|
+
assert.equal(MeetingUtil.sanitizeWebSocketUrl(null), '');
|
|
1693
|
+
assert.equal(MeetingUtil.sanitizeWebSocketUrl(undefined), '');
|
|
1694
|
+
});
|
|
1695
|
+
|
|
1696
|
+
it('returns empty string for non-string input', () => {
|
|
1697
|
+
assert.equal(MeetingUtil.sanitizeWebSocketUrl(123), '');
|
|
1698
|
+
assert.equal(MeetingUtil.sanitizeWebSocketUrl({}), '');
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
it('returns empty string for invalid URL', () => {
|
|
1702
|
+
const result = MeetingUtil.sanitizeWebSocketUrl('not a valid url');
|
|
1703
|
+
|
|
1704
|
+
assert.equal(result, '');
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
it('handles URL without pathname', () => {
|
|
1708
|
+
const url = 'wss://example.com?query=value';
|
|
1709
|
+
const result = MeetingUtil.sanitizeWebSocketUrl(url);
|
|
1710
|
+
|
|
1711
|
+
assert.equal(result, 'wss://example.com');
|
|
1712
|
+
});
|
|
1713
|
+
});
|
|
1714
|
+
|
|
1715
|
+
describe('#_urlsPartiallyMatch', () => {
|
|
1716
|
+
it('returns true when URLs match exactly (ignoring query and hash)', () => {
|
|
1717
|
+
const url1 = 'wss://example.com:443/path?token=abc#fragment1';
|
|
1718
|
+
const url2 = 'wss://example.com:443/path?token=xyz#fragment2';
|
|
1719
|
+
|
|
1720
|
+
assert.isTrue(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1721
|
+
});
|
|
1722
|
+
|
|
1723
|
+
it('returns true when one URL is proxied and ends with the other', () => {
|
|
1724
|
+
const url1 = 'wss://other.example.com/somepath/mercury.example.com/v1/path';
|
|
1725
|
+
const url2 = 'wss://mercury.example.com/v1/path';
|
|
1726
|
+
|
|
1727
|
+
assert.isTrue(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
it('returns true when the second URL is proxied', () => {
|
|
1731
|
+
const url1 = 'wss://mercury.example.com/v1/path';
|
|
1732
|
+
const url2 = 'wss://other.example.com/somepath/mercury.example.com/v1/path';
|
|
1733
|
+
|
|
1734
|
+
assert.isTrue(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1735
|
+
});
|
|
1736
|
+
|
|
1737
|
+
it('returns false when hosts differ and no partial match', () => {
|
|
1738
|
+
const url1 = 'wss://example1.com/path';
|
|
1739
|
+
const url2 = 'wss://example2.com/path';
|
|
1740
|
+
|
|
1741
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
it('returns false when pathnames differ and no partial match', () => {
|
|
1745
|
+
const url1 = 'wss://example.com/path1';
|
|
1746
|
+
const url2 = 'wss://example.com/path2';
|
|
1747
|
+
|
|
1748
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1749
|
+
});
|
|
1750
|
+
|
|
1751
|
+
it('returns false when either URL is null or undefined', () => {
|
|
1752
|
+
const url = 'wss://example.com/path';
|
|
1753
|
+
|
|
1754
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(null, url));
|
|
1755
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(url, null));
|
|
1756
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(undefined, url));
|
|
1757
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(url, undefined));
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
it('returns false when both URLs are null', () => {
|
|
1761
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(null, null));
|
|
1762
|
+
});
|
|
1763
|
+
|
|
1764
|
+
it('returns false when URL parsing fails', () => {
|
|
1765
|
+
const url1 = 'invalid url';
|
|
1766
|
+
const url2 = 'wss://example.com/path';
|
|
1767
|
+
|
|
1768
|
+
assert.isFalse(MeetingUtil._urlsPartiallyMatch(url1, url2));
|
|
1769
|
+
});
|
|
1770
|
+
});
|
|
1771
|
+
|
|
1772
|
+
describe('#getSocketUrlInfo', () => {
|
|
1773
|
+
it('returns socket URL info when URLs differ', () => {
|
|
1774
|
+
const testWebex = {
|
|
1775
|
+
internal: {
|
|
1776
|
+
mercury: {
|
|
1777
|
+
socket: {
|
|
1778
|
+
url: 'wss://mercury.example.com:443/path?token=abc',
|
|
1779
|
+
},
|
|
1780
|
+
},
|
|
1781
|
+
device: {
|
|
1782
|
+
webSocketUrl: 'wss://device.example.com:443/path?token=xyz',
|
|
1783
|
+
},
|
|
1784
|
+
},
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1788
|
+
|
|
1789
|
+
assert.isTrue(result.hasMismatchedSocket);
|
|
1790
|
+
assert.equal(result.mercurySocketUrl, 'wss://mercury.example.com:443/path');
|
|
1791
|
+
assert.equal(result.deviceSocketUrl, 'wss://device.example.com:443/path');
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
it('returns socket URL info when URLs match', () => {
|
|
1795
|
+
const testWebex = {
|
|
1796
|
+
internal: {
|
|
1797
|
+
mercury: {
|
|
1798
|
+
socket: {
|
|
1799
|
+
url: 'wss://example.com:443/path?token=abc',
|
|
1800
|
+
},
|
|
1801
|
+
},
|
|
1802
|
+
device: {
|
|
1803
|
+
webSocketUrl: 'wss://example.com:443/path?token=xyz',
|
|
1804
|
+
},
|
|
1805
|
+
},
|
|
1806
|
+
};
|
|
1807
|
+
|
|
1808
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1809
|
+
|
|
1810
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1811
|
+
assert.equal(result.mercurySocketUrl, 'wss://example.com:443/path');
|
|
1812
|
+
assert.equal(result.deviceSocketUrl, 'wss://example.com:443/path');
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
it('returns hasMismatchedSocket as false when one URL is proxied (partial match)', () => {
|
|
1816
|
+
const testWebex = {
|
|
1817
|
+
internal: {
|
|
1818
|
+
mercury: {
|
|
1819
|
+
socket: {
|
|
1820
|
+
url: 'wss://other.example.com/somepath/mercury.example.com/v1/apps/wx2/registrations/00000000-0000-0000-0000-000000000000/messages',
|
|
1821
|
+
},
|
|
1822
|
+
},
|
|
1823
|
+
device: {
|
|
1824
|
+
webSocketUrl:
|
|
1825
|
+
'wss://mercury.example.com/v1/apps/wx2/registrations/00000000-0000-0000-0000-000000000000/messages',
|
|
1826
|
+
},
|
|
1827
|
+
},
|
|
1828
|
+
};
|
|
1829
|
+
|
|
1830
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1831
|
+
|
|
1832
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1833
|
+
assert.equal(
|
|
1834
|
+
result.mercurySocketUrl,
|
|
1835
|
+
'wss://other.example.com/somepath/mercury.example.com/v1/apps/wx2/registrations/00000000-0000-0000-0000-000000000000/messages'
|
|
1836
|
+
);
|
|
1837
|
+
assert.equal(
|
|
1838
|
+
result.deviceSocketUrl,
|
|
1839
|
+
'wss://mercury.example.com/v1/apps/wx2/registrations/00000000-0000-0000-0000-000000000000/messages'
|
|
1840
|
+
);
|
|
1841
|
+
});
|
|
1842
|
+
|
|
1843
|
+
it('returns false for hasMismatchedSocket when mercury socket URL is missing', () => {
|
|
1844
|
+
const testWebex = {
|
|
1845
|
+
internal: {
|
|
1846
|
+
mercury: {
|
|
1847
|
+
socket: {},
|
|
1848
|
+
},
|
|
1849
|
+
device: {
|
|
1850
|
+
webSocketUrl: 'wss://device.example.com:443/path',
|
|
1851
|
+
},
|
|
1852
|
+
},
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1855
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1856
|
+
|
|
1857
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1858
|
+
assert.equal(result.mercurySocketUrl, '');
|
|
1859
|
+
assert.equal(result.deviceSocketUrl, 'wss://device.example.com:443/path');
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
it('returns false for hasMismatchedSocket when device socket URL is missing', () => {
|
|
1863
|
+
const testWebex = {
|
|
1864
|
+
internal: {
|
|
1865
|
+
mercury: {
|
|
1866
|
+
socket: {
|
|
1867
|
+
url: 'wss://mercury.example.com:443/path',
|
|
1868
|
+
},
|
|
1869
|
+
},
|
|
1870
|
+
device: {},
|
|
1871
|
+
},
|
|
1872
|
+
};
|
|
1873
|
+
|
|
1874
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1875
|
+
|
|
1876
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1877
|
+
assert.equal(result.mercurySocketUrl, 'wss://mercury.example.com:443/path');
|
|
1878
|
+
assert.equal(result.deviceSocketUrl, '');
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
it('returns default values when webex object is missing properties', () => {
|
|
1882
|
+
const testWebex = {
|
|
1883
|
+
internal: {},
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1887
|
+
|
|
1888
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1889
|
+
assert.equal(result.mercurySocketUrl, '');
|
|
1890
|
+
assert.equal(result.deviceSocketUrl, '');
|
|
1891
|
+
});
|
|
1892
|
+
|
|
1893
|
+
it('handles error gracefully and returns default values', () => {
|
|
1894
|
+
const testWebex = null;
|
|
1895
|
+
|
|
1896
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1897
|
+
|
|
1898
|
+
assert.isFalse(result.hasMismatchedSocket);
|
|
1899
|
+
assert.equal(result.mercurySocketUrl, '');
|
|
1900
|
+
assert.equal(result.deviceSocketUrl, '');
|
|
1901
|
+
});
|
|
1902
|
+
|
|
1903
|
+
it('sanitizes URLs by removing query parameters', () => {
|
|
1904
|
+
const testWebex = {
|
|
1905
|
+
internal: {
|
|
1906
|
+
mercury: {
|
|
1907
|
+
socket: {
|
|
1908
|
+
url: 'wss://mercury.example.com/path?secret=token123&key=value',
|
|
1909
|
+
},
|
|
1910
|
+
},
|
|
1911
|
+
device: {
|
|
1912
|
+
webSocketUrl: 'wss://device.example.com/path?secret=differenttoken&key=value',
|
|
1913
|
+
},
|
|
1914
|
+
},
|
|
1915
|
+
};
|
|
1916
|
+
|
|
1917
|
+
const result = MeetingUtil.getSocketUrlInfo(testWebex);
|
|
1918
|
+
|
|
1919
|
+
assert.notInclude(result.mercurySocketUrl, 'secret');
|
|
1920
|
+
assert.notInclude(result.mercurySocketUrl, 'token123');
|
|
1921
|
+
assert.notInclude(result.deviceSocketUrl, 'secret');
|
|
1922
|
+
assert.notInclude(result.deviceSocketUrl, 'differenttoken');
|
|
1923
|
+
});
|
|
1924
|
+
});
|
|
1513
1925
|
});
|
|
1514
1926
|
});
|