@webex/internal-plugin-metrics 3.11.0 → 3.12.0

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 (40) hide show
  1. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +3 -2
  2. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics.js +1 -0
  4. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +11 -2
  6. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  7. package/dist/call-diagnostic/config.js +1 -0
  8. package/dist/call-diagnostic/config.js.map +1 -1
  9. package/dist/generic-metrics.js +8 -6
  10. package/dist/generic-metrics.js.map +1 -1
  11. package/dist/index.js +7 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/metrics.js +1 -1
  14. package/dist/metrics.types.js.map +1 -1
  15. package/dist/new-metrics.js +56 -20
  16. package/dist/new-metrics.js.map +1 -1
  17. package/dist/prelogin-metrics.js +106 -0
  18. package/dist/prelogin-metrics.js.map +1 -0
  19. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +7 -2
  20. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +5 -0
  21. package/dist/types/call-diagnostic/config.d.ts +1 -0
  22. package/dist/types/index.d.ts +2 -1
  23. package/dist/types/metrics.types.d.ts +2 -2
  24. package/dist/types/new-metrics.d.ts +12 -0
  25. package/dist/types/prelogin-metrics.d.ts +47 -0
  26. package/package.json +11 -11
  27. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +3 -5
  28. package/src/call-diagnostic/call-diagnostic-metrics.ts +1 -0
  29. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +15 -1
  30. package/src/call-diagnostic/config.ts +1 -0
  31. package/src/generic-metrics.ts +6 -6
  32. package/src/index.ts +2 -0
  33. package/src/metrics.types.ts +2 -2
  34. package/src/new-metrics.ts +42 -0
  35. package/src/prelogin-metrics.ts +94 -0
  36. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +33 -9
  37. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +120 -117
  38. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +35 -0
  39. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +34 -3
  40. package/test/unit/spec/prelogin-metrics.ts +132 -0
@@ -0,0 +1,47 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import { EventPayload } from './metrics.types';
3
+ import PreLoginMetricsBatcher from './prelogin-metrics-batcher';
4
+ /**
5
+ * @description Util class to handle PreLogin Metrics
6
+ * @export
7
+ * @class PreLoginMetrics
8
+ */
9
+ export default class PreLoginMetrics extends GenericMetrics {
10
+ private preLoginMetricsBatcher;
11
+ /**
12
+ * Constructor
13
+ * @param {PreLoginMetricsBatcher} preLoginMetricsBatcher - Pre-login metrics batcher
14
+ * @param {any} attrs - Attributes
15
+ * @param {any} options - Options
16
+ * @constructor
17
+ */
18
+ constructor(preLoginMetricsBatcher: typeof PreLoginMetricsBatcher, attrs?: any, options?: {
19
+ parent?: any;
20
+ });
21
+ /**
22
+ * Submit a business metric to our metrics endpoint.
23
+ * Routes to the correct table with the correct schema payload by table.
24
+ * @see https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
25
+ * @param {Object} options - The options object
26
+ * @param {string} options.name - Name of the metric
27
+ * @param {string} options.preLoginId - ID to identify pre-login user
28
+ * @param {EventPayload} options.payload - User payload of the metric
29
+ * @param {EventPayload} [options.metadata] - Optional metadata to include outside of eventPayload.value
30
+ * @returns {Promise<void>} Promise that resolves when the metric is submitted
31
+ */
32
+ submitPreLoginEvent({ name, preLoginId, payload, metadata, }: {
33
+ name: string;
34
+ preLoginId: string;
35
+ payload: EventPayload;
36
+ metadata?: EventPayload;
37
+ }): Promise<void>;
38
+ /**
39
+ * Builds a formatted event object for metrics submission.
40
+ * @param {string} metricName - Metric name
41
+ * @param {string} preLoginId - Pre-login user identifier
42
+ * @param {EventPayload} payload - Metric payload data
43
+ * @param {EventPayload} metadata - Additional metadata to include in the event
44
+ * @returns {object} Formatted metrics event object with type, eventPayload, and timestamp
45
+ */
46
+ private buildEvent;
47
+ }
package/package.json CHANGED
@@ -24,23 +24,23 @@
24
24
  "@sinonjs/fake-timers": "^6.0.1",
25
25
  "@webex/babel-config-legacy": "0.0.0",
