@webex/plugin-meetings 3.12.0-next.82 → 3.12.0-next.84

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.
@@ -699,3 +699,68 @@ describe('extractMediaStatus', () => {
699
699
  assert.deepEqual(mediaStatus, {audio: 'RECVONLY', video: 'SENDRECV'});
700
700
  });
701
701
  });
702
+
703
+ describe('MemberUtil.extractCsis', () => {
704
+ it('returns an empty array when participant is undefined', () => {
705
+ assert.deepEqual(MemberUtil.extractCsis(undefined), []);
706
+ });
707
+
708
+ it('returns an empty array when participant has no devices', () => {
709
+ assert.deepEqual(MemberUtil.extractCsis({}), []);
710
+ });
711
+
712
+ it('returns an empty array when devices have no csis or mediaSessions', () => {
713
+ const participant = {devices: [{}, {csis: [], mediaSessions: []}]};
714
+
715
+ assert.deepEqual(MemberUtil.extractCsis(participant), []);
716
+ });
717
+
718
+ it('collects CSIs from device.csis arrays', () => {
719
+ const participant = {
720
+ devices: [{csis: [1, 2]}, {csis: [3]}],
721
+ };
722
+
723
+ assert.deepEqual(MemberUtil.extractCsis(participant), [1, 2, 3]);
724
+ });
725
+
726
+ it('collects CSIs from device.mediaSessions[].csi values', () => {
727
+ const participant = {
728
+ devices: [
729
+ {mediaSessions: [{csi: 10}, {csi: 11}]},
730
+ {mediaSessions: [{csi: 12}]},
731
+ ],
732
+ };
733
+
734
+ assert.deepEqual(MemberUtil.extractCsis(participant), [10, 11, 12]);
735
+ });
736
+
737
+ it('merges CSIs from both csis and mediaSessions, deduplicated', () => {
738
+ const participant = {
739
+ devices: [
740
+ {csis: [1, 2], mediaSessions: [{csi: 2}, {csi: 3}]},
741
+ {csis: [3, 4], mediaSessions: [{csi: 5}]},
742
+ ],
743
+ };
744
+
745
+ assert.deepEqual(MemberUtil.extractCsis(participant), [1, 2, 3, 4, 5]);
746
+ });
747
+
748
+ it('ignores non-numeric csi values', () => {
749
+ const participant = {
750
+ devices: [
751
+ {csis: [1, '2', null, undefined]},
752
+ {mediaSessions: [{csi: 'abc'}, {csi: null}, {csi: 3}, {}]},
753
+ ],
754
+ };
755
+
756
+ assert.deepEqual(MemberUtil.extractCsis(participant), [1, 3]);
757
+ });
758
+
759
+ it('skips falsy devices and mediaSessions entries', () => {
760
+ const participant = {
761
+ devices: [null, undefined, {csis: [7], mediaSessions: [null, {csi: 8}, undefined]}],
762
+ };
763
+
764
+ assert.deepEqual(MemberUtil.extractCsis(participant), [7, 8]);
765
+ });
766
+ });
@@ -322,6 +322,28 @@ describe('plugin-meetings', () => {
322
322
  );
323
323
  sinon.restore();
324
324
  });
325
+
326
+ it('should not clear memberIdByHistoryCsi so it survives member removal (e.g. BO entry/exit)', () => {
327
+ const members = createMembers({url: url1});
328
+ members.memberIdByHistoryCsi.set(1000, 'test1');
329
+ members.clearMembers();
330
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 1);
331
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'test1');
332
+ });
333
+
334
+ it("captures the current members' CSIs into memberIdByHistoryCsi before resetting", () => {
335
+ const members = createMembers({url: url1});
336
+ members.membersCollection.setAll({
337
+ m1: {id: 'm1', participant: {devices: [{csis: [1000, 1001]}]}},
338
+ m2: {id: 'm2', participant: {devices: [{csis: [2000]}]}},
339
+ });
340
+ sinon.stub(Trigger, 'trigger');
341
+ members.clearMembers();
342
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
343
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
344
+ assert.strictEqual(members.memberIdByHistoryCsi.get(2000), 'm2');
345
+ sinon.restore();
346
+ });
325
347
  });
