@webex/plugin-meetings 3.0.0-beta.160 → 3.0.0-beta.161

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.
Files changed (54) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +12 -2
  4. package/dist/constants.js.map +1 -1
  5. package/dist/interpretation/collection.js +23 -0
  6. package/dist/interpretation/collection.js.map +1 -0
  7. package/dist/interpretation/index.js +214 -0
  8. package/dist/interpretation/index.js.map +1 -0
  9. package/dist/interpretation/siLanguage.js +25 -0
  10. package/dist/interpretation/siLanguage.js.map +1 -0
  11. package/dist/locus-info/controlsUtils.js +1 -0
  12. package/dist/locus-info/controlsUtils.js.map +1 -1
  13. package/dist/locus-info/index.js +19 -0
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/locus-info/selfUtils.js +20 -11
  16. package/dist/locus-info/selfUtils.js.map +1 -1
  17. package/dist/meeting/index.js +402 -354
  18. package/dist/meeting/index.js.map +1 -1
  19. package/dist/meeting/util.js +1 -0
  20. package/dist/meeting/util.js.map +1 -1
  21. package/dist/member/index.js +2 -0
  22. package/dist/member/index.js.map +1 -1
  23. package/dist/member/util.js +11 -0
  24. package/dist/member/util.js.map +1 -1
  25. package/dist/types/constants.d.ts +9 -0
  26. package/dist/types/interpretation/collection.d.ts +5 -0
  27. package/dist/types/interpretation/index.d.ts +5 -0
  28. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  29. package/dist/types/meeting/index.d.ts +8 -0
  30. package/dist/types/member/index.d.ts +1 -0
  31. package/package.json +19 -19
  32. package/src/constants.ts +10 -0
  33. package/src/interpretation/README.md +51 -0
  34. package/src/interpretation/collection.ts +19 -0
  35. package/src/interpretation/index.ts +182 -0
  36. package/src/interpretation/siLanguage.ts +18 -0
  37. package/src/locus-info/controlsUtils.ts +2 -0
  38. package/src/locus-info/index.ts +29 -0
  39. package/src/locus-info/selfUtils.ts +6 -0
  40. package/src/meeting/index.ts +62 -1
  41. package/src/meeting/util.ts +1 -0
  42. package/src/member/index.ts +2 -0
  43. package/src/member/util.ts +14 -0
  44. package/test/unit/spec/interpretation/collection.ts +15 -0
  45. package/test/unit/spec/interpretation/index.ts +329 -0
  46. package/test/unit/spec/interpretation/siLanguage.ts +26 -0
  47. package/test/unit/spec/locus-info/controlsUtils.js +20 -0
  48. package/test/unit/spec/locus-info/index.js +64 -0
  49. package/test/unit/spec/locus-info/selfConstant.js +10 -0
  50. package/test/unit/spec/locus-info/selfUtils.js +26 -0
  51. package/test/unit/spec/meeting/index.js +62 -1
  52. package/test/unit/spec/meeting/utils.js +2 -0
  53. package/test/unit/spec/member/index.js +11 -4
  54. package/test/unit/spec/member/util.js +24 -0
