@webex/plugin-meetings 1.159.0 → 1.159.3

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.
@@ -36,7 +36,8 @@ import {
36
36
  PASSWORD_STATUS,
37
37
  EVENTS,
38
38
  EVENT_TRIGGERS,
39
- _SIP_URI_
39
+ _SIP_URI_,
40
+ _MEETING_ID_,
40
41
  } from '@webex/plugin-meetings/src/constants';
41
42
  import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
42
43
 
@@ -126,6 +127,7 @@ describe('plugin-meetings', () => {
126
127
  let test2;
127
128
  let test3;
128
129
  let test4;
130
+ let testDestination;
129
131
 
130
132
  beforeEach(() => {
131
133
  webex = new MockWebex({
@@ -175,13 +177,16 @@ describe('plugin-meetings', () => {
175
177
  test2 = `test2-${uuid.v4()}`;
176
178
  test3 = `test3-${uuid.v4()}`;
177
179
  test4 = `test4-${uuid.v4()}`;
180
+ testDestination = `testDestination-${uuid.v4()}`;
178
181
 
179
182
  meeting = new Meeting(
180
183
  {
181
184
  userId: uuid1,
182
185
  resource: uuid2,
183
186
  deviceUrl: uuid3,
184
- locus: {url: url1}
187
+ locus: {url: url1},
188
+ destination: testDestination,
189
+ destinationType: _MEETING_ID_,
185
190
  },
186
191
  {
187
192
  parent: webex
@@ -227,6 +232,8 @@ describe('plugin-meetings', () => {
227
232
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.UNKNOWN);
228
233
  assert.equal(meeting.requiredCaptcha, null);
229
234
  assert.equal(meeting.meetingInfoFailureReason, undefined);
235
+ assert.equal(meeting.destination, testDestination);
236
+ assert.equal(meeting.destinationType, _MEETING_ID_);
230
237
  });
231
238
  });
232
239
  describe('#invite', () => {
@@ -2141,8 +2148,11 @@ describe('plugin-meetings', () => {
2141
2148
  it('calls meetingInfoProvider with all the right parameters and parses the result', async () => {
2142
2149
  meeting.attrs.meetingInfoProvider = {fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO})};
2143
2150
  meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
2151
+ meeting.destination = FAKE_DESTINATION;
2152
+ meeting.destinationType = FAKE_TYPE;
2153
+
2144
2154
  await meeting.fetchMeetingInfo({
2145
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: FAKE_PASSWORD, captchaCode: FAKE_CAPTCHA_CODE
2155
+ password: FAKE_PASSWORD, captchaCode: FAKE_CAPTCHA_CODE
2146
2156
  });
2147
2157
 
2148
2158
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, FAKE_PASSWORD, {code: FAKE_CAPTCHA_CODE, id: FAKE_CAPTCHA_ID});
@@ -2156,9 +2166,11 @@ describe('plugin-meetings', () => {
2156
2166
  it('fails if captchaCode is provided when captcha not needed', async () => {
2157
2167
  meeting.attrs.meetingInfoProvider = {fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO})};
2158
2168
  meeting.requiredCaptcha = null;
2169
+ meeting.destination = FAKE_DESTINATION;
2170
+ meeting.destinationType = FAKE_TYPE;
2159
2171
 
2160
2172
  await assert.isRejected(meeting.fetchMeetingInfo({
2161
- destination: FAKE_DESTINATION, type: FAKE_TYPE, captchaCode: FAKE_CAPTCHA_CODE
2173
+ captchaCode: FAKE_CAPTCHA_CODE
2162
2174
  }), Error, 'fetchMeetingInfo() called with captchaCode when captcha was not required');
2163
2175
 
2164
2176
  assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
@@ -2167,22 +2179,24 @@ describe('plugin-meetings', () => {
2167
2179
  it('fails if password is provided when not required', async () => {
2168
2180
  meeting.attrs.meetingInfoProvider = {fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO})};
2169
2181
  meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
2182
+ meeting.destination = FAKE_DESTINATION;
2183
+ meeting.destinationType = FAKE_TYPE;
2170
2184
 
2171
2185
  await assert.isRejected(meeting.fetchMeetingInfo({
2172
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: FAKE_PASSWORD
2186
+ password: FAKE_PASSWORD
2173
2187
  }), Error, 'fetchMeetingInfo() called with password when password was not required');
2174
2188
 
2175
2189
  assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
2176
2190
  });
2177
2191
 
2178
2192
  it('handles meetingInfoProvider requiring password', async () => {
2193
+ meeting.destination = FAKE_DESTINATION;
2194
+ meeting.destinationType = FAKE_TYPE;
2179
2195
  meeting.attrs.meetingInfoProvider = {
2180
2196
  fetchMeetingInfo: sinon.stub().throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO))
2181
2197
  };
2182
2198
 
2183
- await assert.isRejected(meeting.fetchMeetingInfo({
2184
- destination: FAKE_DESTINATION, type: FAKE_TYPE
2185
- }), PasswordError);
2199
+ await assert.isRejected(meeting.fetchMeetingInfo({}), PasswordError);
2186
2200
 
2187
2201
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, null, null);
2188
2202
 
@@ -2193,13 +2207,15 @@ describe('plugin-meetings', () => {
2193
2207
  });
2194
2208
 
2195
2209
  it('handles meetingInfoProvider requiring captcha because of wrong password', async () => {
2210
+ meeting.destination = FAKE_DESTINATION;
2211
+ meeting.destinationType = FAKE_TYPE;
2196
2212
  meeting.attrs.meetingInfoProvider = {
2197
2213
  fetchMeetingInfo: sinon.stub().throws(new MeetingInfoV2CaptchaError(423005, FAKE_SDK_CAPTCHA_INFO))
2198
2214
  };
2199
2215
  meeting.requiredCaptcha = null;
2200
2216
 
2201
2217
  await assert.isRejected(meeting.fetchMeetingInfo({
2202
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: 'aaa'
2218
+ password: 'aaa'
2203
2219
  }), CaptchaError);
2204
2220
 
2205
2221
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', null);
@@ -2216,13 +2232,15 @@ describe('plugin-meetings', () => {
2216
2232
  });
2217
2233
 
2218
2234
  it('handles meetingInfoProvider requiring captcha because of wrong captcha', async () => {
2235
+ meeting.destination = FAKE_DESTINATION;
2236
+ meeting.destinationType = FAKE_TYPE;
2219
2237
  meeting.attrs.meetingInfoProvider = {
2220
2238
  fetchMeetingInfo: sinon.stub().throws(new MeetingInfoV2CaptchaError(423005, FAKE_SDK_CAPTCHA_INFO))
2221
2239
  };
2222
2240
  meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
2223
2241
 
2224
2242
  await assert.isRejected(meeting.fetchMeetingInfo({
2225
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: 'aaa', captchaCode: 'bbb'
2243
+ password: 'aaa', captchaCode: 'bbb'
2226
2244
  }), CaptchaError);
2227
2245
 
2228
2246
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', {code: 'bbb', id: FAKE_CAPTCHA_ID});
@@ -2234,6 +2252,8 @@ describe('plugin-meetings', () => {
2234
2252
  });
2235
2253
 
2236
2254
  it('handles successful response when good password is passed', async () => {
2255
+ meeting.destination = FAKE_DESTINATION;
2256
+ meeting.destinationType = FAKE_TYPE;
2237
2257
  meeting.attrs.meetingInfoProvider = {
2238
2258
  fetchMeetingInfo: sinon.stub().resolves(
2239
2259
  {
@@ -2245,7 +2265,7 @@ describe('plugin-meetings', () => {
2245
2265
  meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
2246
2266
 
2247
2267
  await meeting.fetchMeetingInfo({
2248
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: 'aaa'
2268
+ password: 'aaa'
2249
2269
  });
2250
2270
 
2251
2271
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', null);
@@ -2257,6 +2277,8 @@ describe('plugin-meetings', () => {
2257
2277
  });
2258
2278
 
2259
2279
  it('refreshes captcha when captcha was required and we received 403 error code', async () => {
2280
+ meeting.destination = FAKE_DESTINATION;
2281
+ meeting.destinationType = FAKE_TYPE;
2260
2282
  const refreshedCaptcha = {
2261
2283
  captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
2262
2284
  verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
@@ -2273,9 +2295,11 @@ describe('plugin-meetings', () => {
2273
2295
  ));
2274
2296
  meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
2275
2297
  meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
2298
+ meeting.destination = FAKE_DESTINATION;
2299
+ meeting.destinationType = FAKE_TYPE;
2276
2300
 
2277
2301
  await assert.isRejected(meeting.fetchMeetingInfo({
2278
- destination: FAKE_DESTINATION, type: FAKE_TYPE, password: 'aaa', captchaCode: 'bbb'
2302
+ password: 'aaa', captchaCode: 'bbb'
2279
2303
  }));
2280
2304
 
2281
2305
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', {code: 'bbb', id: FAKE_CAPTCHA_ID});
@@ -2319,7 +2343,7 @@ describe('plugin-meetings', () => {
2319
2343
  };
2320
2344
 
2321
2345
  await assert.isRejected(meeting.fetchMeetingInfo({
2322
- destination: 'something@somecompany.com', type: _SIP_URI_, password: ''
2346
+ password: ''
2323
2347
  }), CaptchaError);
2324
2348
 
2325
2349
  assert.deepEqual(meeting.requiredCaptcha, FAKE_SDK_CAPTCHA_INFO);
@@ -2352,6 +2376,10 @@ describe('plugin-meetings', () => {
2352
2376
  assert.equal(result.isPasswordValid, true);
2353
2377
  assert.equal(result.requiredCaptcha, null);
2354
2378
  assert.equal(result.failureReason, MEETING_INFO_FAILURE_REASON.NONE);
2379
+ assert.calledWith(meeting.fetchMeetingInfo, {
2380
+ password: 'password',
2381
+ captchaCode: 'captcha id',
2382
+ });
2355
2383
  });
2356
2384
  it('handles PasswordError returned by fetchMeetingInfo', async () => {
2357
2385
  meeting.fetchMeetingInfo = sinon.stub().callsFake(() => {
@@ -396,7 +396,7 @@ describe('plugin-meetings', () => {
396
396
  it('tests the sync meeting calls for not existing meeting', async () => {
397
397
  await webex.meetings.syncMeetings();
398
398
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
399
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
399
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
400
400
  assert.calledOnce(initialSetup);
401
401
  assert.calledOnce(webex.meetings.create);
402
402
  assert.calledWith(webex.meetings.request.getActiveMeetings);
@@ -496,6 +496,45 @@ describe('plugin-meetings', () => {
496
496
  assert.calledOnce(webex.meetings.createMeeting);
497
497
  assert.calledWith(webex.meetings.createMeeting, test1, test2);
498
498
  });
499
+
500
+ it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
501
+ const conversationId = '3b1ce9a0-777d-11eb-ba2e-b9fd98c6d469';
502
+ const conversationUrl = `https://conv-a.wbx2.com/conversation/api/v1/conversations/${conversationId}`;
503
+ const correlationId = uuid.v4();
504
+ const scheduledMeetingFixture = {
505
+ conversationId,
506
+ conversationUrl,
507
+ correlationId,
508
+ id: correlationId,
509
+ locusInfo: {
510
+ scheduledMeeting: true,
511
+ },
512
+ };
513
+
514
+ infoOptions.destination = conversationUrl;
515
+ infoOptions.locusInfo = {
516
+ scheduledMeeting: true,
517
+ };
518
+
519
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((type) => {
520
+ if (type === 'conversationUrl') {
521
+ return infoOptions;
522
+ }
523
+
524
+ return undefined;
525
+ });
526
+
527
+ webex.meetings.meetingInfo.fetchInfoOptions = sinon.stub().resolves(
528
+ scheduledMeetingFixture
529
+ );
530
+
531
+ webex.meetings.meetingCollection.set(scheduledMeetingFixture);
532
+
533
+ await webex.meetings.create(conversationUrl, infoOptions.type);
534
+
535
+ assert.calledOnce(webex.meetings.createMeeting);
536
+ assert.calledWith(webex.meetings.createMeeting, conversationUrl, infoOptions.type);
537
+ });
499
538
  });
500
539
  });
501
540
  describe('Private Detailed API and Helpers', () => {
@@ -602,7 +641,7 @@ describe('plugin-meetings', () => {
602
641
  eventType: 'locus.difference',
603
642
  locusUrl: url1
604
643
  });
605
- assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
644
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
606
645
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
607
646
  assert.calledOnce(initialSetup);
608
647
  assert.calledWith(initialSetup, {
@@ -630,7 +669,7 @@ describe('plugin-meetings', () => {
630
669
  eventType: 'locus.difference',
631
670
  locusUrl: url1
632
671
  });
633
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
672
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
634
673
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
635
674
  assert.calledOnce(initialSetup);
636
675
  assert.calledWith(initialSetup, {
@@ -655,7 +694,7 @@ describe('plugin-meetings', () => {
655
694
  eventType: test1,
656
695
  locusUrl: url1
657
696
  });
658
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
697
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
659
698
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
660
699
  assert.calledOnce(initialSetup);
661
700
  assert.calledWith(initialSetup, {
@@ -675,7 +714,7 @@ describe('plugin-meetings', () => {
675
714
  webex.internal.device.userId = uuid1;
676
715
  webex.internal.device.url = url1;
677
716
  MeetingCollection.set = sinon.stub().returns(true);
678
- MeetingsUtil.getMeetingAddedType = sinon.stub().returns('test');
717
+ MeetingsUtil.getMeetingAddedType = sinon.stub().returns('test meeting added type');
679
718
  TriggerProxy.trigger.reset();
680
719
  });
681
720
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
@@ -687,30 +726,32 @@ describe('plugin-meetings', () => {
687
726
  }));
688
727
  });
689
728
  it('creates the meeting from a successful meeting info fetch promise testing', async () => {
690
- const meeting = await webex.meetings.createMeeting('test', 'test');
729
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
691
730
 
692
731
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
693
732
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
694
733
  assert.calledTwice(TriggerProxy.trigger);
695
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test');
696
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test');
734
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test destination', 'test type');
735
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
697
736
  assert.equal(meeting.permissionToken, 'PT');
698
737
  assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
738
+ assert.equal(meeting.destination, 'test destination');
739
+ assert.equal(meeting.destinationType, 'test type');
699
740
  });
700
741
 
701
742
  it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
702
- const meeting = await webex.meetings.createMeeting('test', 'test');
743
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
703
744
 
704
745
  assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
705
746
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
706
747
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
707
748
  assert.calledTwice(TriggerProxy.trigger);
708
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test');
709
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test');
749
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test destination', 'test type');
750
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
710
751
  assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
711
752
  file: 'meetings', function: 'createMeeting'
712
753
  }, 'meeting:added', {
713
- meeting: sinon.match.instanceOf(Meeting), type: 'test'
754
+ meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
714
755
  });
715
756
  });
716
757
  });
@@ -721,18 +762,18 @@ describe('plugin-meetings', () => {
721
762
  webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(Promise.reject(new Error('test')));
722
763
  });
723
764
  it('creates the meeting from a rejected meeting info fetch', async () => {
724
- const meeting = await webex.meetings.createMeeting('test', 'test');
765
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
725
766
 
726
767
  assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
727
768
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
728
769
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
729
770
  assert.calledTwice(TriggerProxy.trigger);
730
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test');
731
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test');
771
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, 'test destination', 'test type');
772
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
732
773
  assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
733
774
  file: 'meetings', function: 'createMeeting'
734
775
  }, 'meeting:added', {
735
- meeting: sinon.match.instanceOf(Meeting), type: 'test'
776
+ meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
736
777
  });
737
778
  });
738
779
  });
@@ -812,6 +853,20 @@ describe('plugin-meetings', () => {
812
853
 
813
854
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
814
855
  });
856
+
857
+ it('should not fail if UserPreferred info is not fetched ', async () => {
858
+ Object.assign(webex.internal, {
859
+ services: {
860
+ fetchLoginUserInformation: sinon.stub().returns(Promise.resolve({})),
861
+ },
862
+
863
+ });
864
+
865
+ await webex.meetings.fetchUserPreferredWebexSite()
866
+ .then(() => {
867
+ assert.equal(webex.meetings.preferredWebexSite, '');
868
+ });
869
+ });
815
870
  });
816
871
  });
817
872
  });