@webex/plugin-meetings 2.60.1-next.7 → 2.60.1-next.8

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/README.md +12 -0
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.d.ts +12 -2
  5. package/dist/constants.js +15 -5
  6. package/dist/constants.js.map +1 -1
  7. package/dist/interpretation/index.js +1 -1
  8. package/dist/interpretation/siLanguage.js +1 -1
  9. package/dist/locus-info/index.d.ts +1 -1
  10. package/dist/locus-info/index.js +8 -8
  11. package/dist/locus-info/index.js.map +1 -1
  12. package/dist/meeting/index.d.ts +62 -18
  13. package/dist/meeting/index.js +679 -568
  14. package/dist/meeting/index.js.map +1 -1
  15. package/dist/meeting/request.js +25 -18
  16. package/dist/meeting/request.js.map +1 -1
  17. package/dist/meeting/util.d.ts +16 -0
  18. package/dist/meeting/util.js +71 -0
  19. package/dist/meeting/util.js.map +1 -1
  20. package/dist/meetings/index.d.ts +25 -3
  21. package/dist/meetings/index.js +83 -32
  22. package/dist/meetings/index.js.map +1 -1
  23. package/dist/reachability/index.js +11 -6
  24. package/dist/reachability/index.js.map +1 -1
  25. package/dist/reconnection-manager/index.js +3 -1
  26. package/dist/reconnection-manager/index.js.map +1 -1
  27. package/dist/roap/index.js +50 -54
  28. package/dist/roap/index.js.map +1 -1
  29. package/dist/statsAnalyzer/index.js +1 -1
  30. package/dist/statsAnalyzer/index.js.map +1 -1
  31. package/dist/statsAnalyzer/mqaUtil.js +13 -10
  32. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  33. package/dist/webinar/index.js +1 -1
  34. package/package.json +22 -22
  35. package/src/constants.ts +13 -2
  36. package/src/locus-info/index.ts +13 -12
  37. package/src/meeting/index.ts +215 -116
  38. package/src/meeting/request.ts +7 -0
  39. package/src/meeting/util.ts +97 -0
  40. package/src/meetings/index.ts +59 -18
  41. package/src/reachability/index.ts +7 -4
  42. package/src/reconnection-manager/index.ts +1 -1
  43. package/src/roap/index.ts +49 -51
  44. package/src/statsAnalyzer/index.ts +2 -2
  45. package/src/statsAnalyzer/mqaUtil.ts +15 -14
  46. package/test/unit/spec/locus-info/index.js +53 -5
  47. package/test/unit/spec/meeting/index.js +1792 -1139
  48. package/test/unit/spec/meeting/request.js +22 -12
  49. package/test/unit/spec/meeting/utils.js +93 -0
  50. package/test/unit/spec/meetings/index.js +180 -21
  51. package/test/unit/spec/reachability/index.ts +2 -1
  52. package/test/unit/spec/reconnection-manager/index.js +1 -0
  53. package/test/unit/spec/roap/index.ts +28 -42
  54. package/test/unit/spec/stats-analyzer/index.js +415 -30
@@ -584,7 +584,7 @@ export default class Meetings extends WebexPlugin {
584
584
 
585
585
  // @ts-ignore
586
586
  this.webex.internal.mercury.on(ONLINE, () => {
587
- this.syncMeetings();
587
+ this.syncMeetings({keepOnlyLocusMeetings: false});
588
588
  });
589
589
 
590
590
  // @ts-ignore
@@ -699,6 +699,24 @@ export default class Meetings extends WebexPlugin {
699
699
  }
700
700
  }
701
701
 