@@ -0,0 +1,329 @@
1
+ import {assert, expect} from '@webex/test-helper-chai';
2
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
3
+ import SimultaneousInterpretation from '@webex/plugin-meetings/src/interpretation';
4
+ import MockWebex from '@webex/test-helper-mock-webex';
5
+ import sinon from 'sinon';
6
+
7
+ describe('plugin-meetings', () => {
8
+ describe('SimultaneousInterpretation', () => {
9
+ let webex;
10
+ let interpretation;
11
+
12
+ beforeEach(() => {
13
+ // @ts-ignore
14
+ webex = new MockWebex({});
15
+ interpretation = new SimultaneousInterpretation({}, {parent: webex});
16
+ interpretation.locusUrl = 'locusUrl';
17
+ webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
18
+ webex.meetings = {};
19
+ webex.meetings.getMeetingByType = sinon.stub();
20
+ });
21
+
22
+ describe('#initialize', () => {
23
+ it('creates SimultaneousInterpretation as expected', () => {
24
+ assert.equal(interpretation.namespace, 'Meetings');
25
+ });
26
+ it('call querySupportLanguages correctly when meet the conditions', () => {
27
+ interpretation.querySupportLanguages = sinon.stub();
28
+ interpretation.set({
29
+ canManageInterpreters: true,
30
+ });
31
+ assert.called(interpretation.querySupportLanguages);
32
+ });
33
+ });
34
+
35
+ describe('#cleanUp', () => {
36
+ it('stops listening', () => {
37
+ interpretation.stopListening = sinon.stub();
38
+
39
+ interpretation.cleanUp();
40
+
41
+ assert.calledOnceWithExactly(interpretation.stopListening);
42
+ });
43
+ });
44
+
45
+ describe('#locusUrlUpdate', () => {
46
+ it('sets the locus url', () => {
47
+ interpretation.locusUrlUpdate('newUrl');
48
+
49
+ assert.equal(interpretation.locusUrl, 'newUrl');
50
+ });
51
+ });
52
+
53
+ describe('#updateCanManageInterpreters', () => {
54
+ it('update canManageInterpreters', () => {
55
+ interpretation.updateCanManageInterpreters(true);
56
+
57
+ assert.equal(interpretation.canManageInterpreters, true);
58
+
59
+ interpretation.updateCanManageInterpreters(false);
60
+
61
+ assert.equal(interpretation.canManageInterpreters, false);
62
+ });
63
+ });
64
+
65
+ describe('#updateInterpretation', () => {
66
+ const checkSILanguage = (siLanguage, expectResult) => {
67
+ return siLanguage?.languageCode === expectResult.languageCode && siLanguage?.languageName === expectResult.languageName
68
+ }
69
+ it('update interpretation correctly', () => {
70
+ interpretation.updateInterpretation({siLanguages: [{languageName: 'en', languageCode: 1}]});
71
+ checkSILanguage(interpretation.siLanguages.en, {languageName: 'en', languageCode: 1});
72
+ assert.equal(interpretation.siEnabled, true);
73
+ });
74
+
75
+ it('check siEnable as false if input param interpretation is null/undefined', () => {
76
+ interpretation.updateInterpretation(null);
77
+ assert.equal(interpretation.siEnabled, false);
78
+
79
+ interpretation.updateInterpretation(undefined);
80
+ assert.equal(interpretation.siEnabled, false);
81
+ });
82
+ });
83
+
84
+ describe('#updateSelfInterpretation', () => {
85
+ it('update self interpretation correctly', () => {
86
+ const sampleData: any = {
87
+ interpretation: {
88
+ originalLanguage: 'en',
89
+ sourceLanguage: 'en',
90
+ targetLanguage: 'zh',
91
+ isActive: true,
92
+ receiveLanguage: 'en',
93
+ order: 0,
94
+ }, selfParticipantId: '123'};
95
+ interpretation.updateSelfInterpretation(sampleData);
96
+ assert.equal(interpretation.originalLanguage, 'en');
97
+ assert.equal(interpretation.sourceLanguage, 'en');
98
+ assert.equal(interpretation.targetLanguage, 'zh');
99
+ assert.equal(interpretation.receiveLanguage, 'en');
100
+ assert.equal(interpretation.isActive, true);
101
+ assert.equal(interpretation.order, 0);
102
+
103
+ sampleData.interpretation = {
104
+ originalLanguage: 'en',
105
+ order: 0,
106
+ };
107
+ interpretation.updateSelfInterpretation(sampleData);
108
+ assert.equal(interpretation.sourceLanguage, undefined);
109
+ assert.equal(interpretation.targetLanguage, undefined);
110
+ assert.equal(interpretation.receiveLanguage, undefined);
111
+ });
112
+ });
113
+
114
+ describe('#querySupportLanguages', () => {
115
+ it('makes the request as expected', async () => {
116
+ const mockedReturnBody = {
117
+ siLanguages: [{
118
+ languageCode: 43,
119
+ languageName: 'it'
120
+ },
121
+ {
122
+ languageCode: 20,
123
+ languageName: 'en'
124
+ }]
125
+ };
126
+ webex.request.returns(
127
+ Promise.resolve({
128
+ body: mockedReturnBody,
129
+ })
130
+ );
131
+
132
+ await interpretation.querySupportLanguages();
133
+ assert.calledOnceWithExactly(webex.request, {
134
+ method: 'GET',
135
+ uri: 'locusUrl/languages/interpretation',
136
+ });
137
+ assert.deepEqual(interpretation.supportLanguages, mockedReturnBody.siLanguages);
138
+ });
139
+
140
+ it('rejects with error', async () => {
141
+ const mockError = new Error('something wrong');
142
+ webex.request.returns(Promise.reject(mockError));
143
+ LoggerProxy.logger.error = sinon.stub();
144
+
145
+ await assert.isRejected(interpretation.querySupportLanguages(), mockError, 'something wrong');
146
+
147
+ assert.calledOnceWithExactly(
148
+ LoggerProxy.logger.error,
149
+ 'Meeting:interpretation#querySupportLanguages failed',
150
+ mockError
151
+ );
152
+ });
153
+ });
154
+
155
+ describe('#getInterpreters', () => {
156
+ it('makes the request as expected', async () => {
157
+ const mockedReturnBody = {
158
+ interpreters: [{
159
+ emailAddress : 'bob@example.com',
160
+ emailHash : 'fdde32a3-97b0-4511-b0b5-2731cc9c5266',
161
+ originalLanguageId : 0,
162
+ originalLanguage : 'cn',
163
+ sourceLanguageId : 0,
164
+ sourceLanguage : 'cn',
165
+ targetLanguageId : 1,
166
+ targetLanguage : 'en',
167
+ order : 0,
168
+ isActive : true
169
+ },]
170
+ };
171
+ webex.request.returns(
172
+ Promise.resolve({
173
+ body: mockedReturnBody,
174
+ })
175
+ );
176
+
177
+ const result = await interpretation.getInterpreters();
178
+ assert.calledOnceWithExactly(webex.request, {
179
+ method: 'GET',
180
+ uri: 'locusUrl/interpretation/interpreters',
181
+ });
182
+ assert.deepEqual(result, {body: mockedReturnBody})
183
+ });
184
+
185
+ it('rejects with error', async () => {
186
+ const mockError = new Error('something wrong');
187
+ webex.request.returns(Promise.reject(mockError));
188
+ LoggerProxy.logger.error = sinon.stub();
189
+
190
+ await assert.isRejected(interpretation.getInterpreters(), mockError, 'something wrong');
191
+
192
+ assert.calledOnceWithExactly(
193
+ LoggerProxy.logger.error,
194
+ 'Meeting:interpretation#getInterpreters failed',
195
+ mockError
196
+ );
197
+ });
198
+ });
199
+
200
+ describe('#updateInterpreters', () => {
201
+ it('makes the request as expected', async () => {
202
+ const sampleData = [{
203
+ emailAddress : 'bob@example.com',
204
+ emailHash : 'fdde32a3-97b0-4511-b0b5-2731cc9c5266',
205
+ originalLanguageId : 0,
206
+ originalLanguage : 'cn',
207
+ sourceLanguageId : 0,
208
+ sourceLanguage : 'cn',
209
+ targetLanguageId : 1,
210
+ targetLanguage : 'en',
211
+ order : 0,
212
+ isActive : true
213
+ },];
214
+ webex.request.returns(Promise.resolve({}));
215
+
216
+ await interpretation.updateInterpreters(sampleData);
217
+ assert.calledOnceWithExactly(webex.request, {
218
+ method: 'PATCH',
219
+ uri: 'locusUrl/controls',
220
+ body: {
221
+ interpretation: {
222
+ interpreters: sampleData,
223
+ },
224
+ },
225
+ });
226
+ });
227
+
228
+ it('rejects with error', async () => {
229
+ const mockError = new Error('something wrong');
230
+ webex.request.returns(Promise.reject(mockError));
231
+ LoggerProxy.logger.error = sinon.stub();
232
+
233
+ await assert.isRejected(interpretation.updateInterpreters(), mockError, 'something wrong');
234
+
235
+ assert.calledOnceWithExactly(
236
+ LoggerProxy.logger.error,
237
+ 'Meeting:interpretation#updateInterpreters failed',
238
+ mockError
239
+ );
240
+ });
241
+ });
242
+
243
+ describe('#changeDirection', () => {
244
+ it('makes the request as expected', async () => {
245
+ interpretation.set({
246
+ sourceLanguage : 'cn',
247
+ targetLanguage : 'en',
248
+ isActive: true,
249
+ order: 0,
250
+ selfParticipantId: '123',
251
+ });
252
+ webex.request.returns(Promise.resolve({}));
253
+
254
+ await interpretation.changeDirection();
255
+ assert.calledOnceWithExactly(webex.request, {
256
+ method: 'PATCH',
257
+ uri: 'locusUrl/participant/123/controls',
258
+ body: {
259
+ interpretation: {
260
+ sourceLanguage : 'en',
261
+ targetLanguage : 'cn',
262
+ isActive: true,
263
+ order: 0,
264
+ },
265
+ },
266
+ });
267
+ });
268
+
269
+ it('request rejects with error', async () => {
270
+ interpretation.set({
271
+ sourceLanguage : 'cn',
272
+ targetLanguage : 'en',
273
+ isActive: true,
274
+ order: 0,
275
+ selfParticipantId: '123',
276
+ });
277
+ const mockError = new Error('something wrong');
278
+ webex.request.returns(Promise.reject(mockError));
279
+ LoggerProxy.logger.error = sinon.stub();
280
+
281
+ await assert.isRejected(interpretation.changeDirection(), mockError, 'something wrong');
282
+
283
+ assert.calledOnceWithExactly(
284
+ LoggerProxy.logger.error,
285
+ 'Meeting:interpretation#changeDirection failed',
286
+ mockError
287
+ );
288
+ });
289
+
290
+ it('rejects error when no sourceLanguage or targetLanguage', async () => {
291
+ interpretation.set({
292
+ sourceLanguage : 'cn',
293
+ isActive: true,
294
+ order: 0,
295
+ selfParticipantId: '123',
296
+ });
297
+ LoggerProxy.logger.error = sinon.stub();
298
+
299
+ await interpretation.changeDirection().catch((error) => {
300
+ assert.equal(error.toString(), 'Error: Missing sourceLanguage or targetLanguage');
301
+ });
302
+
303
+ interpretation.set({
304
+ targetLanguage : 'en',
305
+ isActive: true,
306
+ order: 0,
307
+ selfParticipantId: '123',
308
+ });
309
+ await interpretation.changeDirection().catch((error) => {
310
+ assert.equal(error.toString(), 'Error: Missing sourceLanguage or targetLanguage');
311
+ });
312
+ });
313
+
314
+ it('rejects error when no self participant id', async () => {
315
+ interpretation.set({
316
+ sourceLanguage : 'cn',
317
+ targetLanguage : 'en',
318
+ isActive: true,
319
+ order: 0,
320
+ });
321
+ LoggerProxy.logger.error = sinon.stub();
322
+
323
+ await interpretation.changeDirection().catch((error) => {
324
+ assert.equal(error.toString(), 'Error: Missing self participant id');
325
+ });
326
+ });
327
+ });
328
+ });
329
+ });
@@ -0,0 +1,26 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+ import SILanguage from '@webex/plugin-meetings/src/interpretation/siLanguage';
3
+ import SimultaneousInterpretation from '@webex/plugin-meetings/src/interpretation';
4
+ import MockWebex from '@webex/test-helper-mock-webex';
5
+
6
+ describe('plugin-meetings', () => {
7
+ describe('SILanguage', () => {
8
+ let webex;
9
+ let siLanguage;
10
+ let interpretation;
11
+ beforeEach(() => {
12
+ // @ts-ignore
13
+ webex = new MockWebex({});
14
+ interpretation = new SimultaneousInterpretation({}, {parent: webex});
15
+ siLanguage = new SILanguage({}, {parent: interpretation});
16
+ });
17
+ it('set siLanguage props correctly', () => {
18
+ siLanguage.set({
19
+ languageCode: 20,
20
+ languageName: 'en',
21
+ });
22
+ assert.equal(siLanguage.languageCode, 20);
23
+ assert.equal(siLanguage.languageName, 'en');
24
+ });
25
+ });
26
+ });
@@ -249,6 +249,26 @@ describe('plugin-meetings', () => {
249
249
  assert.equal(updates.hasBreakoutChanged, false);
250
250
  });