26
26
  "@webex/eslint-config-legacy": "0.0.0",
27
+ "@webex/event-dictionary-ts": "^1.0.2073",
27
28
  "@webex/jest-config-legacy": "0.0.0",
28
29
  "@webex/legacy-tools": "0.0.0",
29
- "@webex/test-helper-chai": "3.11.0",
30
- "@webex/test-helper-mocha": "3.11.0",
31
- "@webex/test-helper-mock-webex": "3.11.0",
32
- "@webex/test-helper-test-users": "3.11.0",
30
+ "@webex/test-helper-chai": "3.12.0",
31
+ "@webex/test-helper-mocha": "3.12.0",
32
+ "@webex/test-helper-mock-webex": "3.12.0",
33
+ "@webex/test-helper-test-users": "3.12.0",
33
34
  "eslint": "^8.24.0",
34
35
  "prettier": "^2.7.1",
35
36
  "sinon": "^9.2.4"
36
37
  },
37
38
  "dependencies": {
38
- "@webex/common": "3.11.0",
39
- "@webex/common-timers": "3.11.0",
40
- "@webex/event-dictionary-ts": "^1.0.1930",
41
- "@webex/test-helper-chai": "3.11.0",
42
- "@webex/test-helper-mock-webex": "3.11.0",
43
- "@webex/webex-core": "3.11.0",
39
+ "@webex/common": "3.12.0",
40
+ "@webex/common-timers": "3.12.0",
41
+ "@webex/test-helper-chai": "3.12.0",
42
+ "@webex/test-helper-mock-webex": "3.12.0",
43
+ "@webex/webex-core": "3.12.0",
44
44
  "ip-anonymize": "^0.1.0",
45
45
  "lodash": "^4.17.21",
46
46
  "uuid": "^3.3.2"
@@ -53,5 +53,5 @@
53
53
  "test:style": "eslint ./src/**/*.*",
54
54
  "test:unit": "webex-legacy-tools test --unit --runner mocha"
55
55
  },
56
- "version": "3.11.0"
56
+ "version": "3.12.0"
57
57
  }
@@ -303,10 +303,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
303
303
  * @returns - latency
304
304
  */
305
305
  public getStayLobbyTime() {
306
- return this.getDiffBetweenTimestamps(
307
- 'client.locus.join.response',
308
- 'internal.host.meeting.participant.admitted'
309
- );
306
+ return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.lobby.exited');
310
307
  }
311
308
 
