@webex/internal-plugin-metrics 3.11.0 → 3.12.0-auth-prejoin-fetch.1

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 (85) hide show
  1. package/README.md +36 -0
  2. package/dist/automated-user.js +19 -0
  3. package/dist/automated-user.js.map +1 -0
  4. package/dist/batcher.js +3 -0
  5. package/dist/batcher.js.map +1 -1
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +639 -65
  7. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js +168 -76
  9. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +18 -4
  11. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  12. package/dist/call-diagnostic/config.js +17 -3
  13. package/dist/call-diagnostic/config.js.map +1 -1
  14. package/dist/config.js +4 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/generic-metrics.js +8 -6
  17. package/dist/generic-metrics.js.map +1 -1
  18. package/dist/index.js +22 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/metrics.js +1 -1
  21. package/dist/metrics.types.js +4 -0
  22. package/dist/metrics.types.js.map +1 -1
  23. package/dist/new-metrics.js +108 -26
  24. package/dist/new-metrics.js.map +1 -1
  25. package/dist/prelogin-metrics.js +106 -0
  26. package/dist/prelogin-metrics.js.map +1 -0
  27. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  28. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  29. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  30. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  31. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  32. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  33. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  34. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  35. package/dist/types/automated-user.d.ts +2 -0
  36. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  37. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +79 -15
  38. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +5 -0
  39. package/dist/types/call-diagnostic/config.d.ts +5 -0
  40. package/dist/types/config.d.ts +4 -0
  41. package/dist/types/index.d.ts +6 -3
  42. package/dist/types/metrics.types.d.ts +9 -4
  43. package/dist/types/new-metrics.d.ts +29 -1
  44. package/dist/types/prelogin-metrics.d.ts +47 -0
  45. package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
  46. package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
  47. package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
  48. package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
  49. package/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
  50. package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
  51. package/dist/unhandled-exception-telemetry/index.js +330 -0
  52. package/dist/unhandled-exception-telemetry/index.js.map +1 -0
  53. package/dist/unhandled-exception-telemetry/utils.js +105 -0
  54. package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
  55. package/package.json +12 -11
  56. package/src/automated-user.ts +16 -0
  57. package/src/batcher.js +4 -0
  58. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -75
  59. package/src/call-diagnostic/call-diagnostic-metrics.ts +102 -15
  60. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +22 -2
  61. package/src/call-diagnostic/config.ts +15 -0
  62. package/src/config.js +4 -0
  63. package/src/generic-metrics.ts +6 -6
  64. package/src/index.ts +9 -0
  65. package/src/metrics.types.ts +27 -5
  66. package/src/new-metrics.ts +98 -6
  67. package/src/prelogin-metrics.ts +94 -0
  68. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  69. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  70. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  71. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  72. package/src/unhandled-exception-telemetry/index.ts +403 -0
  73. package/src/unhandled-exception-telemetry/utils.ts +101 -0
  74. package/test/unit/spec/automated-user.ts +43 -0
  75. package/test/unit/spec/batcher.js +43 -0
  76. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +47 -11
  77. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1550 -416
  78. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +887 -159
  79. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +61 -3
  80. package/test/unit/spec/new-metrics.ts +203 -50
  81. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  82. package/test/unit/spec/prelogin-metrics.ts +132 -0
  83. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
  84. package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
  85. package/test/unit/spec/unhandled-exception-telemetry.ts +688 -0
@@ -27,6 +27,7 @@ const {
27
27
  isUnauthorizedError,
28
28
  generateClientErrorCodeForIceFailure,
29
29
  isSdpOfferCreationError,
30
+ isWebrtcApiNotAvailableError,
30
31
  } = CallDiagnosticUtils;
31
32
 
32
33
  describe('internal-plugin-metrics', () => {
@@ -206,6 +207,29 @@ describe('internal-plugin-metrics', () => {
206
207
  });
207
208
  });
208
209
 