251
251
 
252
+ it('returns hasInterpretationChanged = true when it has changed', () => {
253
+ const newControls = {
254
+ interpretation: 'interpretation',
255
+ };
256
+
257
+ const {updates} = ControlsUtils.getControls({interpretation: 'old one'}, newControls);
258
+
259
+ assert.equal(updates.hasInterpretationChanged, true);
260
+ });
261
+
262
+ it('returns hasInterpretationChanged = false when it has not changed', () => {
263
+ const newControls = {
264
+ interpretation: 'interpretation',
265
+ };
266
+
267
+ const {updates} = ControlsUtils.getControls({interpretation: 'interpretation'}, newControls);
268
+
269
+ assert.equal(updates.hasInterpretationChanged, false);
270
+ });
271
+
252
272
  describe('videoEnabled', () => {
253
273
  const testVideoEnabled = (oldControls, newControls, updatedProperty) => {
254
274
  const result = ControlsUtils.getControls(oldControls, newControls);
@@ -397,6 +397,26 @@ describe('plugin-meetings', () => {
397
397
  tmpStub.restore();
398
398
  });
399
399
 
400
+ it('should update the interpretation state', () => {
401
+ locusInfo.emitScoped = sinon.stub();
402
+ newControls.interpretation = {siLanguages: [{languageCode: 20, languageName: 'en'}]};
403
+ let selfInfo = {};
404
+
405
+ locusInfo.updateControls(newControls, selfInfo);
406
+
407
+ assert.calledWith(
408
+ locusInfo.emitScoped,
409
+ {
410
+ file: 'locus-info',
411
+ function: 'updateControls',
412
+ },
413
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_INTERPRETATION_UPDATED,
414
+ {
415
+ interpretation: newControls.interpretation,
416
+ }
417
+ );
418
+ });
419
+
400
420
  it('should update the transcript state', () => {
401
421
  locusInfo.emitScoped = sinon.stub();
402
422
  locusInfo.controls = {
@@ -1235,6 +1255,50 @@ describe('plugin-meetings', () => {
1235
1255
  {oldRoles: ['PRESENTER'], newRoles: ['PRESENTER']}
1236
1256
  );
1237
1257
  });
1258
+
1259
+ it('should trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info changed', () => {
1260
+ locusInfo.self = self;
1261
+ locusInfo.emitScoped = sinon.stub();
1262
+ const sampleNewSelf = cloneDeep(self);
1263
+ sampleNewSelf.controls.interpretation.targetLanguage = 'it';
1264
+
1265
+ locusInfo.updateSelf(sampleNewSelf, []);
1266
+
1267
+ assert.calledWith(
1268
+ locusInfo.emitScoped,
1269
+ {
1270
+ file: 'locus-info',
1271
+ function: 'updateSelf',
1272
+ },
1273
+ LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED,
1274
+ {
1275
+ interpretation: sampleNewSelf.controls.interpretation,
1276
+ selfParticipantId: self.id,
1277
+ }
1278
+ );
1279
+ });
1280
+
1281
+ it('should not trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info not changed', () => {
1282
+ locusInfo.self = self;
1283
+ locusInfo.emitScoped = sinon.stub();
1284
+ const sampleNewSelf = cloneDeep(self);
1285
+ sampleNewSelf.controls.interpretation.targetLanguage = 'cn'; // same with previous one
1286
+
1287
+ locusInfo.updateSelf(sampleNewSelf, []);
1288
+
1289
+ assert.neverCalledWith(
1290
+ locusInfo.emitScoped,
1291
+ {
1292
+ file: 'locus-info',
1293
+ function: 'updateSelf',
1294
+ },
1295
+ LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED,
1296
+ {
1297
+ interpretation: sampleNewSelf.controls.interpretation,
1298
+ selfParticipantId: self.id,
1299
+ }
1300
+ );
1301
+ });
1238
1302
  });
1239
1303
 
1240
1304
  describe('#updateMeetingInfo', () => {
@@ -147,6 +147,16 @@ export const self = {
147
147
  readOnly: true,
148
148
  },
149
149
  },
150
+ interpretation: {
151
+ originalLanguage: 'en',
152
+ sourceLanguage: 'en',
153
+ targetLanguage: 'cn',
154
+ order: 0,
155
+ isActive: true,
156
+ meta: {
157
+ lastModified: '2023-07-11T01:57:31.040Z',
158
+ }
159
+ },
150
160
  localRecord: {
151
161
  recording: false,
152
162
  },
@@ -431,4 +431,30 @@ describe('plugin-meetings', () => {
431
431
  assert.deepEqual(SelfUtils.isRolesChanged(parsedSelf, clonedSelf), false);
432
432
  });
433
433
  });
434
+
435
+ describe('interpretationChanged', () => {
436
+ it('should return false if new self is null', () => {
437
+ const parsedSelf = SelfUtils.parse(self);
438
+
439
+ assert.deepEqual(SelfUtils.interpretationChanged(parsedSelf, null), false);
440
+ });
441
+
442
+ it('should return true if interpretation info has changed', () => {
443
+ const parsedSelf = SelfUtils.parse(self);
444
+ const clonedSelf = cloneDeep(parsedSelf);
445
+
446
+ clonedSelf.interpretation.sourceLanguage = 'ja';
447
+
448
+ assert.deepEqual(SelfUtils.interpretationChanged(parsedSelf, clonedSelf), true);
449
+ });
450
+
451
+ it('should return false if interpretation info has not changed', () => {
452
+ const parsedSelf = SelfUtils.parse(self);
453
+ const clonedSelf = cloneDeep(parsedSelf);
454
+
455
+ clonedSelf.interpretation.sourceLanguage = 'en';
456
+
457
+ assert.deepEqual(SelfUtils.interpretationChanged(parsedSelf, clonedSelf), false);
458
+ });
459
+ });
434
460
  });