312
309
  /**
@@ -480,7 +477,8 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
480
477
  const clickToInterstitial = this.getClickToInterstitial();
481
478
  const interstitialToJoinOk = this.getInterstitialToJoinOK();
482
479
  const joinConfJMT = this.getJoinConfJMT();
483
- const lobbyTime = this.getStayLobbyTime();
480
+ const lobbyTimeLatency = this.getStayLobbyTime();
481
+ const lobbyTime = typeof lobbyTimeLatency === 'number' ? lobbyTimeLatency : 0;
484
482
 
485
483
  if (clickToInterstitial && interstitialToJoinOk && joinConfJMT) {
486
484
  const totalMediaJMT = clamp(
@@ -366,6 +366,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
366
366
  if (meeting?.locusInfo?.fullState) {
367
367
  identifiers.locusUrl = meeting.locusUrl;
368
368
  identifiers.locusId = meeting.locusUrl && meeting.locusUrl.split('/').pop();
369
+ identifiers.locusSessionId = meeting.locusInfo.fullState.sessionId;
369
370
  identifiers.locusStartTime =
370
371
  meeting.locusInfo.fullState && meeting.locusInfo.fullState.lastActive;
371
372
  }
@@ -179,6 +179,16 @@ export const isSdpOfferCreationError = (rawError: any) => {
179
179
  return false;
180
180
  };
181
181
 
182
+ export const isWebrtcApiNotAvailableError = (
183
+ rawError: {code: number; message: string; name: string} | unknown
184
+ ) => {
185
+ if ((rawError as {name: string}).name === ERROR_DESCRIPTIONS.WEBRTC_API_NOT_AVAILABLE) {
186
+ return true;
187
+ }
188
+
189
+ return false;
190
+ };
191
+
182
192
  /**
183
193
  * Checks if the given error is a browser media error by its name.
184
194
  * Returns true if the error name matches any known browser media error name in the mapping.
@@ -351,7 +361,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
351
361
  joinTimes.totalMediaJMT = cdl.getTotalMediaJMT();
352
362
  joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();
353
363
  joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();
354
- joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
355
364
  joinTimes.totalMediaJMTWithUserDelay = cdl.getTotalMediaJMTWithUserDelay();
356
365
  joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
357
366
  break;
@@ -359,6 +368,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
359
368
  case 'client.media.tx.start':
360
369
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
361
370
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
371
+ break;
372
+
373
+ case 'client.lobby.exited':
374
+ joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
375
+ break;
362
376
  }
363
377
 
364
378
  if (!isEmpty(joinTimes)) {
@@ -133,6 +133,7 @@ export const ERROR_DESCRIPTIONS = {
133
133
  MULTISTREAM_NOT_AVAILABLE: 'MultistreamNotAvailable',
134
134
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
135
135
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
136
+ WEBRTC_API_NOT_AVAILABLE: 'WebrtcApiNotAvailableError',
136
137
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
137
138
  USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
138
139
  };
@@ -79,7 +79,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
79
79
  device: {
80
80
  id: this.getDeviceId(),
81
81
  },
82
- locale: window.navigator.language,
82
+ locale: window?.navigator.language,
83
83
  os: {
84
84
  name: getOSNameInternal(),
85
85
  version: getOSVersion(),
@@ -94,12 +94,12 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
94
94
  protected getBrowserDetails(): object {
95
95
  return {
96
96
  browser: getBrowserName(),
97
- browserHeight: window.innerHeight,
97
+ browserHeight: window?.innerHeight,
98
98
  browserVersion: getBrowserVersion(),
99
- browserWidth: window.innerWidth,
100
- domain: window.location.hostname,
101
- inIframe: window.self !== window.top,
102
- locale: window.navigator.language,
99
+ browserWidth: window?.innerWidth,
100
+ domain: window?.location.hostname,
101
+ inIframe: window?.self !== window?.top,
102
+ locale: window?.navigator.language,
103
103
  os: getOSNameInternal(),
104
104
  };
105
105
  }
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ import BehavioralMetrics from './behavioral-metrics';
28
28
  import OperationalMetrics from './operational-metrics';
29
29
  import BusinessMetrics from './business-metrics';
30
30
  import RtcMetrics from './rtcMetrics';
31
+ import PreLoginMetrics from './prelogin-metrics';
31
32
 
32
33
  registerInternalPlugin('metrics', Metrics, {
33
34
  config,
@@ -51,6 +52,7 @@ export {
51
52
  OperationalMetrics,
52
53
  BusinessMetrics,
53
54
  RtcMetrics,
55
+ PreLoginMetrics,
54
56
  };
55
57
  export type {
56
58
  ClientEvent,
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  ClientEvent as RawClientEvent,
3
3
  Event as RawEvent,
4
4
  MediaQualityEvent as RawMediaQualityEvent,
@@ -197,7 +197,7 @@ export interface BusinessEventPayload {
197
197
  metricName: string;
198
198
  timestamp: number;
199
199
  context: DeviceContext;
200
- browserDetails: EventPayload;
200
+ browserDetails: object;
201
201
  value: EventPayload;
202
202
  }
203
203
 
@@ -9,6 +9,8 @@ import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
9
9
  import BehavioralMetrics from './behavioral-metrics';
10
10
  import OperationalMetrics from './operational-metrics';
11
11
  import BusinessMetrics from './business-metrics';
12
+ import PreLoginMetrics from './prelogin-metrics';
13
+ import PreLoginMetricsBatcher from './prelogin-metrics-batcher';
12
14
  import {
13
15
  RecursivePartial,
14
16
  MetricEventProduct,
@@ -45,6 +47,7 @@ class Metrics extends WebexPlugin {
45
47
  behavioralMetrics: BehavioralMetrics;
46
48
  operationalMetrics: OperationalMetrics;
47
49
  businessMetrics: BusinessMetrics;
50
+ preLoginMetrics: PreLoginMetrics;
48
51
  isReady = false;
49
52
 
50
53
  /**
@@ -87,6 +90,13 @@ class Metrics extends WebexPlugin {
87
90
  this.webex.once('ready', () => {
88
91
  // @ts-ignore
89
92
  this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
93
+ this.preLoginMetrics = new PreLoginMetrics(
94
+ // @ts-ignore
95
+ new PreLoginMetricsBatcher({}, {parent: this.webex}),
96
+ {},
97
+ // @ts-ignore
98
+ {parent: this.webex}
99
+ );
90
100
  this.isReady = true;
91
101
  this.setDelaySubmitClientEvents({
92
102
  shouldDelay: this.delaySubmitClientEvents,
@@ -251,6 +261,38 @@ class Metrics extends WebexPlugin {
251
261
  return this.businessMetrics.submitBusinessEvent({name, payload, table, metadata});
252
262
  }
253
263
 
264
+ /**
265
+ * Call Analyzer: Pre-Login Event
266
+ * @param args
267
+ */
268
+ submitPreLoginEvent({
269
+ name,
270
+ preLoginId,
271
+ payload,
272
+ metadata,
273
+ }: {
274
+ name: string;
275
+ preLoginId: string;
276
+ payload: EventPayload;
277
+ metadata?: EventPayload;
278
+ }): Promise<void> {
279
+ if (!this.isReady) {
280
+ // @ts-ignore
281
+ this.webex.logger.log(
282
+ `NewMetrics: @submitPreLoginEvent. Attempted to submit before webex.ready: ${name}`
283
+ );
284
+
285
+ return Promise.resolve();
286
+ }
287
+
288
+ return this.preLoginMetrics.submitPreLoginEvent({
289
+ name,
290
+ preLoginId,
291
+ payload,
292
+ metadata,
293
+ });
294
+ }
295
+
254
296
  /**
255
297
  * Call Analyzer: Media Quality Event
256
298
  * @param args
@@ -0,0 +1,94 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import {BusinessEvent, EventPayload} from './metrics.types';
3
+ import PreLoginMetricsBatcher from './prelogin-metrics-batcher';
4
+
5
+ /**
6
+ * @description Util class to handle PreLogin Metrics
7
+ * @export
8
+ * @class PreLoginMetrics
9
+ */
10
+ export default class PreLoginMetrics extends GenericMetrics {
11
+ private preLoginMetricsBatcher: typeof PreLoginMetricsBatcher;
12
+
13
+ /**
14
+ * Constructor
15
+ * @param {PreLoginMetricsBatcher} preLoginMetricsBatcher - Pre-login metrics batcher
16
+ * @param {any} attrs - Attributes
17
+ * @param {any} options - Options
18
+ * @constructor
19
+ */
20
+ constructor(
21
+ preLoginMetricsBatcher: typeof PreLoginMetricsBatcher,
22
+ attrs: any = {},
23
+ options: {parent?: any} = {}
24
+ ) {
25
+ super(attrs, options);
26
+ this.preLoginMetricsBatcher = preLoginMetricsBatcher;
27
+ }
28
+
29
+ /**
30
+ * Submit a business metric to our metrics endpoint.
31
+ * Routes to the correct table with the correct schema payload by table.
32
+ * @see https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
33
+ * @param {Object} options - The options object
34
+ * @param {string} options.name - Name of the metric
35
+ * @param {string} options.preLoginId - ID to identify pre-login user
36
+ * @param {EventPayload} options.payload - User payload of the metric
37
+ * @param {EventPayload} [options.metadata] - Optional metadata to include outside of eventPayload.value
38
+ * @returns {Promise<void>} Promise that resolves when the metric is submitted
39
+ */
40
+ public submitPreLoginEvent({
41
+ name,
42
+ preLoginId,
43
+ payload,
44
+ metadata,
45
+ }: {
46
+ name: string;
47
+ preLoginId: string;
48
+ payload: EventPayload;
49
+ metadata?: EventPayload;
50
+ }): Promise<void> {
51
+ if (!metadata) {
52
+ metadata = {};
53
+ }
54
+ if (!metadata.appType) {
55
+ metadata.appType = 'Web Client';
56
+ }
57
+
58
+ const finalEvent = this.buildEvent(name, preLoginId, payload, metadata);
59
+
60
+ this.preLoginMetricsBatcher.savePreLoginId(preLoginId);
61
+
62
+ return this.preLoginMetricsBatcher.request(finalEvent);
63
+ }
64
+
65
+ /**
66
+ * Builds a formatted event object for metrics submission.
67
+ * @param {string} metricName - Metric name
68
+ * @param {string} preLoginId - Pre-login user identifier
69
+ * @param {EventPayload} payload - Metric payload data
70
+ * @param {EventPayload} metadata - Additional metadata to include in the event
71
+ * @returns {object} Formatted metrics event object with type, eventPayload, and timestamp
72
+ */
73
+ private buildEvent(
74
+ metricName: string,
75
+ preLoginId: string,
76
+ payload: EventPayload,
77
+ metadata: EventPayload
78
+ ): BusinessEvent {
79
+ return {
80
+ type: ['business'],
81
+ eventPayload: {
82
+ metricName,
83
+ browserDetails: this.getBrowserDetails(),
84
+ context: this.getContext(),
85
+ timestamp: new Date().getTime(),
86
+ value: {
87
+ preLoginId,
88
+ ...metadata,
89
+ ...payload,
90
+ },
91
+ },
92
+ };
93
+ }
94
+ }
@@ -142,9 +142,7 @@ describe('plugin-metrics', () => {
142
142
  webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
143
143
  .stub()
144
144
  .returns(10);
145
- webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon
146
- .stub()
147
- .returns(20);
145
+ webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon.stub().returns(20);
148
146
  webex.internal.newMetrics.callDiagnosticLatencies.getReachabilityClustersReqResp = sinon
149
147
  .stub()
150
148
  .returns(10);
@@ -165,7 +163,7 @@ describe('plugin-metrics', () => {
165
163
  registerWDMDeviceJMT: 10,
166
164
  showInterstitialTime: 10,
167
165
  getU2CTime: 20,
168
- getReachabilityClustersReqResp: 10
166
+ getReachabilityClustersReqResp: 10,
169
167
  },
170
168
  });
171
169
  assert.lengthOf(
@@ -189,9 +187,8 @@ describe('plugin-metrics', () => {
189
187
  webex.internal.newMetrics.callDiagnosticLatencies.getDownloadTimeJMT = sinon
190
188
  .stub()
191
189
  .returns(100);
192
- webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay = sinon
193
- .stub()
194
- .returns(43);
190
+ webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay =
191
+ sinon.stub().returns(43);
195
192
  webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMTWithUserDelay = sinon
196
193
  .stub()
197
194
  .returns(64);
@@ -346,7 +343,7 @@ describe('plugin-metrics', () => {
346
343
  webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToJoinOK = sinon
347
344
  .stub()
348
345
  .returns(7);
349
- webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
346
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
350
347
  .stub()
351
348
  .returns(1);
352
349
  webex.internal.newMetrics.callDiagnosticLatencies.getTotalMediaJMTWithUserDelay = sinon
@@ -372,7 +369,6 @@ describe('plugin-metrics', () => {
372
369
  totalMediaJMT: 61,
373
370
  interstitialToMediaOKJMT: 22,
374
371
  callInitMediaEngineReady: 10,
375
- stayLobbyTime: 1,
376
372
  totalMediaJMTWithUserDelay: 43,
377
373
  totalJMTWithUserDelay: 64,
378
374
  },
@@ -382,6 +378,34 @@ describe('plugin-metrics', () => {
382
378
  0
383
379
  );
384
380
  });
381
+
382
+ it('appends the correct join times to the request for client.lobby.exited', async () => {
383
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
384
+ .stub()
385
+ .returns(10);
386
+
387
+ const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
388
+ //@ts-ignore
389
+ {event: {name: 'client.lobby.exited'}}
390
+ );
391
+ await flushPromises();
392
+ clock.tick(config.metrics.batcherWait);
393
+
394
+ await promise;
395
+
396
+ //@ts-ignore
397
+ assert.calledOnce(webex.request);
398
+ assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
399
+ name: 'client.lobby.exited',
400
+ joinTimes: {
401
+ stayLobbyTime: 10,
402
+ },
403
+ });
404
+ assert.lengthOf(
405
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.queue,
406
+ 0
407
+ );
408
+ });
385
409
  });
386
410
 
387
411
  describe('when the request fails', () => {