702
+ /**
703
+ * API to toggle TCP reachability, needs to be called before webex.meetings.register()
704
+ * @param {Boolean} newValue
705
+ * @private
706
+ * @memberof Meetings
707
+ * @returns {undefined}
708
+ */
709
+ private _toggleTcpReachability(newValue: boolean) {
710
+ if (typeof newValue !== 'boolean') {
711
+ return;
712
+ }
713
+ // @ts-ignore
714
+ if (this.config.experimental.enableTcpReachability !== newValue) {
715
+ // @ts-ignore
716
+ this.config.experimental.enableTcpReachability = newValue;
717
+ }
718
+ }
719
+
702
720
  /**
703
721
  * Explicitly sets up the meetings plugin by registering
704
722
  * the device, connecting to mercury, and listening for locus events.
@@ -1026,6 +1044,9 @@ export default class Meetings extends WebexPlugin {
1026
1044
 
1027
1045
  /**
1028
1046
  * Create a meeting or return an existing meeting.
1047
+ *
1048
+ * When meeting info passed it should be complete, e.g.: fetched after password or captcha provided
1049
+ *
1029
1050
  * @param {string} destination - sipURL, phonenumber, or locus object}
1030
1051
  * @param {string} [type] - the optional specified type, such as locusId
1031
1052
  * @param {Boolean} useRandomDelayForInfo - whether a random delay should be added to fetching meeting info
@@ -1033,6 +1054,8 @@ export default class Meetings extends WebexPlugin {
1033
1054
  * @param {string} correlationId - the optional specified correlationId (callStateForMetrics.correlationId can be provided instead)
1034
1055
  * @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
1035
1056
  * @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
1057
+ * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1058
+ * @param {String} [meetingLookupUrl] - meeting info prefetch url
1036
1059
  * @returns {Promise<Meeting>} A new Meeting.
1037
1060
  * @public
1038
1061
  * @memberof Meetings
@@ -1044,7 +1067,9 @@ export default class Meetings extends WebexPlugin {
1044
1067
  infoExtraParams = {},
1045
1068
  correlationId: string = undefined,
1046
1069
  failOnMissingMeetingInfo = false,
1047
- callStateForMetrics: CallStateForMetrics = undefined
1070
+ callStateForMetrics: CallStateForMetrics = undefined,
1071
+ meetingInfo = undefined,
1072
+ meetingLookupUrl = undefined
1048
1073
  ) {
1049
1074
  // TODO: type should be from a dictionary
1050
1075
 
@@ -1103,7 +1128,9 @@ export default class Meetings extends WebexPlugin {
1103
1128
  useRandomDelayForInfo,
1104
1129
  infoExtraParams,
1105
1130
  callStateForMetrics,
1106
- failOnMissingMeetingInfo
1131
+ failOnMissingMeetingInfo,
1132
+ meetingInfo,
1133
+ meetingLookupUrl
1107
1134
  ).then((createdMeeting: any) => {
1108
1135
  // If the meeting was successfully created.
1109
1136
  if (createdMeeting && createdMeeting.on) {
@@ -1158,12 +1185,18 @@ export default class Meetings extends WebexPlugin {
1158
1185
  }
1159
1186
 
1160
1187
  /**
1188
+ * Create meeting
1189
+ *
1190
+ * When meeting info passed it should be complete, e.g.: fetched after password or captcha provided
1191
+ *
1161
1192
  * @param {String} destination see create()
1162
1193
  * @param {String} type see create()
1163
1194
  * @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
1164
1195
  * @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
1165
1196
  * @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
1166
1197
  * @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
1198
+ * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1199
+ * @param {String} [meetingLookupUrl] - meeting info prefetch url
1167
1200
  * @returns {Promise} a new meeting instance complete with meeting info and destination
1168
1201
  * @private
1169
1202
  * @memberof Meetings
@@ -1174,7 +1207,9 @@ export default class Meetings extends WebexPlugin {
1174
1207
  useRandomDelayForInfo = false,
1175
1208
  infoExtraParams = {},
1176
1209
  callStateForMetrics: CallStateForMetrics = undefined,
1177
- failOnMissingMeetingInfo = false
1210
+ failOnMissingMeetingInfo = false,
1211
+ meetingInfo = undefined,
1212
+ meetingLookupUrl = undefined
1178
1213
  ) {
1179
1214
  const meeting = new Meeting(
1180
1215
  {
@@ -1220,22 +1255,26 @@ export default class Meetings extends WebexPlugin {
1220
1255
  const isMeetingActive = !!destination.fullState?.active;
1221
1256
  // @ts-ignore
1222
1257
  const {enableUnifiedMeetings} = this.config.experimental;
1223
-
1224
- if (enableUnifiedMeetings && !isMeetingActive && useRandomDelayForInfo && waitingTime > 0) {
1258
+ const meetingInfoOptions = {
1259
+ extraParams: infoExtraParams,
1260
+ sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
1261
+ };
1262
+
1263
+ if (meetingInfo) {
1264
+ meeting.injectMeetingInfo(meetingInfo, meetingInfoOptions, meetingLookupUrl);
1265
+ } else if (
1266
+ enableUnifiedMeetings &&
1267
+ !isMeetingActive &&
1268
+ useRandomDelayForInfo &&
1269
+ waitingTime > 0
1270
+ ) {
1225
1271
  meeting.fetchMeetingInfoTimeoutId = setTimeout(
1226
- () =>
1227
- meeting.fetchMeetingInfo({
1228
- extraParams: infoExtraParams,
1229
- sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
1230
- }),
1272
+ () => meeting.fetchMeetingInfo(meetingInfoOptions),
1231
1273
  waitingTime
1232
1274
  );
1233
1275
  meeting.parseMeetingInfo(undefined, destination);
1234
1276
  } else {
1235
- await meeting.fetchMeetingInfo({
1236
- extraParams: infoExtraParams,
1237
- sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
1238
- });
1277
+ await meeting.fetchMeetingInfo(meetingInfoOptions);
1239
1278
  }
1240
1279
  } catch (err) {
1241
1280
  if (
@@ -1346,11 +1385,12 @@ export default class Meetings extends WebexPlugin {
1346
1385
 
1347
1386
  /**
1348
1387
  * syncs all the meeting from server
1349
- * @returns {undefined}
1388
+ * @param {boolean} keepOnlyLocusMeetings - whether the sync should keep only locus meetings or any other meeting in meetingCollection
1389
+ * @returns {Promise<void>}
1350
1390
  * @public
1351
1391
  * @memberof Meetings
1352
1392
  */