@@ -70,6 +70,7 @@ import * as ReceiveSlotManagerModule from '@webex/plugin-meetings/src/multistrea
70
70
  import LLM from '@webex/internal-plugin-llm';
71
71
  import Mercury from '@webex/internal-plugin-mercury';
72
72
  import Breakouts from '@webex/plugin-meetings/src/breakouts';
73
+ import SimultaneousInterpretation from '@webex/plugin-meetings/src/interpretation';
73
74
  import {REACTION_RELAY_TYPES} from '../../../../src/reactions/constants';
74
75
  import locus from '../fixture/locus';
75
76
  import {
@@ -318,6 +319,7 @@ describe('plugin-meetings', () => {
318
319
  assert.equal(meeting.destination, testDestination);
319
320
  assert.equal(meeting.destinationType, _MEETING_ID_);
320
321
  assert.instanceOf(meeting.breakouts, Breakouts);
322
+ assert.instanceOf(meeting.simultaneousInterpretation, SimultaneousInterpretation);
321
323
  });
322
324
  it('creates MediaRequestManager instances', () => {
323
325
  assert.instanceOf(meeting.mediaRequestManagers.audio, MediaRequestManager);
@@ -4415,8 +4417,9 @@ describe('plugin-meetings', () => {
4415
4417
  });
4416
4418
 
4417
4419
  it('listens to the self roles changed event', () => {
4418
- const payload = {oldRoles: [], newRoles: ['COHOST']};
4420
+ const payload = {oldRoles: [], newRoles: ['COHOST', 'MODERATOR']};
4419
4421
  meeting.breakouts.updateCanManageBreakouts = sinon.stub();
4422
+ meeting.simultaneousInterpretation.updateCanManageInterpreters = sinon.stub();
4420
4423
 
4421
4424
  meeting.locusInfo.emit(
4422
4425
  {function: 'test', file: 'test'},
@@ -4425,6 +4428,7 @@ describe('plugin-meetings', () => {
4425
4428
  );
4426
4429
 
4427
4430
  assert.calledOnceWithExactly(meeting.breakouts.updateCanManageBreakouts, true);
4431
+ assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateCanManageInterpreters, true);
4428
4432
  assert.calledWith(
4429
4433
  TriggerProxy.trigger,
4430
4434
  meeting,
@@ -4433,6 +4437,26 @@ describe('plugin-meetings', () => {
4433
4437
  {payload}
4434
4438
  );
4435
4439
  });
4440
+
4441
+ it('listens to the interpretation changed event', () => {
4442
+ meeting.simultaneousInterpretation.updateSelfInterpretation = sinon.stub();
4443
+
4444
+ const payload = 'payload';
4445
+
4446
+ meeting.locusInfo.emit(
4447
+ {function: 'test', file: 'test'},
4448
+ 'SELF_MEETING_INTERPRETATION_CHANGED',
4449
+ payload
4450
+ );
4451
+
4452
+ assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateSelfInterpretation, payload);
4453
+ assert.calledWith(
4454
+ TriggerProxy.trigger,
4455
+ meeting,
4456
+ {file: 'meeting/index', function: 'setUpLocusInfoSelfListener'},
4457
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
4458
+ );
4459
+ });
4436
4460
  });
4437
4461
 
4438
4462
  describe('#setUpBreakoutsListener', () => {
@@ -4714,6 +4738,27 @@ describe('plugin-meetings', () => {
4714
4738
 
4715
4739
  assert.notCalled(meeting.locusInfo.clearMainSessionLocusCache);
4716
4740
  });
4741
+
4742
+ it('listens to the locus interpretation update event', () => {
4743
+ const interpretation = {
4744
+ siLanguages: [{languageCode: 20, languageName: 'en'}],
4745
+ };
4746
+
4747
+ meeting.simultaneousInterpretation.updateInterpretation = sinon.stub();
4748
+ meeting.locusInfo.emit(
4749
+ {function: 'test', file: 'test'},
4750
+ 'CONTROLS_MEETING_INTERPRETATION_UPDATED',
4751
+ {interpretation}
4752
+ );
4753
+
4754
+ assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateInterpretation, interpretation);
4755
+ assert.calledWith(
4756
+ TriggerProxy.trigger,
4757
+ meeting,
4758
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
4759
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
4760
+ );
4761
+ });
4717
4762
  });
4718
4763
 
4719
4764
  describe('#setUpLocusUrlListener', () => {
@@ -4726,6 +4771,7 @@ describe('plugin-meetings', () => {
4726
4771
 
4727
4772
  meeting.breakouts.locusUrlUpdate = sinon.stub();
4728
4773
  meeting.annotation.locusUrlUpdate = sinon.stub();
4774
+ meeting.simultaneousInterpretation.locusUrlUpdate = sinon.stub();
4729
4775
 
4730
4776
  meeting.locusInfo.emit(
4731
4777
  {function: 'test', file: 'test'},
@@ -4738,6 +4784,7 @@ describe('plugin-meetings', () => {
4738
4784
  assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
4739
4785
  assert.calledWith(meeting.recordingController.setLocusUrl, newLocusUrl);
4740
4786
  assert.calledWith(meeting.controlsOptionsManager.setLocusUrl, newLocusUrl);
4787
+ assert.calledWith(meeting.simultaneousInterpretation.locusUrlUpdate, newLocusUrl);
4741
4788
  assert.equal(meeting.locusUrl, newLocusUrl);
4742
4789
  assert(meeting.locusId, '12345');
4743
4790
  done();
@@ -4869,6 +4916,20 @@ describe('plugin-meetings', () => {
4869
4916
  done();
4870
4917
  });
4871
4918
  });
4919
+
4920
+ describe('#setUpInterpretationListener', () => {
4921
+ it('listens to the support languages update event from interpretation and triggers the update event', () => {
4922
+ TriggerProxy.trigger.reset();
4923
+ meeting.simultaneousInterpretation.trigger('SUPPORT_LANGUAGES_UPDATE');
4924
+
4925
+ assert.calledWith(
4926
+ TriggerProxy.trigger,
4927
+ meeting,
4928
+ {file: 'meeting/index', function: 'setUpInterpretationListener'},
4929
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_SUPPORT_LANGUAGES_UPDATE
4930
+ );
4931
+ });
4932
+ });
4872
4933
  });
4873
4934
  describe('Private Detailed API and Helpers', () => {
4874
4935
  let sandbox;
@@ -37,6 +37,7 @@ describe('plugin-meetings', () => {
37
37
  meeting.updateLLMConnection = sinon.stub();
38
38
  meeting.breakouts = {cleanUp: sinon.stub()};
39
39
  meeting.annotaion = {cleanUp: sinon.stub()};
40
+ meeting.simultaneousInterpretation = {cleanUp: sinon.stub()};
40
41
  });
41
42
 
42
43
  afterEach(() => {
@@ -56,6 +57,7 @@ describe('plugin-meetings', () => {
56
57
  assert.calledOnce(meeting.stopKeepAlive);
57
58
  assert.calledOnce(meeting.updateLLMConnection);
58
59
  assert.calledOnce(meeting.breakouts.cleanUp);
60
+ assert.calledOnce(meeting.simultaneousInterpretation.cleanUp);
59
61
  });
60
62
  });
61
63
 
@@ -9,6 +9,13 @@ describe('member', () => {
9
9
  sinon.restore();
10
10
  });
11
11
 
12
+ it('checks member properties', () => {
13
+ const member = new Member({});
14
+ assert.exists(member.supportsInterpretation);
15
+ assert.exists(member.supportsBreakouts);
16
+ assert.exists(member.supportLiveAnnotation);
17
+ });
18
+
12
19
  it('checks that processParticipant calls isHandRaised', () => {
13
20
  const participant = {controls: {}};
14
21
 
@@ -25,10 +32,10 @@ describe('member', () => {
25
32
  const participant = {};
26
33
 
27
34
  const member = new Member({});
28
-
35
+
29
36
  sinon.spy(member, 'processRoles');
30
37
  member.processParticipant(participant);
31
-
38
+
32
39
  assert.calledOnceWithExactly(member.processRoles, participant);
33
40
  });
34
41
 
@@ -36,10 +43,10 @@ describe('member', () => {
36
43
  const participant = {};
37
44
 
38
45
  const member = new Member({});
39
-
46
+
40
47
  sinon.spy(MemberUtil, 'extractControlRoles');
41
48
  member.processParticipant(participant);
42
-
49
+
43
50
  assert.calledOnceWithExactly(MemberUtil.extractControlRoles, participant);
44
51
  });
45
52
  })