@webex/plugin-meetings 3.0.0-beta.391 → 3.0.0-beta.392
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/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +16 -7
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +738 -616
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.js +172 -0
- package/dist/meeting/voicea-meeting.js.map +1 -0
- package/dist/meeting-info/meeting-info-v2.js +9 -6
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/util.js +7 -6
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +8 -4
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/member/index.js +0 -1
- package/dist/member/index.js.map +1 -1
- package/dist/types/constants.d.ts +8 -2
- package/dist/types/meeting/index.d.ts +56 -12
- package/dist/types/meeting/voicea-meeting.d.ts +16 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +20 -20
- package/src/config.ts +2 -4
- package/src/constants.ts +11 -2
- package/src/meeting/index.ts +320 -157
- package/src/meeting/util.ts +5 -1
- package/src/meeting/voicea-meeting.ts +122 -0
- package/src/meeting-info/meeting-info-v2.ts +5 -11
- package/src/meeting-info/util.ts +12 -9
- package/src/meeting-info/utilv2.ts +24 -14
- package/src/member/index.ts +0 -1
- package/test/integration/spec/journey.js +2 -2
- package/test/unit/spec/breakouts/breakout.ts +2 -1
- package/test/unit/spec/breakouts/index.ts +7 -4
- package/test/unit/spec/locus-info/index.js +27 -18
- package/test/unit/spec/locus-info/selfUtils.js +6 -11
- package/test/unit/spec/media/index.ts +5 -0
- package/test/unit/spec/meeting/index.js +315 -87
- package/test/unit/spec/meeting/utils.js +52 -10
- package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +20 -15
- package/test/unit/spec/meetings/index.js +78 -10
- package/test/unit/spec/metrics/index.js +1 -2
- package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
- package/test/unit/spec/recording-controller/index.js +0 -1
- package/test/unit/spec/roap/turnDiscovery.ts +1 -1
|
@@ -57,7 +57,8 @@ describe('plugin-meetings', () => {
|
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
describe('#cleanup', () => {
|
|
60
|
-
it('do clean up on meeting object', async () => {
|
|
60
|
+
it('do clean up on meeting object with LLM enabled', async () => {
|
|
61
|
+
meeting.config = {enableAutomaticLLM : true};
|
|
61
62
|
await MeetingUtil.cleanUp(meeting);
|
|
62
63
|
assert.calledOnce(meeting.cleanupLocalStreams);
|
|
63
64
|
assert.calledOnce(meeting.closeRemoteStreams);
|
|
@@ -71,6 +72,37 @@ describe('plugin-meetings', () => {
|
|
|
71
72
|
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
72
73
|
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
73
74
|
});
|
|
75
|
+
|
|
76
|
+
it('do clean up on meeting object with LLM disabled', async () => {
|
|
77
|
+
meeting.config = {enableAutomaticLLM : false};
|
|
78
|
+
await MeetingUtil.cleanUp(meeting);
|
|
79
|
+
assert.calledOnce(meeting.cleanupLocalStreams);
|
|
80
|
+
assert.calledOnce(meeting.closeRemoteStreams);
|
|
81
|
+
assert.calledOnce(meeting.closePeerConnections);
|
|
82
|
+
|
|
83
|
+
assert.calledOnce(meeting.unsetRemoteStreams);
|
|
84
|
+
assert.calledOnce(meeting.unsetPeerConnections);
|
|
85
|
+
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
86
|
+
assert.calledOnce(meeting.stopKeepAlive);
|
|
87
|
+
assert.notCalled(meeting.updateLLMConnection);
|
|
88
|
+
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
89
|
+
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('do clean up on meeting object with no config', async () => {
|
|
93
|
+
await MeetingUtil.cleanUp(meeting);
|
|
94
|
+
assert.calledOnce(meeting.cleanupLocalStreams);
|
|
95
|
+
assert.calledOnce(meeting.closeRemoteStreams);
|
|
96
|
+
assert.calledOnce(meeting.closePeerConnections);
|
|
97
|
+
|
|
98
|
+
assert.calledOnce(meeting.unsetRemoteStreams);
|
|
99
|
+
assert.calledOnce(meeting.unsetPeerConnections);
|
|
100
|
+
assert.calledOnce(meeting.reconnectionManager.cleanUp);
|
|
101
|
+
assert.calledOnce(meeting.stopKeepAlive);
|
|
102
|
+
assert.notCalled(meeting.updateLLMConnection);
|
|
103
|
+
assert.calledOnce(meeting.breakouts.cleanUp);
|
|
104
|
+
assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
|
|
105
|
+
});
|
|
74
106
|
});
|
|
75
107
|
|
|
76
108
|
describe('logging', () => {
|
|
@@ -369,7 +401,7 @@ describe('plugin-meetings', () => {
|
|
|
369
401
|
getWebexObject: sinon.stub().returns(webex),
|
|
370
402
|
};
|
|
371
403
|
|
|
372
|
-
|
|
404
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
373
405
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
374
406
|
|
|
375
407
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
@@ -396,6 +428,7 @@ describe('plugin-meetings', () => {
|
|
|
396
428
|
mediaConnections: 'mediaConnections',
|
|
397
429
|
},
|
|
398
430
|
});
|
|
431
|
+
parseLocusJoinSpy.restore();
|
|
399
432
|
});
|
|
400
433
|
|
|
401
434
|
it('#Should call meetingRequest.joinMeeting with breakoutsSupported=true when passed in as true', async () => {
|
|
@@ -406,7 +439,7 @@ describe('plugin-meetings', () => {
|
|
|
406
439
|
getWebexObject: sinon.stub().returns(webex),
|
|
407
440
|
};
|
|
408
441
|
|
|
409
|
-
|
|
442
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
410
443
|
await MeetingUtil.joinMeeting(meeting, {
|
|
411
444
|
breakoutsSupported: true,
|
|
412
445
|
});
|
|
@@ -415,6 +448,7 @@ describe('plugin-meetings', () => {
|
|
|
415
448
|
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
416
449
|
|
|
417
450
|
assert.equal(parameter.breakoutsSupported, true);
|
|
451
|
+
parseLocusJoinSpy.restore();
|
|
418
452
|
});
|
|
419
453
|
|
|
420
454
|
it('#Should call meetingRequest.joinMeeting with liveAnnotationSupported=true when passed in as true', async () => {
|
|
@@ -425,7 +459,7 @@ describe('plugin-meetings', () => {
|
|
|
425
459
|
getWebexObject: sinon.stub().returns(webex),
|
|
426
460
|
};
|
|
427
461
|
|
|
428
|
-
|
|
462
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
429
463
|
await MeetingUtil.joinMeeting(meeting, {
|
|
430
464
|
liveAnnotationSupported: true,
|
|
431
465
|
});
|
|
@@ -434,6 +468,7 @@ describe('plugin-meetings', () => {
|
|
|
434
468
|
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
435
469
|
|
|
436
470
|
assert.equal(parameter.liveAnnotationSupported, true);
|
|
471
|
+
parseLocusJoinSpy.restore();
|
|
437
472
|
});
|
|
438
473
|
|
|
439
474
|
it('#Should call meetingRequest.joinMeeting with locale=en_UK, deviceCapabilities=["TEST"] when they are passed in as those values', async () => {
|
|
@@ -444,7 +479,7 @@ describe('plugin-meetings', () => {
|
|
|
444
479
|
getWebexObject: sinon.stub().returns(webex),
|
|
445
480
|
};
|
|
446
481
|
|
|
447
|
-
|
|
482
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
448
483
|
await MeetingUtil.joinMeeting(meeting, {
|
|
449
484
|
locale: 'en_UK',
|
|
450
485
|
deviceCapabilities: ['TEST'],
|
|
@@ -455,6 +490,7 @@ describe('plugin-meetings', () => {
|
|
|
455
490
|
|
|
456
491
|
assert.equal(parameter.locale, 'en_UK');
|
|
457
492
|
assert.deepEqual(parameter.deviceCapabilities, ['TEST']);
|
|
493
|
+
parseLocusJoinSpy.restore();
|
|
458
494
|
});
|
|
459
495
|
|
|
460
496
|
it('#Should call meetingRequest.joinMeeting with preferTranscoding=false when multistream is enabled', async () => {
|
|
@@ -468,7 +504,7 @@ describe('plugin-meetings', () => {
|
|
|
468
504
|
getWebexObject: sinon.stub().returns(webex),
|
|
469
505
|
};
|
|
470
506
|
|
|
471
|
-
|
|
507
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
472
508
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
473
509
|
|
|
474
510
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
@@ -476,6 +512,7 @@ describe('plugin-meetings', () => {
|
|
|
476
512
|
|
|
477
513
|
assert.equal(parameter.inviteeAddress, 'meetingJoinUrl');
|
|
478
514
|
assert.equal(parameter.preferTranscoding, false);
|
|
515
|
+
parseLocusJoinSpy.restore();
|
|
479
516
|
});
|
|
480
517
|
|
|
481
518
|
it('#Should fallback sipUrl if meetingJoinUrl does not exists', async () => {
|
|
@@ -488,13 +525,14 @@ describe('plugin-meetings', () => {
|
|
|
488
525
|
getWebexObject: sinon.stub().returns(webex),
|
|
489
526
|
};
|
|
490
527
|
|
|
491
|
-
|
|
528
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
492
529
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
493
530
|
|
|
494
531
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
495
532
|
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
496
533
|
|
|
497
534
|
assert.equal(parameter.inviteeAddress, 'sipUri');
|
|
535
|
+
parseLocusJoinSpy.restore();
|
|
498
536
|
});
|
|
499
537
|
|
|
500
538
|
it('#Should fallback to meetingNumber if meetingJoinUrl/sipUrl does not exists', async () => {
|
|
@@ -507,7 +545,7 @@ describe('plugin-meetings', () => {
|
|
|
507
545
|
getWebexObject: sinon.stub().returns(webex),
|
|
508
546
|
};
|
|
509
547
|
|
|
510
|
-
|
|
548
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
511
549
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
512
550
|
|
|
513
551
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
@@ -515,6 +553,7 @@ describe('plugin-meetings', () => {
|
|
|
515
553
|
|
|
516
554
|
assert.isUndefined(parameter.inviteeAddress);
|
|
517
555
|
assert.equal(parameter.meetingNumber, 'meetingNumber');
|
|
556
|
+
parseLocusJoinSpy.restore();
|
|
518
557
|
});
|
|
519
558
|
|
|
520
559
|
it('should pass in the locusClusterUrl from meetingInfo', async () => {
|
|
@@ -528,19 +567,20 @@ describe('plugin-meetings', () => {
|
|
|
528
567
|
getWebexObject: sinon.stub().returns(webex),
|
|
529
568
|
};
|
|
530
569
|
|
|
531
|
-
|
|
570
|
+
const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
|
|
532
571
|
await MeetingUtil.joinMeeting(meeting, {});
|
|
533
572
|
|
|
534
573
|
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
535
574
|
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
536
575
|
|
|
537
576
|
assert.equal(parameter.locusClusterUrl, 'locusClusterUrl');
|
|
577
|
+
parseLocusJoinSpy.restore();
|
|
538
578
|
});
|
|
539
579
|
});
|
|
540
580
|
|
|
541
581
|
describe('joinMeetingOptions', () => {
|
|
542
582
|
it('sends client events correctly', async () => {
|
|
543
|
-
|
|
583
|
+
const joinMeetingSpy = sinon.stub(MeetingUtil, 'joinMeeting').rejects({});
|
|
544
584
|
MeetingUtil.isPinOrGuest = sinon.stub().returns(true);
|
|
545
585
|
const meeting = {
|
|
546
586
|
id: 'meeting-id',
|
|
@@ -571,6 +611,8 @@ describe('plugin-meetings', () => {
|
|
|
571
611
|
meetingId: meeting.id,
|
|
572
612
|
},
|
|
573
613
|
});
|
|
614
|
+
} finally {
|
|
615
|
+
joinMeetingSpy.restore();
|
|
574
616
|
}
|
|
575
617
|
});
|
|
576
618
|
});
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSpeakerFromProxyOrStore,
|
|
3
|
+
processNewCaptions,
|
|
4
|
+
} from '@webex/plugin-meetings/src/meeting/voicea-meeting';
|
|
5
|
+
import {assert} from '@webex/test-helper-chai';
|
|
6
|
+
import { expect } from 'chai';
|
|
7
|
+
|
|
8
|
+
describe('plugin-meetings', () => {
|
|
9
|
+
let fakeMeeting, fakeVoiceaPayload;
|
|
10
|
+
const fakeMemberId = "4f35a5ab-f750-3ba7-b309-dea62a512257";
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
const fakeMemberList = {
|
|
13
|
+
[fakeMemberId]: {
|
|
14
|
+
participant: {
|
|
15
|
+
person: {
|
|
16
|
+
id: "8093d335-9b96-4f9d-a6b2-7293423be88a",
|
|
17
|
+
name: "John Doe",
|
|
18
|
+
isExternal: false,
|
|
19
|
+
orgId: "1eb65fdf-9643-417f-9974-ad72cae0e10f",
|
|
20
|
+
incomingCallProtocols: []
|
|
21
|
+
},
|
|
22
|
+
status: {
|
|
23
|
+
audioStatus: "SENDRECV",
|
|
24
|
+
videoStatus: "INACTIVE",
|
|
25
|
+
videoSlidesStatus: "RECVONLY",
|
|
26
|
+
audioSlidesStatus: "INACTIVE",
|
|
27
|
+
csis: [
|
|
28
|
+
3060099329,
|
|
29
|
+
3060099328,
|
|
30
|
+
1234867712,
|
|
31
|
+
1234867713
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
id: fakeMemberId
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const fakeCaptions = {
|
|
40
|
+
captions: [
|
|
41
|
+
{
|
|
42
|
+
id: "6bece1b9-4e50-fafe-fb63-d27d5fb27280",
|
|
43
|
+
isFinal: true,
|
|
44
|
+
text: "Oh it's not update.",
|
|
45
|
+
currentSpokenLanguage: "en",
|
|
46
|
+
timestamp: "1:34",
|
|
47
|
+
speaker: {
|
|
48
|
+
speakerId: "8093d335-9b96-4f9d-a6b2-7293423be88a",
|
|
49
|
+
name: "John Doe"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "c34400a9-cb2b-20c3-d20c-bd7981cc62a9",
|
|
54
|
+
isFinal: true,
|
|
55
|
+
text: "Nice.",
|
|
56
|
+
currentSpokenLanguage: "en",
|
|
57
|
+
timestamp: "1:60",
|
|
58
|
+
speaker: {
|
|
59
|
+
speakerId: "8093d335-9b96-4f9d-a6b2-7293423be88a",
|
|
60
|
+
name: "John Doe"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "311cc182-e657-c077-c078-795f866c4e9b_8093d335-9b96-4f9d-a6b2-7293423be88a",
|
|
65
|
+
isFinal: false,
|
|
66
|
+
text: " Don't bother me talking I'm just going to get the transcript data that is interim and I",
|
|
67
|
+
currentCaptionLanguage: "en",
|
|
68
|
+
speaker: {
|
|
69
|
+
speakerId: "8093d335-9b96-4f9d-a6b2-7293423be88a",
|
|
70
|
+
name: "John Doe"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
interimCaptions: {
|
|
75
|
+
"6bece1b9-4e50-fafe-fb63-d27d5fb27280": [],
|
|
76
|
+
"c34400a9-cb2b-20c3-d20c-bd7981cc62a9": [],
|
|
77
|
+
"311cc182-e657-c077-c078-795f866c4e9b": [
|
|
78
|
+
"311cc182-e657-c077-c078-795f866c4e9b_8093d335-9b96-4f9d-a6b2-7293423be88a"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
speakerProxy: {},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
fakeMeeting = {
|
|
85
|
+
members: {
|
|
86
|
+
membersCollection: {
|
|
87
|
+
members: fakeMemberList
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
transcription: fakeCaptions
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fakeVoiceaPayload = {
|
|
94
|
+
isFinal: true,
|
|
95
|
+
transcriptId: "311cc182-e657-c077-c078-795f866c4e9b",
|
|
96
|
+
transcripts: [
|
|
97
|
+
{
|
|
98
|
+
text: "Don't bother me talking I'm just going to get the transcript data that is interim and I needed if I keep talking, I get the interim data",
|
|
99
|
+
csis: [
|
|
100
|
+
1234867712
|
|
101
|
+
],
|
|
102
|
+
transcript_language_code: "en"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
transcript: {
|
|
106
|
+
text: "Don't bother me talking I'm just going to get the transcript data that is interim and I needed if I keep talking, I get the interim data",
|
|
107
|
+
csis: [
|
|
108
|
+
1234867712
|
|
109
|
+
],
|
|
110
|
+
transcript_language_code: "en"
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('voicea-meeting', () => {
|
|
116
|
+
it('should export the correct members', () => {
|
|
117
|
+
assert.isFunction(getSpeakerFromProxyOrStore);
|
|
118
|
+
assert.isFunction(processNewCaptions);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('getSpeakerFromProxyOrStore', () => {
|
|
122
|
+
it('should return a cached speaker if csisKey is in speakerProxy', () => {
|
|
123
|
+
// Add a speaker to the speakerProxy
|
|
124
|
+
const csisKey = 1234867712;
|
|
125
|
+
const cachedSpeaker = {
|
|
126
|
+
speakerId: 'cached-speaker-id',
|
|
127
|
+
name: 'Cached Speaker'
|
|
128
|
+
};
|
|
129
|
+
fakeMeeting.transcription.speakerProxy[csisKey] = cachedSpeaker;
|
|
130
|
+
|
|
131
|
+
const { speaker, needsCaching } = getSpeakerFromProxyOrStore({
|
|
132
|
+
csisKey,
|
|
133
|
+
meetingMembers: fakeMeeting.members.membersCollection.members,
|
|
134
|
+
transcriptData: fakeMeeting.transcription
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(speaker).to.deep.equal(cachedSpeaker);
|
|
138
|
+
expect(needsCaching).to.be.false;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should find and cache a speaker if not already in speakerProxy', () => {
|
|
142
|
+
const csisKey = 1234867712; // This csis exists in the fakeMemberList
|
|
143
|
+
|
|
144
|
+
// Ensure speakerProxy is empty
|
|
145
|
+
fakeMeeting.transcription.speakerProxy = {};
|
|
146
|
+
|
|
147
|
+
const { speaker, needsCaching } = getSpeakerFromProxyOrStore({
|
|
148
|
+
csisKey,
|
|
149
|
+
meetingMembers: fakeMeeting.members.membersCollection.members,
|
|
150
|
+
transcriptData: fakeMeeting.transcription
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(speaker.speakerId).to.equal(fakeMeeting.members.membersCollection.members[fakeMemberId].participant.person.id);
|
|
154
|
+
expect(speaker.name).to.equal(fakeMeeting.members.membersCollection.members[fakeMemberId].participant.person.name);
|
|
155
|
+
expect(needsCaching).to.be.true;
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('processNewCaptions', () => {
|
|
160
|
+
it('should process new final captions correctly', () => {
|
|
161
|
+
let transcriptData = fakeMeeting.transcription;
|
|
162
|
+
let transcriptId = fakeVoiceaPayload.transcriptId;
|
|
163
|
+
delete fakeVoiceaPayload.transcripts;
|
|
164
|
+
|
|
165
|
+
// Assuming that processNewCaptions is a pure function that doesn't mutate the input but returns a new state
|
|
166
|
+
processNewCaptions({
|
|
167
|
+
data: fakeVoiceaPayload,
|
|
168
|
+
meeting: fakeMeeting
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Check if speaker details are cached if needed
|
|
172
|
+
const csisKey = fakeVoiceaPayload.transcript.csis[0];
|
|
173
|
+
const speaker = transcriptData.speakerProxy[csisKey];
|
|
174
|
+
expect(speaker).to.exist;
|
|
175
|
+
|
|
176
|
+
// Check if interim captions are removed
|
|
177
|
+
expect(transcriptData.interimCaptions[transcriptId]).to.deep.equal([]);
|
|
178
|
+
|
|
179
|
+
//check if the interim caption is removed
|
|
180
|
+
const oldInterimCaption = transcriptData.captions.find(caption => caption.id === `${transcriptId}_${speaker.speakerId}`);
|
|
181
|
+
expect(oldInterimCaption).to.not.exist;
|
|
182
|
+
|
|
183
|
+
// Check the final caption data
|
|
184
|
+
const newCaption = transcriptData.captions.find(caption => caption.id === transcriptId);
|
|
185
|
+
expect(newCaption).to.exist;
|
|
186
|
+
expect(newCaption).to.include({
|
|
187
|
+
id: transcriptId,
|
|
188
|
+
isFinal: fakeVoiceaPayload.isFinal,
|
|
189
|
+
text: fakeVoiceaPayload.transcript.text,
|
|
190
|
+
currentSpokenLanguage: fakeVoiceaPayload.transcript.transcript_language_code,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Check the speaker data in the new caption
|
|
194
|
+
expect(newCaption.speaker).to.deep.equal(speaker);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should process new interim captions correctly', () => {
|
|
198
|
+
let transcriptData = fakeMeeting.transcription;
|
|
199
|
+
let transcriptId = fakeVoiceaPayload.transcriptId;
|
|
200
|
+
delete fakeVoiceaPayload.transcript;
|
|
201
|
+
|
|
202
|
+
transcriptData.captions.splice(transcriptData.length - 1, 1);
|
|
203
|
+
fakeVoiceaPayload.isFinal = false;
|
|
204
|
+
|
|
205
|
+
processNewCaptions({
|
|
206
|
+
data: fakeVoiceaPayload,
|
|
207
|
+
meeting: fakeMeeting
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Check if speaker details are cached if needed
|
|
211
|
+
const csisKey = fakeVoiceaPayload.transcripts[0].csis[0];
|
|
212
|
+
const speaker = transcriptData.speakerProxy[csisKey];
|
|
213
|
+
expect(speaker).to.exist;
|
|
214
|
+
|
|
215
|
+
// Check the final caption data
|
|
216
|
+
const newCaption = transcriptData.captions.find(caption => caption.id === `${transcriptId}_${speaker.speakerId}`);
|
|
217
|
+
expect(newCaption).to.exist;
|
|
218
|
+
expect(newCaption).to.include({
|
|
219
|
+
id: `${transcriptId}_${speaker.speakerId}`,
|
|
220
|
+
isFinal: fakeVoiceaPayload.isFinal,
|
|
221
|
+
text: fakeVoiceaPayload.transcripts[0].text,
|
|
222
|
+
currentCaptionLanguage: fakeVoiceaPayload.transcripts[0].transcript_language_code,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Check if interim captions has the right caption id
|
|
226
|
+
expect(transcriptData.interimCaptions[transcriptId]).to.deep.equal([newCaption.id]);
|
|
227
|
+
|
|
228
|
+
// Check the speaker data in the new caption
|
|
229
|
+
expect(newCaption.speaker).to.deep.equal(speaker);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should process interim captions with an existing one correctly', () => {
|
|
233
|
+
let transcriptData = fakeMeeting.transcription;
|
|
234
|
+
let transcriptId = fakeVoiceaPayload.transcriptId;
|
|
235
|
+
delete fakeVoiceaPayload.transcript;
|
|
236
|
+
fakeVoiceaPayload.isFinal = false;
|
|
237
|
+
|
|
238
|
+
processNewCaptions({
|
|
239
|
+
data: fakeVoiceaPayload,
|
|
240
|
+
meeting: fakeMeeting
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Check if speaker details are cached if needed
|
|
244
|
+
const csisKey = fakeVoiceaPayload.transcripts[0].csis[0];
|
|
245
|
+
const speaker = transcriptData.speakerProxy[csisKey];
|
|
246
|
+
expect(speaker).to.exist;
|
|
247
|
+
|
|
248
|
+
// Check the final caption data
|
|
249
|
+
const newCaption = transcriptData.captions.find(caption => caption.id === `${transcriptId}_${speaker.speakerId}`);
|
|
250
|
+
expect(newCaption).to.exist;
|
|
251
|
+
expect(newCaption).to.include({
|
|
252
|
+
id: `${transcriptId}_${speaker.speakerId}`,
|
|
253
|
+
isFinal: fakeVoiceaPayload.isFinal,
|
|
254
|
+
text: fakeVoiceaPayload.transcripts[0].text,
|
|
255
|
+
currentCaptionLanguage: fakeVoiceaPayload.transcripts[0].transcript_language_code,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Check if interim captions has the right caption id
|
|
259
|
+
expect(transcriptData.interimCaptions[transcriptId]).to.deep.equal([newCaption.id]);
|
|
260
|
+
|
|
261
|
+
// Check the speaker data in the new caption
|
|
262
|
+
expect(newCaption.speaker).to.deep.equal(speaker);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
@@ -795,13 +795,17 @@ describe('plugin-meetings', () => {
|
|
|
795
795
|
it('Make a request to /spaceInstant when conversationUrl', async () => {
|
|
796
796
|
const {invitee} = setup();
|
|
797
797
|
|
|
798
|
-
|
|
798
|
+
webex.request.resolves({
|
|
799
|
+
statusCode: 200,
|
|
800
|
+
body: conversation
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
const result = await meetingInfo.createAdhocSpaceMeeting(conversationUrl,installedOrgID);
|
|
799
804
|
|
|
800
805
|
assert.calledWith(
|
|
801
|
-
webex.
|
|
802
|
-
{
|
|
803
|
-
|
|
804
|
-
);
|
|
806
|
+
webex.request,
|
|
807
|
+
{uri:conversationUrl, qs: {includeParticipants: true}, disableTransform: true}
|
|
808
|
+
)
|
|
805
809
|
|
|
806
810
|
assert.calledWith(webex.request, {
|
|
807
811
|
method: 'POST',
|
|
@@ -812,27 +816,28 @@ describe('plugin-meetings', () => {
|
|
|
812
816
|
keyUrl: conversation.encryptionKeyUrl,
|
|
813
817
|
kroUrl: conversation.kmsResourceObjectUrl,
|
|
814
818
|
invitees: invitee,
|
|
819
|
+
installedOrgID: installedOrgID
|
|
815
820
|
},
|
|
816
821
|
});
|
|
817
|
-
assert(Metrics.sendBehavioralMetric
|
|
822
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
818
823
|
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
819
824
|
assert.deepEqual(result, {
|
|
820
|
-
body:
|
|
825
|
+
body: conversation,
|
|
821
826
|
statusCode: 200
|
|
822
827
|
});
|
|
823
828
|
});
|
|
824
|
-
|
|
825
829
|
it('Make a request to /spaceInstant when conversationUrl with installed org ID', async () => {
|
|
826
830
|
const {invitee} = setup();
|
|
827
|
-
|
|
831
|
+
webex.request = sinon.stub().resolves({
|
|
832
|
+
body: conversation,
|
|
833
|
+
});
|
|
828
834
|
await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
|
|
829
835
|
|
|
830
|
-
assert.calledWith(
|
|
831
|
-
|
|
832
|
-
{
|
|
833
|
-
|
|
834
|
-
);
|
|
835
|
-
|
|
836
|
+
assert.calledWith(webex.request, {
|
|
837
|
+
uri: conversationUrl,
|
|
838
|
+
qs: {includeParticipants: true},
|
|
839
|
+
disableTransform: true,
|
|
840
|
+
});
|
|
836
841
|
assert.calledWith(webex.request, {
|
|
837
842
|
method: 'POST',
|
|
838
843
|
uri: 'https://go.webex.com/wbxappapi/v2/meetings/spaceInstant',
|
|
@@ -595,6 +595,7 @@ describe('plugin-meetings', () => {
|
|
|
595
595
|
});
|
|
596
596
|
describe('when destroying meeting is needed', () => {
|
|
597
597
|
let destroySpy;
|
|
598
|
+
let cleanUpSpy;
|
|
598
599
|
|
|
599
600
|
const meetingCollectionMeetings = {
|
|
600
601
|
stillValidLocusMeeting: {
|
|
@@ -625,7 +626,11 @@ describe('plugin-meetings', () => {
|
|
|
625
626
|
loci: [{url: 'still-valid-locus-url'}],
|
|
626
627
|
})
|
|
627
628
|
);
|
|
628
|
-
|
|
629
|
+
cleanUpSpy = sinon.stub(MeetingUtil, 'cleanUp').returns(Promise.resolve());
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
afterEach(() => {
|
|
633
|
+
cleanUpSpy.restore();
|
|
629
634
|
});
|
|
630
635
|
|
|
631
636
|
it('destroy any meeting that has no active locus url if keepOnlyLocusMeetings is not defined', async () => {
|
|
@@ -1205,7 +1210,8 @@ describe('plugin-meetings', () => {
|
|
|
1205
1210
|
webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(
|
|
1206
1211
|
Promise.resolve({
|
|
1207
1212
|
body: {
|
|
1208
|
-
permissionToken:
|
|
1213
|
+
permissionToken:
|
|
1214
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1209
1215
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1210
1216
|
},
|
|
1211
1217
|
})
|
|
@@ -1308,7 +1314,8 @@ describe('plugin-meetings', () => {
|
|
|
1308
1314
|
const meeting = await webex.meetings.createMeeting('test destination', 'test type');
|
|
1309
1315
|
|
|
1310
1316
|
const expectedMeetingData = {
|
|
1311
|
-
permissionToken:
|
|
1317
|
+
permissionToken:
|
|
1318
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1312
1319
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1313
1320
|
correlationId: meeting.id,
|
|
1314
1321
|
};
|
|
@@ -1324,7 +1331,8 @@ describe('plugin-meetings', () => {
|
|
|
1324
1331
|
|
|
1325
1332
|
it('accepts injected meeting info', async () => {
|
|
1326
1333
|
const meetingInfo = {
|
|
1327
|
-
permissionToken:
|
|
1334
|
+
permissionToken:
|
|
1335
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1328
1336
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1329
1337
|
};
|
|
1330
1338
|
|
|
@@ -1356,7 +1364,8 @@ describe('plugin-meetings', () => {
|
|
|
1356
1364
|
|
|
1357
1365
|
it('accepts injected meeting info with meeting lookup url', async () => {
|
|
1358
1366
|
const meetingInfo = {
|
|
1359
|
-
permissionToken:
|
|
1367
|
+
permissionToken:
|
|
1368
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1360
1369
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1361
1370
|
};
|
|
1362
1371
|
|
|
@@ -1401,7 +1410,8 @@ describe('plugin-meetings', () => {
|
|
|
1401
1410
|
infoExtraParams
|
|
1402
1411
|
);
|
|
1403
1412
|
const expectedMeetingData = {
|
|
1404
|
-
permissionToken:
|
|
1413
|
+
permissionToken:
|
|
1414
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1405
1415
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1406
1416
|
};
|
|
1407
1417
|
|
|
@@ -1502,8 +1512,10 @@ describe('plugin-meetings', () => {
|
|
|
1502
1512
|
assert.equal(meeting.meetingNumber, 'locusMeetingId');
|
|
1503
1513
|
assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
|
|
1504
1514
|
assert.equal(meeting.owner, 'locusOwner');
|
|
1505
|
-
assert.equal(
|
|
1506
|
-
|
|
1515
|
+
assert.equal(
|
|
1516
|
+
meeting.permissionToken,
|
|
1517
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0'
|
|
1518
|
+
);
|
|
1507
1519
|
assert.calledWith(
|
|
1508
1520
|
TriggerProxy.trigger,
|
|
1509
1521
|
meeting,
|
|
@@ -1802,9 +1814,13 @@ describe('plugin-meetings', () => {
|
|
|
1802
1814
|
});
|
|
1803
1815
|
});
|
|
1804
1816
|
describe('Public Event Triggers', () => {
|
|
1817
|
+
let cleanUpSpy;
|
|
1805
1818
|
describe('#destroy', () => {
|
|
1806
1819
|
beforeEach(() => {
|
|
1807
|
-
|
|
1820
|
+
cleanUpSpy = sinon.stub(MeetingUtil, 'cleanUp');
|
|
1821
|
+
});
|
|
1822
|
+
afterEach(() => {
|
|
1823
|
+
cleanUpSpy.restore();
|
|
1808
1824
|
});
|
|
1809
1825
|
it('should have #destroy', () => {
|
|
1810
1826
|
assert.exists(webex.meetings.destroy);
|
|
@@ -1969,6 +1985,57 @@ describe('plugin-meetings', () => {
|
|
|
1969
1985
|
'Failed to fetch preferred site from user - no site will be set'
|
|
1970
1986
|
);
|
|
1971
1987
|
});
|
|
1988
|
+
|
|
1989
|
+
it('should fall back to fetching the site from the user', async () => {
|
|
1990
|
+
setup({
|
|
1991
|
+
user: {
|
|
1992
|
+
userPreferences: {
|
|
1993
|
+
userPreferencesItems: {
|
|
1994
|
+
preferredWebExSite: 'site.webex.com',
|
|
1995
|
+
},
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
});
|
|
1999
|
+
|
|
2000
|
+
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2001
|
+
|
|
2002
|
+
assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
|
|
2003
|
+
assert.notCalled(loggerProxySpy);
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
forEach([
|
|
2007
|
+
{user: undefined},
|
|
2008
|
+
{user: {userPreferences: {}}},
|
|
2009
|
+
{user: {userPreferences: {userPreferencesItems: {}}}},
|
|
2010
|
+
{user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
|
|
2011
|
+
], ({user}) => {
|
|
2012
|
+
it(`should handle invalid user data ${user}`, async () => {
|
|
2013
|
+
setup({user});
|
|
2014
|
+
|
|
2015
|
+
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2016
|
+
|
|
2017
|
+
assert.equal(webex.meetings.preferredWebexSite, '');
|
|
2018
|
+
assert.calledOnceWithExactly(
|
|
2019
|
+
loggerProxySpy,
|
|
2020
|
+
'Failed to fetch preferred site from user - no site will be set'
|
|
2021
|
+
);
|
|
2022
|
+
});
|
|
2023
|
+
});
|
|
2024
|
+
|
|
2025
|
+
it('should handle a get user failure', async () => {
|
|
2026
|
+
setup();
|
|
2027
|
+
|
|
2028
|
+
webex.internal.user.get.rejects(new Error());
|
|
2029
|
+
|
|
2030
|
+
await webex.meetings.fetchUserPreferredWebexSite();
|
|
2031
|
+
|
|
2032
|
+
assert.equal(webex.meetings.preferredWebexSite, '');
|
|
2033
|
+
assert.calledOnceWithExactly(
|
|
2034
|
+
loggerProxySpy,
|
|
2035
|
+
'Failed to fetch preferred site from user - no site will be set'
|
|
2036
|
+
);
|
|
2037
|
+
});
|
|
2038
|
+
|
|
1972
2039
|
});
|
|
1973
2040
|
});
|
|
1974
2041
|
|
|
@@ -1986,7 +2053,8 @@ describe('plugin-meetings', () => {
|
|
|
1986
2053
|
webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(
|
|
1987
2054
|
Promise.resolve({
|
|
1988
2055
|
body: {
|
|
1989
|
-
permissionToken:
|
|
2056
|
+
permissionToken:
|
|
2057
|
+
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0',
|
|
1990
2058
|
meetingJoinUrl: 'meetingJoinUrl',
|
|
1991
2059
|
},
|
|
1992
2060
|
})
|