1353
- public syncMeetings() {
1393
+ public syncMeetings({keepOnlyLocusMeetings = true} = {}): Promise<void> {
1354
1394
  return this.request
1355
1395
  .getActiveMeetings()
1356
1396
  .then((locusArray) => {
@@ -1374,7 +1414,8 @@ export default class Meetings extends WebexPlugin {
1374
1414
  // (they had a locusUrl previously but are no longer active) in the sync
1375
1415
  for (const meeting of Object.values(meetingsCollection)) {
1376
1416
  // @ts-ignore
1377
- if (meeting.locusUrl && !activeLocusUrl.includes(meeting.locusUrl)) {
1417
+ const {locusUrl} = meeting;
1418
+ if ((keepOnlyLocusMeetings || locusUrl) && !activeLocusUrl.includes(locusUrl)) {
1378
1419
  // destroy function also uploads logs
1379
1420
  // @ts-ignore
1380
1421
  this.destroy(meeting, MEETING_REMOVED_REASON.NO_MEETINGS_TO_SYNC);
@@ -341,18 +341,21 @@ export default class Reachability {
341
341
  return Promise.resolve(results);
342
342
  }
343
343
 
344
- // @ts-ignore
345
- const includeTcpReachability = this.webex.config.meetings.experimental.enableTcpReachability;
346
-
347
344
  LoggerProxy.logger.log(
348
345
  `Reachability:index#performReachabilityChecks --> doing UDP${
349
- includeTcpReachability ? ' and TCP' : ''
346
+ // @ts-ignore
347
+ this.webex.config.meetings.experimental.enableTcpReachability ? ' and TCP' : ''
350
348
  } reachability checks`
351
349
  );
352
350
 
353
351
  const clusterReachabilityChecks = Object.keys(clusterList).map((key) => {
354
352
  const cluster = clusterList[key];
355
353
 
354
+ // Linus doesn't support TCP reachability checks on video mesh nodes
355
+ const includeTcpReachability =
356
+ // @ts-ignore
357
+ this.webex.config.meetings.experimental.enableTcpReachability && !cluster.isVideoMesh;
358
+
356
359
  if (!includeTcpReachability) {
357
360
  cluster.tcp = [];
358
361
  }
@@ -442,7 +442,7 @@ export default class ReconnectionManager {
442
442
  LoggerProxy.logger.info(
443
443
  'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'
444
444
  );
445
- await this.webex.meetings.syncMeetings();
445
+ await this.webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});
446
446
  } catch (syncError) {
447
447
  LoggerProxy.logger.info(
448
448
  'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',
package/src/roap/index.ts CHANGED
@@ -187,7 +187,7 @@ export default class Roap extends StatelessWebexPlugin {
187
187
  * @memberof Roap
188
188
  */
189
189
  sendRoapMediaRequest(options: any) {
190
- const {meeting, seq, sdp, reconnect, tieBreaker} = options;
190
+ const {meeting, seq, sdp, tieBreaker} = options;
191
191
  const roapMessage = {
192
192
  messageType: ROAP.ROAP_TYPES.OFFER,
193
193
  sdps: [sdp],
@@ -197,64 +197,62 @@ export default class Roap extends StatelessWebexPlugin {
197
197
  headers: ['includeAnswerInHttpResponse', 'noOkInTransaction'],
198
198
  };
199
199
 
200
- // When reconnecting, it's important that the first roap message being sent out has empty media id.
201
- // Normally this is the roap offer, but when TURN discovery is enabled,
202
- // then this is the TURN discovery request message
203
- return this.turnDiscovery.isSkipped(meeting).then((isTurnDiscoverySkipped) => {
204
- const sendEmptyMediaId = reconnect && isTurnDiscoverySkipped;
200
+ // The only time we want to send an empty media id is when we are reconnecting, because this way we tell Locus
201
+ // that it needs to create a new confluence, but when reconnecting we always send TURN_DISCOVERY_REQUEST first,
202
+ // so we don't need to ever send an empty media id here
203
+ const sendEmptyMediaId = false;
205
204
 
206
- return this.roapRequest
207
- .sendRoap({
208
- roapMessage,
209
- locusSelfUrl: meeting.selfUrl,
210
- mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
211
- meetingId: meeting.id,
212
- preferTranscoding: !meeting.isMultistream,
213
- locusMediaRequest: meeting.locusMediaRequest,
214
- ipVersion: MeetingUtil.getIpVersion(meeting.webex),
215
- })
216
- .then(({locus, mediaConnections}) => {
217
- if (mediaConnections) {
218
- meeting.updateMediaConnections(mediaConnections);
219
- }
205
+ return this.roapRequest
206
+ .sendRoap({
207
+ roapMessage,
208
+ locusSelfUrl: meeting.selfUrl,
209
+ mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
210
+ meetingId: meeting.id,
211
+ preferTranscoding: !meeting.isMultistream,
212
+ locusMediaRequest: meeting.locusMediaRequest,
213
+ ipVersion: MeetingUtil.getIpVersion(meeting.webex),
214
+ })
215
+ .then(({locus, mediaConnections}) => {
216
+ if (mediaConnections) {
217
+ meeting.updateMediaConnections(mediaConnections);
218
+ }
220
219
 
221
- let roapAnswer;
220
+ let roapAnswer;
222
221
 
223
- if (mediaConnections?.[0]?.remoteSdp) {
224
- const remoteSdp = JSON.parse(mediaConnections[0].remoteSdp);
222
+ if (mediaConnections?.[0]?.remoteSdp) {
223
+ const remoteSdp = JSON.parse(mediaConnections[0].remoteSdp);
225
224
 
226
- if (remoteSdp.roapMessage) {
227
- const {
228
- seq: answerSeq,
229
- messageType,
230
- sdps,
231
- errorType,
232
- errorCause,
233
- headers,
234
- } = remoteSdp.roapMessage;
225
+ if (remoteSdp.roapMessage) {
226
+ const {
227
+ seq: answerSeq,
228
+ messageType,
229
+ sdps,
230
+ errorType,
231
+ errorCause,
232
+ headers,
233
+ } = remoteSdp.roapMessage;
235
234
 
236
- roapAnswer = {
237
- seq: answerSeq,
238
- messageType,
239
- sdp: sdps[0],
240
- errorType,
241
- errorCause,
242
- headers,
243
- };
244
- }
235
+ roapAnswer = {
236
+ seq: answerSeq,
237
+ messageType,
238
+ sdp: sdps[0],
239
+ errorType,
240
+ errorCause,
241
+ headers,
242
+ };
245
243
  }
244
+ }
246
245
 
247
- if (!roapAnswer) {
248
- Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING, {
249
- correlationId: meeting.correlationId,
250
- messageType: 'ANSWER',
251
- isMultistream: meeting.isMultistream,
252
- });
253
- }
246
+ if (!roapAnswer) {
247
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING, {
248
+ correlationId: meeting.correlationId,
249
+ messageType: 'ANSWER',
250
+ isMultistream: meeting.isMultistream,
251
+ });
252
+ }
254
253
 
255
- return {locus, roapAnswer};
256
- });
257
- });
254
+ return {locus, roapAnswer};
255
+ });
258
256
  }
259
257
 
260
258
  /**
@@ -7,7 +7,7 @@ import EventsScope from '../common/events/events-scope';
7
7
  import {
8
8
  DEFAULT_GET_STATS_FILTER,
9
9
  STATS,
10
- MQA_INTEVAL,
10
+ MQA_INTERVAL,
11
11
  NETWORK_TYPE,
12
12
  MEDIA_DEVICES,
13
13
  _UNKNOWN_,
@@ -299,7 +299,7 @@ export class StatsAnalyzer extends EventsScope {
299
299
  this.sendMqaData();
300
300
  this.mqaInterval = setInterval(() => {
301
301
  this.sendMqaData();
302
- }, MQA_INTEVAL);
302
+ }, MQA_INTERVAL);
303
303
  });
304
304
  }
305
305
 
@@ -29,13 +29,14 @@ export const getAudioReceiverMqa = ({audioReceiver, statsResults, lastMqaDataSen
29
29
  // add rtpPacket info inside common as also for call analyzer
30
30
  audioReceiver.common.rtpPackets =
31
31
  statsResults[mediaType][sendrecvType].totalPacketsReceived - lastPacketsReceived || 0;
32
+ audioReceiver.streams[0].common.rtpPackets = audioReceiver.common.rtpPackets;
33
+
32
34
  // Hop by hop are numbers and not percentage so we compare on what we sent the last min
33
35
  // collect the packets received for the last min
34
- audioReceiver.streams[0].common.rtpPackets = audioReceiver.common.rtpPackets;
35
- audioReceiver.common.mediaHopByHopLost =
36
- statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
37
- audioReceiver.common.rtpHopByHopLost =
36
+ const totalPacketsLost =
38
37
  statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
38
+ audioReceiver.common.mediaHopByHopLost = totalPacketsLost;
39
+ audioReceiver.common.rtpHopByHopLost = totalPacketsLost;
39
40
 
40
41
  audioReceiver.streams[0].common.maxRtpJitter =
41
42
  // @ts-ignore
@@ -49,6 +50,7 @@ export const getAudioReceiverMqa = ({audioReceiver, statsResults, lastMqaDataSen
49
50
  statsResults[mediaType][sendrecvType].fecPacketsReceived -
50
51
  lastFecPacketsReceived -
51
52
  (statsResults[mediaType][sendrecvType].fecPacketsDiscarded - lastFecPacketsDiscarded);
53
+ audioReceiver.common.fecPackets = fecRecovered || 0;
52
54
 
53
55
  audioReceiver.streams[0].common.rtpEndToEndLost =
54
56
  statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost - fecRecovered || 0;
@@ -105,7 +107,7 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent, m
105
107
  statsResults[mediaType][sendrecvType].totalPacketsLostOnReceiver - lastPacketsLost;
106
108
 
107
109
  audioSender.common.remoteLossRate =
108
- totalpacketsLostForaMin > 0
110
+ audioSender.common.rtpPackets > 0
109
111
  ? (totalpacketsLostForaMin * 100) / audioSender.common.rtpPackets
110
112
  : 0; // This is the packets sent with in last min || 0;
111
113
 
@@ -156,16 +158,15 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
156
158
  statsResults[mediaType][sendrecvType].totalPacketsReceived - lastPacketsReceived || 0;
157
159
  videoReceiver.streams[0].common.rtpPackets = videoReceiver.common.rtpPackets;
158
160
 
159
- const totalPacketLoss =
160
- statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
161
-
162
- // Hope by hop are numbers and not percentage so we compare on what we sent the last min
161
+ // Hop by hop are numbers and not percentage so we compare on what we sent the last min
163
162
  // this is including packet lost
164
- videoReceiver.common.mediaHopByHopLost = totalPacketLoss;
165
- videoReceiver.common.rtpHopByHopLost = totalPacketLoss;
163
+ const totalPacketsLost =
164
+ statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
165
+ videoReceiver.common.mediaHopByHopLost = totalPacketsLost;
166
+ videoReceiver.common.rtpHopByHopLost = totalPacketsLost;
166
167
 
167
168
  // End to end packetloss is after recovery
168
- videoReceiver.streams[0].common.rtpEndToEndLost = totalPacketLoss;
169
+ videoReceiver.streams[0].common.rtpEndToEndLost = totalPacketsLost;
169
170
 
170
171
  // calculate this values
171
172
 
@@ -249,8 +250,8 @@ export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, m
249
250
  statsResults[mediaType][sendrecvType].totalPacketsLostOnReceiver - lastPacketsLost;
250
251
 
251
252
  videoSender.common.remoteLossRate =
252
- totalpacketsLostForaMin > 0
253
- ? (totalpacketsLostForaMin * 100) / (videoSender.common.rtpPackets + totalpacketsLostForaMin)
253
+ videoSender.common.rtpPackets > 0
254
+ ? (totalpacketsLostForaMin * 100) / videoSender.common.rtpPackets
254
255
  : 0; // This is the packets sent with in last min || 0;
255
256
 
256
257
  videoSender.common.maxRoundTripTime =
@@ -2058,7 +2058,7 @@ describe('plugin-meetings', () => {
2058
2058
  });
2059
2059
 
2060
2060
  describe('#getTheLocusToUpdate', () => {
2061
- it('return the cache locus if return to main session', () => {
2061
+ it('return the cache locus if return to main session and do not clear main session cache', () => {
2062
2062
  locusInfo.mainSessionLocusCache = {url: 'url'};
2063
2063
  locusInfo.controls = {
2064
2064
  breakout: {
@@ -2074,9 +2074,13 @@ describe('plugin-meetings', () => {
2074
2074
  };
2075
2075
 
2076
2076
  assert.deepEqual(locusInfo.getTheLocusToUpdate(newLocus), {url: 'url'});
2077
+
2078
+ locusInfo.clearMainSessionLocusCache = sinon.stub();
2079
+ locusInfo.getTheLocusToUpdate(newLocus);
2080
+ assert.notCalled(locusInfo.clearMainSessionLocusCache)
2077
2081
  });
2078
2082
 
2079
- it('return the new locus if return to main session but no cache', () => {
2083
+ it('return the new locus if return to main session but no cache and do not clear main session cache', () => {
2080
2084
  locusInfo.mainSessionLocusCache = null;
2081
2085
  locusInfo.controls = {
2082
2086
  breakout: {
@@ -2092,10 +2096,22 @@ describe('plugin-meetings', () => {
2092
2096
  };
2093
2097
 
2094
2098
  assert.deepEqual(locusInfo.getTheLocusToUpdate(newLocus), newLocus);
2099
+
2100
+ locusInfo.clearMainSessionLocusCache = sinon.stub();
2101
+ locusInfo.getTheLocusToUpdate(newLocus);
2102
+ assert.notCalled(locusInfo.clearMainSessionLocusCache)
2095
2103
  });
2096
2104
 
2097
- it('return the new locus if not return to main session', () => {
2098
- locusInfo.mainSessionLocusCache = {url: 'url'};
2105
+ it('return the new locus if not return to main session and clear main session cache', () => {
2106
+ locusInfo.mainSessionLocusCache = {
2107
+ controls: {
2108
+ breakout: {
2109
+ sessionType: 'MAIN',
2110
+ },
2111
+ },
2112
+ self: {removed: true}
2113
+ };
2114
+ locusInfo.fullState = {state: 'ACTIVE'}
2099
2115
  locusInfo.controls = {
2100
2116
  breakout: {
2101
2117
  sessionType: 'MAIN',
@@ -2109,7 +2125,39 @@ describe('plugin-meetings', () => {
2109
2125
  },
2110
2126
  };
2111
2127
 
2112
- assert.deepEqual(locusInfo.getTheLocusToUpdate(newLocus), newLocus);
2128
+ locusInfo.clearMainSessionLocusCache = sinon.stub();
2129
+ const result = locusInfo.getTheLocusToUpdate(newLocus);
2130
+ assert.calledOnce(locusInfo.clearMainSessionLocusCache)
2131
+
2132
+ assert.deepEqual(result, newLocus);
2133
+ });
2134
+
2135
+ it('do not clear main session cache when "mainSessionLocusCache?.self?.removed" is not true', () => {
2136
+ locusInfo.mainSessionLocusCache = {
2137
+ controls: {
2138
+ breakout: {
2139
+ sessionType: 'MAIN',
2140
+ },
2141
+ },
2142
+ self: {removed: undefined}
2143
+ };
2144
+ locusInfo.fullState = {state: 'ACTIVE'}
2145
+ locusInfo.controls = {
2146
+ breakout: {
2147
+ sessionType: 'MAIN',
2148
+ },
2149
+ };
2150
+ const newLocus = {
2151
+ controls: {
2152
+ breakout: {
2153
+ sessionType: 'BREAKOUT',
2154
+ },
2155
+ },
2156
+ };
2157
+
2158
+ locusInfo.clearMainSessionLocusCache = sinon.stub();
2159
+ locusInfo.getTheLocusToUpdate(newLocus);
2160
+ assert.notCalled(locusInfo.clearMainSessionLocusCache)
2113
2161
  });
2114
2162
  });
2115
2163