326
348
  describe('#locusParticipantsUpdate', () => {
327
349
  beforeEach(() => {
@@ -1165,6 +1187,139 @@ describe('plugin-meetings', () => {
1165
1187
  it('returns correct member when CSI matches the second device', () => {
1166
1188
  assert.strictEqual(members.findMemberByCsi(2001), fakeCollection.oneWithSomeCsis);
1167
1189
  });
1190
+
1191
+ it('falls back to memberIdByHistoryCsi when CSI is no longer on the current devices', () => {
1192
+ members.memberIdByHistoryCsi.set(9999, 'oneWithDevicesWithoutCsis');
1193
+ assert.strictEqual(
1194
+ members.findMemberByCsi(9999),
1195
+ fakeCollection.oneWithDevicesWithoutCsis
1196
+ );
1197
+ });
1198
+
1199
+ it('returns undefined when the memberIdByHistoryCsi entry points to a removed member', () => {
1200
+ members.memberIdByHistoryCsi.set(8888, 'not-in-collection');
1201
+ assert.strictEqual(members.findMemberByCsi(8888), undefined);
1202
+ });
1203
+
1204
+ it('prefers a current device match over a memberIdByHistoryCsi match', () => {
1205
+ members.memberIdByHistoryCsi.set(1001, 'oneWithDevicesWithoutCsis');
1206
+ assert.strictEqual(members.findMemberByCsi(1001), fakeCollection.oneWithSomeCsis);
1207
+ });
1208
+ });
1209
+
1210
+ describe('memberIdByHistoryCsi tracking', () => {
1211
+ let members;
1212
+
1213
+ const participantWithCsis = (id, csis) => ({
1214
+ id,
1215
+ type: 'USER',
1216
+ person: {},
1217
+ devices: [{csis}],
1218
+ });
1219
+
1220
+ beforeEach(() => {
1221
+ sinon.stub(Trigger, 'trigger');
1222
+ members = createMembers({url: url1});
1223
+ });
1224
+
1225
+ afterEach(() => {
1226
+ sinon.restore();
1227
+ });
1228
+
1229
+ it('does not populate the map when adding a brand new member', () => {
1230
+ members.locusParticipantsUpdate({
1231
+ participants: [participantWithCsis('m1', [1000])],
1232
+ });
1233
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1234
+ });
1235
+
1236
+ it('does not populate the map when devices have not changed between updates', () => {
1237
+ const devices = [{csis: [1000]}];
1238
+
1239
+ members.locusParticipantsUpdate({
1240
+ participants: [{id: 'm1', type: 'USER', person: {}, devices}],
1241
+ });
1242
+ members.locusParticipantsUpdate({
1243
+ participants: [{id: 'm1', type: 'USER', person: {}, devices}],
1244
+ });
1245
+
1246
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1247
+ });
1248
+
1249
+ it('captures previous CSIs into the map when devices change on update', () => {
1250
+ members.locusParticipantsUpdate({
1251
+ participants: [participantWithCsis('m1', [1000, 1001])],
1252
+ });
1253
+ members.locusParticipantsUpdate({
1254
+ participants: [participantWithCsis('m1', [2000])],
1255
+ });
1256
+
1257
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1258
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
1259
+ });
1260
+
1261
+ it('preserves history when a member is removed and re-added (breakout scenario)', () => {
1262
+ members.locusParticipantsUpdate({
1263
+ participants: [participantWithCsis('m1', [1000])],
1264
+ });
1265
+ // change devices so previous CSIs are captured into history
1266
+ members.locusParticipantsUpdate({
1267
+ participants: [participantWithCsis('m1', [2000])],
1268
+ });
1269
+ // remove the member
1270
+ members.locusParticipantsUpdate({
1271
+ participants: [],
1272
+ removedParticipantIds: ['m1'],
1273
+ });
1274
+
1275
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1276
+
1277
+ // re-add the member with brand new CSIs
1278
+ members.locusParticipantsUpdate({
1279
+ participants: [participantWithCsis('m1', [3000])],
1280
+ });
1281
+
1282
+ const member = members.findMemberByCsi(1000);
1283
+ assert.isDefined(member);
1284
+ assert.strictEqual(member.id, 'm1');
1285
+ });
1286
+
1287
+ it("captures the removed member's current CSIs even without a prior device-change update", () => {
1288
+ // member is added, then removed in the very next delta without any
1289
+ // intermediate device-change update - their current CSIs must still be
1290
+ // captured into the history map on removal
1291
+ members.locusParticipantsUpdate({
1292
+ participants: [participantWithCsis('m1', [1000, 1001])],
1293
+ });
1294
+
1295
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1296
+
1297
+ members.locusParticipantsUpdate({
1298
+ participants: [],
1299
+ removedParticipantIds: ['m1'],
1300
+ });
1301
+
1302
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1303
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
1304
+ });
1305
+
1306
+ it('merges existing history with CSIs captured at removal time', () => {
1307
+ members.locusParticipantsUpdate({
1308
+ participants: [participantWithCsis('m1', [1000])],
1309
+ });
1310
+ // device change captures 1000 into history; member now reports 2000
1311
+ members.locusParticipantsUpdate({
1312
+ participants: [participantWithCsis('m1', [2000])],
1313
+ });
1314
+ // removal should additionally capture the member's current CSIs (2000)
1315
+ members.locusParticipantsUpdate({
1316
+ participants: [],
1317
+ removedParticipantIds: ['m1'],
1318
+ });
1319
+
1320
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1321
+ assert.strictEqual(members.memberIdByHistoryCsi.get(2000), 'm1');
1322
+ });
1168
1323
  });
1169
1324
 
1170
1325
  describe('getCsisForMember()', () => {