@webex/internal-plugin-mercury 3.0.0-beta.4 → 3.0.0-beta.400

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.
@@ -11,7 +11,7 @@ import Mercury, {
11
11
  // NotFound,
12
12
  config as mercuryConfig,
13
13
  ConnectionError,
14
- Socket
14
+ Socket,
15
15
  } from '@webex/internal-plugin-mercury';
16
16
  import sinon from 'sinon';
17
17
  import MockWebex from '@webex/test-helper-mock-webex';
@@ -24,23 +24,19 @@ import promiseTick from '../lib/promise-tick';
24
24
 
25
25
  describe('plugin-mercury', () => {
26
26
  describe('Mercury', () => {
27
- let clock,
28
- mercury,
29
- mockWebSocket,
30
- socketOpenStub,
31
- webex;
27
+ let clock, mercury, mockWebSocket, socketOpenStub, webex;
32
28
 
33
29
  const statusStartTypingMessage = JSON.stringify({
34
30
  id: uuid.v4(),
35
31
  data: {
36
32
  eventType: 'status.start_typing',
37
33
  actor: {
38
- id: 'actorId'
34
+ id: 'actorId',
39
35
  },
40
- conversationId: uuid.v4()
36
+ conversationId: uuid.v4(),
41
37
  },
42
38
  timestamp: Date.now(),
43
- trackingId: `suffix_${uuid.v4()}_${Date.now()}`
39
+ trackingId: `suffix_${uuid.v4()}_${Date.now()}`,
44
40
  });
45
41
 
46
42
  beforeEach(() => {
@@ -54,27 +50,31 @@ describe('plugin-mercury', () => {
54
50
  beforeEach(() => {
55
51
  webex = new MockWebex({
56
52
  children: {
57
- mercury: Mercury
58
- }
53
+ mercury: Mercury,
54
+ },
59
55
  });
60
56
  webex.credentials = {
61
57
  refresh: sinon.stub().returns(Promise.resolve()),
62
- getUserToken: sinon.stub().returns(Promise.resolve({
63
- toString() {
64
- return 'Bearer FAKE';
65
- }
66
- }))
58
+ getUserToken: sinon.stub().returns(
59
+ Promise.resolve({
60
+ toString() {
61
+ return 'Bearer FAKE';
62
+ },
63
+ })
64
+ ),
67
65
  };
68
66
  webex.internal.device = {
69
67
  register: sinon.stub().returns(Promise.resolve()),
70
68
  refresh: sinon.stub().returns(Promise.resolve()),
71
69
  webSocketUrl: 'ws://example.com',
72
70
  getWebSocketUrl: sinon.stub().returns(Promise.resolve('ws://example-2.com')),
73
- useServiceCatalogUrl: sinon.stub().returns(Promise.resolve('https://service-catalog-url.com'))
71
+ useServiceCatalogUrl: sinon
72
+ .stub()
73
+ .returns(Promise.resolve('https://service-catalog-url.com')),
74
74
  };
75
75
  webex.internal.services = {
76
76
  convertUrlToPriorityHostUrl: sinon.stub().returns(Promise.resolve('ws://example-2.com')),
77
- markFailedUrl: sinon.stub().returns(Promise.resolve())
77
+ markFailedUrl: sinon.stub().returns(Promise.resolve()),
78
78
  };
79
79
  webex.internal.metrics.submitClientMetrics = sinon.stub();
80
80
  webex.trackingId = 'fakeTrackingId';
@@ -132,10 +132,9 @@ describe('plugin-mercury', () => {
132
132
 
133
133
  mockWebSocket.open();
134
134
 
135
- return promise
136
- .then(() => {
137
- assert.calledOnce(webex.internal.device.register);
138
- });
135
+ return promise.then(() => {
136
+ assert.calledOnce(webex.internal.device.register);
137
+ });
139
138
  });
140
139
 
141
140
  it('connects to Mercury using default url', () => {
@@ -145,18 +144,16 @@ describe('plugin-mercury', () => {
145
144
  assert.isTrue(mercury.connecting, 'Mercury is connecting');
146
145
  mockWebSocket.open();
147
146
 
148
- return promise
149
- .then(() => {
150
- assert.isTrue(mercury.connected, 'Mercury is connected');
151
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
152
- assert.calledWith(socketOpenStub, sinon.match(/ws:\/\/example.com/), sinon.match.any);
153
- });
147
+ return promise.then(() => {
148
+ assert.isTrue(mercury.connected, 'Mercury is connected');
149
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
150
+ assert.calledWith(socketOpenStub, sinon.match(/ws:\/\/example.com/), sinon.match.any);
151
+ });
154
152
  });
155
153
 
156
154
  describe('when `maxRetries` is set', () => {
157
- // skipping due to apparent bug with lolex in all browsers but Chrome.
158
- skipInBrowser(it)('fails after `maxRetries` attempts', () => {
159
- mercury.config.maxRetries = 2;
155
+
156
+ const check = () => {
160
157
  socketOpenStub.restore();
161
158
  socketOpenStub = sinon.stub(Socket.prototype, 'open');
162
159
  socketOpenStub.returns(Promise.reject(new ConnectionError()));
@@ -184,12 +181,42 @@ describe('plugin-mercury', () => {
184
181
  .then(() => {
185
182
  assert.calledThrice(Socket.prototype.open);
186
183
  clock.tick(5 * mercury.config.backoffTimeReset);
187
-
188
184
  return assert.isRejected(promise);
189
185
  })
190
186
  .then(() => {
191
187
  assert.calledThrice(Socket.prototype.open);
192
188
  });
189
+ }
190
+
191
+ // skipping due to apparent bug with lolex in all browsers but Chrome.
192
+ // if initial retries is zero and mercury has never connected max retries is used
193
+ skipInBrowser(it)('fails after `maxRetries` attempts', () => {
194
+ mercury.config.maxRetries = 2;
195
+ mercury.config.initialConnectionMaxRetries = 0;
196
+
197
+ return check();
198
+ });
199
+
200
+ // initial retries is non-zero so takes precedence over maxRetries when mercury has never connected
201
+ skipInBrowser(it)('fails after `initialConnectionMaxRetries` attempts', () => {
202
+ mercury.config.maxRetries = 0;
203
+ mercury.config.initialConnectionMaxRetries = 2;
204
+ return check();
205
+ });
206
+
207
+ // initial retries is non-zero so takes precedence over maxRetries when mercury has never connected
208
+ skipInBrowser(it)('fails after `initialConnectionMaxRetries` attempts', () => {
209
+ mercury.config.initialConnectionMaxRetries = 2;
210
+ mercury.config.maxRetries = 5;
211
+ return check();
212
+ });
213
+
214
+ // when mercury has connected maxRetries is used and the initialConnectionMaxRetries is ignored
215
+ skipInBrowser(it)('fails after `initialConnectionMaxRetries` attempts', () => {
216
+ mercury.config.initialConnectionMaxRetries = 5;
217
+ mercury.config.maxRetries = 2;
218
+ mercury.hasEverConnected = true;
219
+ return check();
193
220
  });
194
221
  });
195
222
 
@@ -198,15 +225,14 @@ describe('plugin-mercury', () => {
198
225
  mercury.connect(),
199
226
  mercury.connect(),
200
227
  mercury.connect(),
201
- mercury.connect()
228
+ mercury.connect(),
202
229
  ]);
203
230
 
204
231
  mockWebSocket.open();
205
232
 
206
- return promise
207
- .then(() => {
208
- assert.calledOnce(Socket.prototype.open);
209
- });
233
+ return promise.then(() => {
234
+ assert.calledOnce(Socket.prototype.open);
235
+ });
210
236
  });
211
237
 
212
238
  // skipping due to apparent bug with lolex in all browsers but Chrome.
@@ -261,7 +287,9 @@ describe('plugin-mercury', () => {
261
287
  it('fails permanently', () => {
262
288
  clock.uninstall();
263
289
  socketOpenStub.restore();
264
- socketOpenStub = sinon.stub(Socket.prototype, 'open').returns(Promise.reject(new BadRequest({code: 4400})));
290
+ socketOpenStub = sinon
291
+ .stub(Socket.prototype, 'open')
292
+ .returns(Promise.reject(new BadRequest({code: 4400})));
265
293
 
266
294
  return assert.isRejected(mercury.connect());
267
295
  });
@@ -276,18 +304,16 @@ describe('plugin-mercury', () => {
276
304
  assert.notCalled(webex.internal.device.refresh);
277
305
  const promise = mercury.connect();
278
306
 
279
- return promiseTick(7)
280
- .then(() => {
281
- assert.notCalled(webex.credentials.refresh);
282
- assert.called(webex.internal.device.refresh);
283
- clock.tick(1000);
307
+ return promiseTick(7).then(() => {
308
+ assert.notCalled(webex.credentials.refresh);
309
+ assert.called(webex.internal.device.refresh);
310
+ clock.tick(1000);
284
311
 
285
- return promise;
286
- });
312
+ return promise;
313
+ });
287
314
  });
288
315
  });
289
316
 
290
-
291
317
  describe('with `NotAuthorized`', () => {
292
318
  it('triggers a token refresh', () => {
293
319
  socketOpenStub.restore();
@@ -297,14 +323,13 @@ describe('plugin-mercury', () => {
297
323
  assert.notCalled(webex.internal.device.refresh);
298
324
  const promise = mercury.connect();
299
325
 
300
- return promiseTick(7)
301
- .then(() => {
302
- assert.called(webex.credentials.refresh);
303
- assert.notCalled(webex.internal.device.refresh);
304
- clock.tick(1000);
326
+ return promiseTick(7).then(() => {
327
+ assert.called(webex.credentials.refresh);
328
+ assert.notCalled(webex.internal.device.refresh);
329
+ clock.tick(1000);
305
330
 
306
- return promise;
307
- });
331
+ return promise;
332
+ });
308
333
  });
309
334
  });
310
335
 
@@ -312,7 +337,9 @@ describe('plugin-mercury', () => {
312
337
  it('fails permanently', () => {
313
338
  clock.uninstall();
314
339
  socketOpenStub.restore();
315
- socketOpenStub = sinon.stub(Socket.prototype, 'open').returns(Promise.reject(new Forbidden({code: 4403})));
340
+ socketOpenStub = sinon
341
+ .stub(Socket.prototype, 'open')
342
+ .returns(Promise.reject(new Forbidden({code: 4403})));
316
343
 
317
344
  return assert.isRejected(mercury.connect());
318
345
  });
@@ -344,20 +371,19 @@ describe('plugin-mercury', () => {
344
371
  socketOpenStub.onCall(0).returns(Promise.reject(new ConnectionError({code: 4001})));
345
372
  const promise = mercury.connect();
346
373
 
347
- return promiseTick(7)
348
- .then(() => {
349
- assert.calledOnce(webex.internal.services.markFailedUrl);
350
- clock.tick(1000);
374
+ return promiseTick(7).then(() => {
375
+ assert.calledOnce(webex.internal.services.markFailedUrl);
376
+ clock.tick(1000);
351
377
 
352
- return promise;
353
- });
378
+ return promise;
379
+ });
354
380
  });
355
381
  });
356
382
  });
357
383
 
358
384
  describe('when connected', () => {
359
- it('resolves immediately', () => mercury.connect()
360
- .then(() => {
385
+ it('resolves immediately', () =>
386
+ mercury.connect().then(() => {
361
387
  assert.isTrue(mercury.connected, 'Mercury is connected');
362
388
  assert.isFalse(mercury.connecting, 'Mercury is not connecting');
363
389
  const promise = mercury.connect();
@@ -393,12 +419,15 @@ describe('plugin-mercury', () => {
393
419
  assert.isTrue(mercury.connecting, 'Mercury is connecting');
394
420
  mockWebSocket.open();
395
421
 
396
- return promise
397
- .then(() => {
398
- assert.isTrue(mercury.connected, 'Mercury is connected');
399
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
400
- assert.calledWith(Socket.prototype.open, sinon.match(/ws:\/\/providedurl.com/), sinon.match.any);
401
- });
422
+ return promise.then(() => {
423
+ assert.isTrue(mercury.connected, 'Mercury is connected');
424
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
425
+ assert.calledWith(
426
+ Socket.prototype.open,
427
+ sinon.match(/ws:\/\/providedurl.com/),
428
+ sinon.match.any
429
+ );
430
+ });
402
431
  });
403
432
  });
404
433
  });
@@ -418,13 +447,18 @@ describe('plugin-mercury', () => {
418
447
  assert.isTrue(mercury.connecting, 'Mercury is connecting');
419
448
  mockWebSocket.open();
420
449
 
421
- return promise
422
- .then(() => {
423
- assert.isTrue(mercury.connected, 'Mercury is connected');
424
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
425
- assert.calledWith(socketOpenStub, sinon.match(/ws:\/\/example.com/), sinon.match.has('agent',
426
- sinon.match.has('proxy', sinon.match.has('href', testProxyUrl))));
427
- });
450
+ return promise.then(() => {
451
+ assert.isTrue(mercury.connected, 'Mercury is connected');
452
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
453
+ assert.calledWith(
454
+ socketOpenStub,
455
+ sinon.match(/ws:\/\/example.com/),
456
+ sinon.match.has(
457
+ 'agent',
458
+ sinon.match.has('proxy', sinon.match.has('href', testProxyUrl))
459
+ )
460
+ );
461
+ });
428
462
  });
429
463
 
430
464
  it('connects to Mercury without proxy agent', () => {
@@ -434,41 +468,47 @@ describe('plugin-mercury', () => {
434
468
  assert.isTrue(mercury.connecting, 'Mercury is connecting');
435
469
  mockWebSocket.open();
436
470
 
437
- return promise
438
- .then(() => {
439
- assert.isTrue(mercury.connected, 'Mercury is connected');
440
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
441
- assert.calledWith(socketOpenStub, sinon.match(/ws:\/\/example.com/), sinon.match({agent: undefined}));
442
- });
471
+ return promise.then(() => {
472
+ assert.isTrue(mercury.connected, 'Mercury is connected');
473
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
474
+ assert.calledWith(
475
+ socketOpenStub,
476
+ sinon.match(/ws:\/\/example.com/),
477
+ sinon.match({agent: undefined})
478
+ );
479
+ });
443
480
  });
444
481
  });
445
482
 
446
483
  describe('#disconnect()', () => {
447
- it('disconnects the WebSocket', () => mercury.connect()
448
- .then(() => {
449
- assert.isTrue(mercury.connected, 'Mercury is connected');
450
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
451
- const promise = mercury.disconnect();
484
+ it('disconnects the WebSocket', () =>
485
+ mercury
486
+ .connect()
487
+ .then(() => {
488
+ assert.isTrue(mercury.connected, 'Mercury is connected');
489
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
490
+ const promise = mercury.disconnect();
452
491
 
453
- mockWebSocket.emit('close', {
454
- code: 1000,
455
- reason: 'Done'
456
- });
492
+ mockWebSocket.emit('close', {
493
+ code: 1000,
494
+ reason: 'Done',
495
+ });
457
496
 
458
- return promise;
459
- })
460
- .then(() => {
461
- assert.isFalse(mercury.connected, 'Mercury is not connected');
462
- assert.isFalse(mercury.connecting, 'Mercury is not connecting');
463
- assert.isUndefined(mercury.mockWebSocket, 'Mercury does not have a mockWebSocket');
464
- }));
497
+ return promise;
498
+ })
499
+ .then(() => {
500
+ assert.isFalse(mercury.connected, 'Mercury is not connected');
501
+ assert.isFalse(mercury.connecting, 'Mercury is not connecting');
502
+ assert.isUndefined(mercury.mockWebSocket, 'Mercury does not have a mockWebSocket');
503
+ }));
465
504
 
466
505
  it('stops emitting message events', () => {
467
506
  const spy = sinon.spy();
468
507
 
469
508
  mercury.on('event:status.start_typing', spy);
470
509
 
471
- return mercury.connect()
510
+ return mercury
511
+ .connect()
472
512
  .then(() => {
473
513
  assert.isTrue(mercury.connected, 'Mercury is connected');
474
514
  assert.isFalse(mercury.connecting, 'Mercury is not connecting');
@@ -488,7 +528,7 @@ describe('plugin-mercury', () => {
488
528
  mockWebSocket.emit('message', {data: statusStartTypingMessage});
489
529
  mockWebSocket.emit('close', {
490
530
  code: 1000,
491
- reason: 'Done'
531
+ reason: 'Done',
492
532
  });
493
533
  mockWebSocket.emit('message', {data: statusStartTypingMessage});
494
534
 
@@ -511,28 +551,27 @@ describe('plugin-mercury', () => {
511
551
  // Delay the opening of the socket so that disconnect is called while open
512
552
  // is in progress
513
553
  promiseTick(2 * webex.internal.mercury.config.backoffTimeReset)
514
- // Pretend the socket opened successfully. Failing should be fine too but
515
- // it generates more console output.
554
+ // Pretend the socket opened successfully. Failing should be fine too but
555
+ // it generates more console output.
516
556
  .then(() => Promise.resolve())
517
557
  );
518
558
  const promise = mercury.connect();
519
559
 
520
560
  // Wait for the connect call to setup
521
- return promiseTick(webex.internal.mercury.config.backoffTimeReset)
522
- .then(() => {
523
- // By this time backoffCall and mercury socket should be defined by the
524
- // 'connect' call
525
- assert.isDefined(mercury.backoffCall, 'Mercury backoffCall is not defined');
526
- assert.isDefined(mercury.socket, 'Mercury socket is not defined');
527
- // Calling disconnect will abort the backoffCall, close the socket, and
528
- // reject the connect
529
- mercury.disconnect();
530
- assert.isUndefined(mercury.backoffCall, 'Mercury backoffCall is still defined');
531
- // The socket will never be unset (which seems bad)
532
- assert.isDefined(mercury.socket, 'Mercury socket is not defined');
533
-
534
- return assert.isRejected(promise);
535
- });
561
+ return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
562
+ // By this time backoffCall and mercury socket should be defined by the
563
+ // 'connect' call
564
+ assert.isDefined(mercury.backoffCall, 'Mercury backoffCall is not defined');
565
+ assert.isDefined(mercury.socket, 'Mercury socket is not defined');
566
+ // Calling disconnect will abort the backoffCall, close the socket, and
567
+ // reject the connect
568
+ mercury.disconnect();
569
+ assert.isUndefined(mercury.backoffCall, 'Mercury backoffCall is still defined');
570
+ // The socket will never be unset (which seems bad)
571
+ assert.isDefined(mercury.socket, 'Mercury socket is not defined');
572
+
573
+ return assert.isRejected(promise);
574
+ });
536
575
  });
537
576
 
538
577
  it('stops the attempt when backoffCall is undefined', () => {
@@ -547,21 +586,32 @@ describe('plugin-mercury', () => {
547
586
  reason = _reason;
548
587
  });
549
588
 
550
- return promiseTick(webex.internal.mercury.config.backoffTimeReset)
551
- .then(() => {
552
- assert.equal(reason.message, 'mercury: prevent socket open when backoffCall no longer defined');
553
- });
589
+ return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
590
+ assert.equal(
591
+ reason.message,
592
+ 'Mercury: prevent socket open when backoffCall no longer defined'
593
+ );
594
+ });
554
595
  });
555
596
  });
556
597
  });
557
598
 
558
599
  describe('#_emit()', () => {
559
- it('emits Error-safe events', () => {
600
+ it('emits Error-safe events and log the error with the call parameters', () => {
601
+ const error = 'error';
602
+ const event = {data: 'some data'};
560
603
  mercury.on('break', () => {
561
- throw new Error();
604
+ throw error;
562
605
  });
606
+ sinon.stub(mercury.logger, 'error');
563
607
 
564
- return Promise.resolve(mercury._emit('break'));
608
+ return Promise.resolve(mercury._emit('break', event)).then((res) => {
609
+ assert.calledWith(mercury.logger.error, 'Mercury: error occurred in event handler', {
610
+ error,
611
+ arguments: ['break', event],
612
+ });
613
+ return res;
614
+ });
565
615
  });
566
616
  });
567
617
 
@@ -572,11 +622,11 @@ describe('plugin-mercury', () => {
572
622
  it('merges a single header field with data', () => {
573
623
  const envelope = {
574
624
  headers: {
575
- 'data.activity.target.lastSeenActivityDate': lastSeenActivityDate
625
+ 'data.activity.target.lastSeenActivityDate': lastSeenActivityDate,
576
626
  },
577
627
  data: {
578
- activity: {}
579
- }
628
+ activity: {},
629
+ },
580
630
  };
581
631
 
582
632
  mercury._applyOverrides(envelope);
@@ -588,27 +638,30 @@ describe('plugin-mercury', () => {
588
638
  const envelope = {
589
639
  headers: {
590
640
  'data.activity.target.lastSeenActivityDate': lastSeenActivityDate,
591
- 'data.activity.target.lastReadableActivityDate': lastReadableActivityDate
641
+ 'data.activity.target.lastReadableActivityDate': lastReadableActivityDate,
592
642
  },
593
643
  data: {
594
- activity: {}
595
- }
644
+ activity: {},
645
+ },
596
646
  };
597
647
 
598
648
  mercury._applyOverrides(envelope);
599
649
 
600
650
  assert.equal(envelope.data.activity.target.lastSeenActivityDate, lastSeenActivityDate);
601
- assert.equal(envelope.data.activity.target.lastReadableActivityDate, lastReadableActivityDate);
651
+ assert.equal(
652
+ envelope.data.activity.target.lastReadableActivityDate,
653
+ lastReadableActivityDate
654
+ );
602
655
  });
603
656
 
604
657
  it('merges headers when Mercury messages arrive', () => {
605
658
  const envelope = {
606
659
  headers: {
607
- 'data.activity.target.lastSeenActivityDate': lastSeenActivityDate
660
+ 'data.activity.target.lastSeenActivityDate': lastSeenActivityDate,
608
661
  },
609
662
  data: {
610
- activity: {}
611
- }
663
+ activity: {},
664
+ },
612
665
  };
613
666
 
614
667
  mercury._applyOverrides(envelope);
@@ -622,19 +675,24 @@ describe('plugin-mercury', () => {
622
675
  webex.internal.device.webSocketUrl = 'ws://example.com';
623
676
  });
624
677
 
625
- it('uses device default webSocketUrl', () => webex.internal.mercury._prepareUrl()
626
- .then((wsUrl) => assert.match(wsUrl, /example.com/)));
627
- it('uses provided webSocketUrl', () => webex.internal.mercury._prepareUrl('ws://provided.com')
628
- .then((wsUrl) => assert.match(wsUrl, /provided.com/)));
629
- it('requests text-mode WebSockets', () => webex.internal.mercury._prepareUrl()
630
- .then((wsUrl) => assert.match(wsUrl, /outboundWireFormat=text/)));
631
-
632
- it('requests the buffer state message', () => webex.internal.mercury._prepareUrl()
633
- .then((wsUrl) => assert.match(wsUrl, /bufferStates=true/)));
634
-
635
-
636
- it('does not add conditional properties', () => webex.internal.mercury._prepareUrl()
637
- .then((wsUrl) => {
678
+ it('uses device default webSocketUrl', () =>
679
+ webex.internal.mercury._prepareUrl().then((wsUrl) => assert.match(wsUrl, /example.com/)));
680
+ it('uses provided webSocketUrl', () =>
681
+ webex.internal.mercury
682
+ ._prepareUrl('ws://provided.com')
683
+ .then((wsUrl) => assert.match(wsUrl, /provided.com/)));
684
+ it('requests text-mode WebSockets', () =>
685
+ webex.internal.mercury
686
+ ._prepareUrl()
687
+ .then((wsUrl) => assert.match(wsUrl, /outboundWireFormat=text/)));
688
+
689
+ it('requests the buffer state message', () =>
690
+ webex.internal.mercury
691
+ ._prepareUrl()
692
+ .then((wsUrl) => assert.match(wsUrl, /bufferStates=true/)));
693
+
694
+ it('does not add conditional properties', () =>
695
+ webex.internal.mercury._prepareUrl().then((wsUrl) => {
638
696
  assert.notMatch(wsUrl, /mercuryRegistrationStatus/);
639
697
  assert.notMatch(wsUrl, /mercuryRegistrationStatus/);
640
698
  assert.notMatch(wsUrl, /isRegistrationRefreshEnabled/);
@@ -643,27 +701,34 @@ describe('plugin-mercury', () => {
643
701
 
644
702
  describe('when web-high-availability is enabled', () => {
645
703
  it('uses webSocketUrl provided by device', () => {
646
- webex.internal.device.useServiceCatalogUrl = sinon.stub().returns(Promise.resolve('ws://example-2.com'));
704
+ webex.internal.device.useServiceCatalogUrl = sinon
705
+ .stub()
706
+ .returns(Promise.resolve('ws://example-2.com'));
647
707
  webex.internal.feature.getFeature.onCall(0).returns(Promise.resolve(true));
648
708
 
649
- return webex.internal.mercury._prepareUrl()
709
+ return webex.internal.mercury
710
+ ._prepareUrl()
650
711
  .then((wsUrl) => assert.match(wsUrl, /example-2.com/));
651
712
  });
652
713
  });
653
714
 
654
- describe('when \'web-shared-socket\' is enabled', () => {
715
+ describe("when 'web-shared-socket' is enabled", () => {
655
716
  beforeEach(() => {
656
717
  webex.internal.feature.getFeature.returns(Promise.resolve(true));
657
718
  });
658
719
 
659
- it('requests shared socket support', () => webex.internal.mercury._prepareUrl()
660
- .then((wsUrl) => assert.match(wsUrl, /isRegistrationRefreshEnabled=true/)));
720
+ it('requests shared socket support', () =>
721
+ webex.internal.mercury
722
+ ._prepareUrl()
723
+ .then((wsUrl) => assert.match(wsUrl, /isRegistrationRefreshEnabled=true/)));
661
724
 
662
- it('requests the registration banner', () => webex.internal.mercury._prepareUrl()
663
- .then((wsUrl) => assert.match(wsUrl, /mercuryRegistrationStatus=true/)));
725
+ it('requests the registration banner', () =>
726
+ webex.internal.mercury
727
+ ._prepareUrl()
728
+ .then((wsUrl) => assert.match(wsUrl, /mercuryRegistrationStatus=true/)));
664
729
 
665
- it('does not request the buffer state message', () => webex.internal.mercury._prepareUrl()
666
- .then((wsUrl) => {
730
+ it('does not request the buffer state message', () =>
731
+ webex.internal.mercury._prepareUrl().then((wsUrl) => {
667
732
  assert.match(wsUrl, /mercuryRegistrationStatus=true/);
668
733
  assert.notMatch(wsUrl, /bufferStates/);
669
734
  }));
@@ -674,8 +739,23 @@ describe('plugin-mercury', () => {
674
739
  webex.config.device.ephemeral = true;
675
740
  });
676
741
 
677
- it('indicates multiple connections may be coming from this user', () => webex.internal.mercury._prepareUrl()
678
- .then((wsUrl) => assert.match(wsUrl, /multipleConnections/)));
742
+ it('indicates multiple connections may be coming from this user', () =>
743
+ webex.internal.mercury
744
+ ._prepareUrl()
745
+ .then((wsUrl) => assert.match(wsUrl, /multipleConnections/)));
746
+ });
747
+ });
748
+
749
+ describe('ping pong latency event is forwarded', () => {
750
+ it('should forward ping pong latency event', () => {
751
+ const spy = sinon.spy();
752
+
753
+ mercury.on('ping-pong-latency', spy);
754
+
755
+ return mercury.connect().then(() => {
756
+ assert.calledWith(spy, 0);
757
+ assert.calledOnce(spy);
758
+ });
679
759
  });
680
760
  });
681
761
  });