210
+ describe('isWebrtcApiNotAvailableError', () => {
211
+ type TestWebrtcApiNotAvailableError = {
212
+ code: number;
213
+ message: string;
214
+ name: string;
215
+ };
216
+
217
+ const error: TestWebrtcApiNotAvailableError = {
218
+ code: 30007,
219
+ name: 'WebrtcApiNotAvailableError',
220
+ message: 'RTCPeerConnection API is not available in this environment',
221
+ };
222
+
223
+ [
224
+ ['WebrtcApiNotAvailableError', error, true],
225
+ ['generic error', new Error('this is an error'), false],
226
+ ].forEach(([errorType, rawError, expected]) => {
227
+ it(`for ${errorType} rawError returns the correct result`, () => {
228
+ assert.strictEqual(isWebrtcApiNotAvailableError(rawError), expected);
229
+ });
230
+ });
231
+ });
232
+
209
233
  describe('isBrowserMediaErrorName', () => {
210
234
  [
211
235
  ['PermissionDeniedError', true],
@@ -287,7 +311,7 @@ describe('internal-plugin-metrics', () => {
287
311
  origin: {
288
312
  buildType: 'prod',
289
313
  networkType: 'unknown',
290
- upgradeChannel: expectedUpgradeChannel
314
+ upgradeChannel: expectedUpgradeChannel,
291
315
  },
292
316
  event: {name: eventName, ...expectedEvent},
293
317
  },
@@ -369,7 +393,7 @@ describe('internal-plugin-metrics', () => {
369
393
  totalJmt: undefined,
370
394
  clientJmt: undefined,
371
395
  downloadTime: undefined,
372
- clickToInterstitialWithUserDelay: undefined,
396
+ clickToInterstitialWithUserDelay: undefined,
373
397
  totalJMTWithUserDelay: undefined,
374
398
  },
375
399
  },
@@ -406,7 +430,6 @@ describe('internal-plugin-metrics', () => {
406
430
  totalMediaJMT: undefined,
407
431
  interstitialToMediaOKJMT: undefined,
408
432
  callInitMediaEngineReady: undefined,
409
- stayLobbyTime: undefined,
410
433
  totalMediaJMTWithUserDelay: undefined,
411
434
  totalJMTWithUserDelay: undefined,
412
435
  },
@@ -423,12 +446,47 @@ describe('internal-plugin-metrics', () => {
423
446
  },
424
447
  },
425
448
  ],
449
+ [
450
+ 'client.lobby.exited',
451
+ {
452
+ joinTimes: {
453
+ stayLobbyTime: undefined,
454
+ },
455
+ },
456
+ ],
426
457
  ].forEach(([eventName, expectedEvent]) => {
427
458
  it(`returns expected result for ${eventName}`, () => {
428
459
  check(eventName as string, expectedEvent, 'gold');
429
460
  });
430
461
  });
431
462
 
463
+ it('logs a Milestone entry when event name is present', () => {
464
+ const logSpy = sinon.spy(webex.logger, 'log');
465
+ const eventName = 'client.call.initiated';
466
+ const eventPayload = {event: {name: eventName}};
467
+
468
+ prepareDiagnosticMetricItem(webex, {eventPayload, type: ['diagnostic-event']});
469
+
470
+ assert.isTrue(
471
+ logSpy.calledWith('Milestone,CallDiagnostic', eventName),
472
+ 'expected logger.log to be called with Milestone,CallDiagnostic and the event name'
473
+ );
474
+ sinon.restore();
475
+ });
476
+
477
+ it('does not log a Milestone entry when event name is absent', () => {
478
+ const logSpy = sinon.spy(webex.logger, 'log');
479
+ const eventPayload = {event: {}};
480
+
481
+ prepareDiagnosticMetricItem(webex, {eventPayload, type: ['diagnostic-event']});
482
+
483
+ assert.isFalse(
484
+ logSpy.calledWith('Milestone,CallDiagnostic', sinon.match.any),
485
+ 'expected logger.log not to be called with Milestone,CallDiagnostic when event name is absent'
486
+ );
487
+ sinon.restore();
488
+ });
489
+
432
490
  it('sets buildType and upgradeChannel correctly', () => {
433
491
  const item: any = {
434
492
  eventPayload: {
@@ -1,23 +1,34 @@
1
1
  import {assert} from '@webex/test-helper-chai';
2
- import {NewMetrics, CallDiagnosticLatencies} from '@webex/internal-plugin-metrics';
2
+ import {
3
+ NewMetrics,
4
+ CallDiagnosticLatencies,
5
+ AutomatedUserUtils,
6
+ Utils,
7
+ } from '@webex/internal-plugin-metrics';
3
8
  import MockWebex from '@webex/test-helper-mock-webex';
4
9
  import sinon from 'sinon';
5
- import {Utils} from '@webex/internal-plugin-metrics';
6
10
 
7
- describe('internal-plugin-metrics', () => {
11
+ import SourceNewMetrics from '@webex/internal-plugin-metrics/src/new-metrics';
12
+ import * as Telemetry from '@webex/internal-plugin-metrics/src/unhandled-exception-telemetry';
8
13
 
9
- const mockWebex = () => new MockWebex({
10
- children: {
11
- newMetrics: NewMetrics,
12
- },
13
- meetings: {
14
- },
15
- request: sinon.stub().resolves({}),
16
- logger: {
17
- log: sinon.stub(),
18
- error: sinon.stub(),
19
- }
20
- });
14
+ describe('internal-plugin-metrics', () => {
15
+ const mockWebex = (NewMetricsPlugin = NewMetrics) =>
16
+ new MockWebex({
17
+ children: {
18
+ newMetrics: NewMetricsPlugin,
19
+ },
20
+ meetings: {
21
+ getBasicMeetingInformation: sinon.stub().callsFake((meetingId) => ({
22
+ id: meetingId,
23
+ correlationId: `correlation-${meetingId}`,
24
+ })),
25
+ },
26
+ request: sinon.stub().resolves({}),
27
+ logger: {
28
+ log: sinon.stub(),
29
+ error: sinon.stub(),
30
+ },
31
+ });
21
32
 
22
33
  describe('check submitClientEvent, submitFeatureEvent when webex is not ready', () => {
23
34
  let webex;
@@ -46,12 +57,14 @@ describe('internal-plugin-metrics', () => {
46
57
  payload: {
47
58
  meetingSummaryInfo: {
48
59
  featureName: 'syncSystemMuteStatus',
49
- featureActions: [{
50
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
51
- actionId: '14200',
52
- isInitialValue: false,
53
- clickCount: '1'
54
- }]
60
+ featureActions: [
61
+ {
62
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
63
+ actionId: '14200',
64
+ isInitialValue: false,
65
+ clickCount: '1',
66
+ },
67
+ ],
55
68
  },
56
69
  },
57
70
  });
@@ -63,12 +76,54 @@ describe('internal-plugin-metrics', () => {
63
76
  });
64
77
 
65
78
  describe('new-metrics contstructor', () => {
66
- it('checks callDiagnosticLatencies is defined before ready emit', () => {
79
+ afterEach(() => {
80
+ sinon.restore();
81
+ });
67
82
 
83
+ it('checks callDiagnosticLatencies is defined before ready emit', () => {
68
84
  const webex = mockWebex();
69
85
 
70
86
  assert.instanceOf(webex.internal.newMetrics.callDiagnosticLatencies, CallDiagnosticLatencies);
71
87
  });
88
+
89
+ it('checks callDiagnosticMetrics is defined before ready emit', () => {
90
+ const webex = mockWebex();
91
+
92
+ assert.isDefined(webex.internal.newMetrics.callDiagnosticMetrics);
93
+ });
94
+
95
+ it('can call buildClientEventFetchRequestOptions before ready', async () => {
96
+ const webex = mockWebex();
97
+ const stub = sinon
98
+ .stub(
99
+ webex.internal.newMetrics.callDiagnosticMetrics,
100
+ 'buildClientEventFetchRequestOptions'
101
+ )
102
+ .resolves({url: 'https://metrics.example.com'});
103
+
104
+ const result = await webex.internal.newMetrics.buildClientEventFetchRequestOptions({
105
+ name: 'client.alert.displayed',
106
+ options: {correlationId: 'test-id'},
107
+ });
108
+
109
+ assert.calledOnceWithExactly(stub, {
110
+ name: 'client.alert.displayed',
111
+ payload: undefined,
112
+ options: {correlationId: 'test-id'},
113
+ });
114
+ assert.deepEqual(result, {url: 'https://metrics.example.com'});
115
+ });
116
+
117
+ it('starts unhandled exception telemetry when webex is ready', () => {
118
+ const start = sinon.stub(Telemetry, 'startUnhandledExceptionTelemetry');
119
+ const webex = mockWebex(SourceNewMetrics);
120
+
121
+ assert.notCalled(start);
122
+
123
+ webex.emit('ready');
124
+
125
+ assert.calledOnceWithExactly(start, webex);
126
+ });
72
127
  });
73
128
 
74
129
  describe('new-metrics', () => {
@@ -94,7 +149,7 @@ describe('internal-plugin-metrics', () => {
94
149
 
95
150
  afterEach(() => {
96
151
  sinon.restore();
97
- })
152
+ });
98
153
 
99
154
  it('lazy metrics backend initialization when checking if backend ready', () => {
100
155
  assert.isUndefined(webex.internal.newMetrics.behavioralMetrics);
@@ -105,13 +160,20 @@ describe('internal-plugin-metrics', () => {
105
160
  webex.internal.newMetrics.isReadyToSubmitOperationalEvents();
106
161
  assert.isDefined(webex.internal.newMetrics.operationalMetrics);
107
162
 
108
- assert.isUndefined(webex.internal.newMetrics.businessMetrics)
163
+ assert.isUndefined(webex.internal.newMetrics.businessMetrics);
109
164
  webex.internal.newMetrics.isReadyToSubmitBusinessEvents();
110
165
  assert.isDefined(webex.internal.newMetrics.businessMetrics);
111
- })
166
+ });
167
+
168
+ it('returns the automated user classification', () => {
169
+ assert.strictEqual(
170
+ webex.internal.newMetrics.isAutomatedUser(),
171
+ AutomatedUserUtils.isAutomatedUser()
172
+ );
173
+ });
112
174
 
113
175
  it('passes the table through to the business metrics', () => {
114
- assert.isUndefined(webex.internal.newMetrics.businessMetrics)
176
+ assert.isUndefined(webex.internal.newMetrics.businessMetrics);
115
177
  webex.internal.newMetrics.isReadyToSubmitBusinessEvents();
116
178
  assert.isDefined(webex.internal.newMetrics.businessMetrics);
117
179
  webex.internal.newMetrics.businessMetrics.submitBusinessEvent = sinon.stub();
@@ -119,14 +181,14 @@ describe('internal-plugin-metrics', () => {
119
181
  name: 'foobar',
120
182
  payload: {},
121
183
  table: 'test',
122
- metadata: { foo: 'bar' },
184
+ metadata: {foo: 'bar'},
123
185
  });
124
186
 
125
187
  assert.calledWith(webex.internal.newMetrics.businessMetrics.submitBusinessEvent, {
126
188
  name: 'foobar',
127
189
  payload: {},
128
190
  table: 'test',
129
- metadata: { foo: 'bar' },
191
+ metadata: {foo: 'bar'},
130
192
  });
131
193
  });
132
194
 
@@ -150,6 +212,87 @@ describe('internal-plugin-metrics', () => {
150
212
  });
151
213
  });
152
214
 
215
+ describe('privacy and security permission enrichment', () => {
216
+ const permission = {
217
+ camera: {status: 'GRANTED' as const},
218
+ microphone: {status: 'DENIED' as const, reason: 'DENIED_BY_USER' as const},
219
+ contentShare: {status: 'REQUESTING' as const},
220
+ };
221
+
222
+ it('enriches an eligible client event through the public metrics API', () => {
223
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
224
+ webex.internal.newMetrics.submitClientEvent({name: 'client.call.initiated'});
225
+
226
+ const submittedPayload =
227
+ webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.firstCall.args[0]
228
+ .payload;
229
+
230
+ assert.deepEqual(submittedPayload.privacyAndSecurityPermission, {
231
+ camera: permission.camera,
232
+ microphone: permission.microphone,
233
+ });
234
+ });
235
+
236
+ it('uses the meeting correlation id to preserve history across identifier transitions', () => {
237
+ webex.meetings.getBasicMeetingInformation
238
+ .withArgs('meeting-1')
239
+ .returns({id: 'meeting-1', correlationId: 'correlation-1'});
240
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
241
+
242
+ webex.internal.newMetrics.submitClientEvent({
243
+ name: 'client.call.initiated',
244
+ options: {correlationId: 'correlation-1'},
245
+ });
246
+ webex.internal.newMetrics.submitClientEvent({
247
+ name: 'client.ice.end',
248
+ payload: {},
249
+ options: {meetingId: 'meeting-1'},
250
+ });
251
+
252
+ const submissions = webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.args;
253
+
254
+ assert.property(submissions[0][0].payload, 'privacyAndSecurityPermission');
255
+ assert.notProperty(submissions[1][0].payload, 'privacyAndSecurityPermission');
256
+ });
257
+
258
+ it('uses the default scope when no correlation id can be resolved', () => {
259
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
260
+
261
+ webex.internal.newMetrics.submitClientEvent({
262
+ name: 'client.call.initiated',
263
+ options: {sessionCorrelationId: 'session-1'},
264
+ });
265
+ webex.internal.newMetrics.submitClientEvent({
266
+ name: 'client.ice.end',
267
+ payload: {},
268
+ options: {sessionCorrelationId: 'session-2'},
269
+ });
270
+
271
+ const submissions = webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.args;
272
+
273
+ assert.property(submissions[0][0].payload, 'privacyAndSecurityPermission');
274
+ assert.notProperty(submissions[1][0].payload, 'privacyAndSecurityPermission');
275
+ });
276
+
277
+ it('captures the permission snapshot before a delayed event is queued', () => {
278
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
279
+ webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: true});
280
+ webex.internal.newMetrics.submitClientEvent({name: 'client.call.initiated'});
281
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission({
282
+ camera: {status: 'DENIED' as const},
283
+ });
284
+
285
+ const submission =
286
+ webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.firstCall.args[0];
287
+
288
+ assert.isTrue(submission.delaySubmitEvent);
289
+ assert.deepEqual(submission.payload.privacyAndSecurityPermission, {
290
+ camera: permission.camera,
291
+ microphone: permission.microphone,
292
+ });
293
+ });
294
+ });
295
+
153
296
  it('submits feature Event successfully', () => {
154
297
  webex.internal.newMetrics.submitFeatureEvent({
155
298
  name: 'client.feature.meeting.summary',
@@ -159,12 +302,14 @@ describe('internal-plugin-metrics', () => {
159
302
  payload: {
160
303
  meetingSummaryInfo: {
161
304
  featureName: 'syncSystemMuteStatus',
162
- featureActions: [{
163
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
164
- actionId: '14200',
165
- isInitialValue: false,
166
- clickCount: '1'
167
- }]
305
+ featureActions: [
306
+ {
307
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
308
+ actionId: '14200',
309
+ isInitialValue: false,
310
+ clickCount: '1',
311
+ },
312
+ ],
168
313
  },
169
314
  },
170
315
  });
@@ -178,12 +323,14 @@ describe('internal-plugin-metrics', () => {
178
323
  payload: {
179
324
  meetingSummaryInfo: {
180
325
  featureName: 'syncSystemMuteStatus',
181
- featureActions: [{
182
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
183
- actionId: '14200',
184
- isInitialValue: false,
185
- clickCount: '1'
186
- }]
326
+ featureActions: [
327
+ {
328
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
329
+ actionId: '14200',
330
+ isInitialValue: false,
331
+ clickCount: '1',
332
+ },
333
+ ],
187
334
  },
188
335
  },
189
336
  options: {meetingId: '123'},
@@ -244,9 +391,9 @@ describe('internal-plugin-metrics', () => {
244
391
  method: 'POST',
245
392
  api: 'metrics',
246
393
  resource: 'clientmetrics',
247
- headers: { 'x-prelogin-userid': 'my-id' },
394
+ headers: {'x-prelogin-userid': 'my-id'},
248
395
  body: {},
249
- qs: { alias: true },
396
+ qs: {alias: true},
250
397
  });
251
398
  assert.calledWith(
252
399
  webex.logger.log,
@@ -255,8 +402,8 @@ describe('internal-plugin-metrics', () => {
255
402
  });
256
403
 
257
404
  it('handles failed request correctly', async () => {
258
- webex.request.rejects(new Error("test error"));
259
- sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError')
405
+ webex.request.rejects(new Error('test error'));
406
+ sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError');
260
407
  try {
261
408
  await webex.internal.newMetrics.clientMetricsAliasUser({event: 'test'}, 'my-id');
262
409
  } catch (err) {
@@ -338,19 +485,26 @@ describe('internal-plugin-metrics', () => {
338
485
  sinon.assert.match(webex.internal.newMetrics.delaySubmitClientEvents, true);
339
486
  sinon.assert.match(webex.internal.newMetrics.delayedClientEventsOverrides, {});
340
487
 
341
- webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: false, overrides: {foo: 'bar'}});
488
+ webex.internal.newMetrics.setDelaySubmitClientEvents({
489
+ shouldDelay: false,
490
+ overrides: {foo: 'bar'},
491
+ });
342
492
 
343
- assert.calledOnce(webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents);
344
- assert.calledWith(webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents, {foo: 'bar'});
493
+ assert.calledOnce(
494
+ webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents
495
+ );
496
+ assert.calledWith(
497
+ webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents,
498
+ {foo: 'bar'}
499
+ );
345
500
 
346
501
  sinon.assert.match(webex.internal.newMetrics.delaySubmitClientEvents, false);
347
502
  sinon.assert.match(webex.internal.newMetrics.delayedClientEventsOverrides, {foo: 'bar'});
348
503
  });
349
504
 
350
505
  it('should not fail when called before webex is ready', () => {
351
-
352
506
  // Create mock
353
- webex = mockWebex()
507
+ webex = mockWebex();
354
508
 
355
509
  webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
356
510
  webex.internal.newMetrics.callDiagnosticLatencies.clearTimestamps = sinon.stub();
@@ -365,7 +519,6 @@ describe('internal-plugin-metrics', () => {
365
519
  webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: false});
366
520
  // Webex is ready
367
521
  webex.emit('ready');
368
-
369
522
  });
370
523
  });
371
524
  });
@@ -64,45 +64,36 @@ describe('internal-plugin-metrics', () => {
64
64
  //@ts-ignore
65
65
  assert.calledOnce(webex.request);
66
66
 
67
- // matching because the request includes a symbol key: value pair and sinon cannot handle to compare it..
68
- assert.match(webexRequestArgs, {
69
- //@ts-ignore
70
- body: {
71
- metrics: [
72
- {
73
- eventPayload: {
74
- event: {
75
- joinTimes: {
76
- meetingInfoReqResp: undefined,
77
- clickToInterstitial: undefined,
78
- refreshCaptchaServiceReqResp: undefined,
79
- downloadIntelligenceModelsReqResp: undefined,
80
- clickToInterstitialWithUserDelay: undefined,
81
- },
82
- name: 'client.interstitial-window.launched',
83
- },
84
- origin: {
85
- buildType: 'test',
86
- networkType: 'unknown',
87
- upgradeChannel: 'test',
88
- },
89
- originTime: {
90
- sent: dateAfterBatcherWait.toISOString(),
91
- },
92
- },
93
- type: ['diagnostic-event'],
94
- },
95
- ],
67
+ assert.deepEqual(webexRequestArgs.headers, {
68
+ authorization: false,
69
+ 'x-prelogin-userid': preLoginId,
70
+ });
71
+ assert.equal(webexRequestArgs.method, 'POST');
72
+ assert.equal(webexRequestArgs.resource, 'clientmetrics-prelogin');
73
+ assert.equal(webexRequestArgs.service, 'metrics');
74
+ assert.equal(webexRequestArgs.waitForServiceTimeout, 30);
75
+
76
+ assert.deepEqual(webexRequestArgs.body.metrics[0].eventPayload, {
77
+ event: {
78
+ joinTimes: {
79
+ meetingInfoReqResp: undefined,
80
+ clickToInterstitial: undefined,
81
+ refreshCaptchaServiceReqResp: undefined,
82
+ downloadIntelligenceModelsReqResp: undefined,
83
+ clickToInterstitialWithUserDelay: undefined,
84
+ },
85
+ name: 'client.interstitial-window.launched',
96
86
  },
97
- headers: {
98
- authorization: false,
99
- 'x-prelogin-userid': preLoginId,
87
+ origin: {
88
+ buildType: 'test',
89
+ networkType: 'unknown',
90
+ upgradeChannel: 'test',
91
+ },
92
+ originTime: {
93
+ sent: dateAfterBatcherWait.toISOString(),
100
94
  },
101
- method: 'POST',
102
- resource: 'clientmetrics-prelogin',
103
- service: 'metrics',
104
- waitForServiceTimeout: 30,
105
95
  });
96
+ assert.deepEqual(webexRequestArgs.body.metrics[0].type, ['diagnostic-event']);
106
97
  assert.lengthOf(
107
98
  webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.queue,
108
99
  0
@@ -320,5 +311,49 @@ describe('internal-plugin-metrics', () => {
320
311
  );
321
312
  });
322
313
  });
314
+
315
+ describe('#submitHttpRequest', () => {
316
+ it('calls webex.request with the correct parameters', async () => {
317
+ const payload = [
318
+ {
319
+ eventPayload: {event: 'my.event'},
320
+ type: ['diagnostic-event'],
321
+ },
322
+ ];
323
+
324
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.savePreLoginId(
325
+ preLoginId
326
+ );
327
+ webex.request = sinon.stub().resolves({statusCode: 200});
328
+
329
+ const promise =
330
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.submitHttpRequest(
331
+ payload
332
+ );
333
+
334
+ await flushPromises();
335
+
336
+ clock.tick(config.metrics.batcherWait);
337
+
338
+ await promise;
339
+
340
+ const webexRequestArgs = webex.request.args[0][0];
341
+
342
+ assert.match(webexRequestArgs, {
343
+ //@ts-ignore
344
+ body: {
345
+ metrics: payload,
346
+ },
347
+ headers: {
348
+ authorization: false,
349
+ 'x-prelogin-userid': preLoginId,
350
+ },
351
+ method: 'POST',
352
+ resource: 'clientmetrics-prelogin',
353
+ service: 'metrics',
354
+ waitForServiceTimeout: 30,
355
+ });
356
+ });
357
+ });
323
358
  });
324
359
  });