@newrelic/browser-agent 1.233.0 → 1.234.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 (115) hide show
  1. package/dist/cjs/cdn/experimental.js +27 -0
  2. package/dist/cjs/common/config/state/init.js +1 -1
  3. package/dist/cjs/common/constants/env.cdn.js +1 -1
  4. package/dist/cjs/common/constants/env.npm.js +1 -1
  5. package/dist/cjs/common/event-emitter/contextual-ee.test.js +10 -10
  6. package/dist/cjs/common/harvest/harvest-scheduler.js +18 -3
  7. package/dist/cjs/common/harvest/harvest-scheduler.test.js +39 -0
  8. package/dist/cjs/common/harvest/harvest.js +14 -34
  9. package/dist/cjs/common/harvest/harvest.test.js +224 -0
  10. package/dist/cjs/common/url/encode.js +2 -2
  11. package/dist/cjs/common/util/console.test.js +30 -0
  12. package/dist/cjs/common/util/get-or-set.js +8 -1
  13. package/dist/cjs/common/util/get-or-set.test.js +47 -0
  14. package/dist/cjs/common/util/stringify.test.js +48 -0
  15. package/dist/cjs/common/util/submit-data.js +15 -15
  16. package/dist/cjs/common/util/submit-data.test.js +221 -0
  17. package/dist/cjs/common/util/traverse.js +19 -27
  18. package/dist/cjs/common/util/traverse.test.js +44 -0
  19. package/dist/cjs/features/metrics/aggregate/endpoint-map.js +14 -0
  20. package/dist/cjs/features/metrics/aggregate/index.js +3 -2
  21. package/dist/cjs/features/metrics/instrument/index.js +0 -2
  22. package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
  23. package/dist/cjs/features/session_replay/aggregate/index.js +10 -7
  24. package/dist/cjs/loaders/configure/configure.js +0 -1
  25. package/dist/esm/cdn/experimental.js +24 -0
  26. package/dist/esm/common/config/state/init.js +1 -1
  27. package/dist/esm/common/constants/env.cdn.js +1 -1
  28. package/dist/esm/common/constants/env.npm.js +1 -1
  29. package/dist/esm/common/event-emitter/contextual-ee.test.js +10 -10
  30. package/dist/esm/common/harvest/harvest-scheduler.js +18 -3
  31. package/dist/esm/common/harvest/harvest-scheduler.test.js +37 -0
  32. package/dist/esm/common/harvest/harvest.js +14 -34
  33. package/dist/esm/common/harvest/harvest.test.js +222 -0
  34. package/dist/esm/common/url/encode.js +2 -2
  35. package/dist/esm/common/util/console.test.js +28 -0
  36. package/dist/esm/common/util/get-or-set.js +8 -1
  37. package/dist/esm/common/util/get-or-set.test.js +45 -0
  38. package/dist/esm/common/util/stringify.test.js +46 -0
  39. package/dist/esm/common/util/submit-data.js +15 -15
  40. package/dist/esm/common/util/submit-data.test.js +219 -0
  41. package/dist/esm/common/util/traverse.js +19 -27
  42. package/dist/esm/common/util/traverse.test.js +42 -0
  43. package/dist/esm/features/metrics/aggregate/endpoint-map.js +7 -0
  44. package/dist/esm/features/metrics/aggregate/index.js +3 -2
  45. package/dist/esm/features/metrics/instrument/index.js +0 -2
  46. package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
  47. package/dist/esm/features/session_replay/aggregate/index.js +10 -7
  48. package/dist/esm/loaders/configure/configure.js +0 -1
  49. package/dist/types/cdn/experimental.d.ts +2 -0
  50. package/dist/types/cdn/experimental.d.ts.map +1 -0
  51. package/dist/types/common/config/state/init.d.ts.map +1 -1
  52. package/dist/types/common/context/shared-context.d.ts.map +1 -1
  53. package/dist/types/common/harvest/harvest-scheduler.d.ts +26 -3
  54. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  55. package/dist/types/common/harvest/harvest.d.ts +2 -2
  56. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  57. package/dist/types/common/timer/timer.d.ts.map +1 -1
  58. package/dist/types/common/util/get-or-set.d.ts +9 -1
  59. package/dist/types/common/util/get-or-set.d.ts.map +1 -1
  60. package/dist/types/common/util/submit-data.d.ts +14 -10
  61. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  62. package/dist/types/common/util/traverse.d.ts +10 -1
  63. package/dist/types/common/util/traverse.d.ts.map +1 -1
  64. package/dist/types/common/window/nreum.d.ts.map +1 -1
  65. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +8 -0
  66. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
  67. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  68. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
  69. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  70. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  71. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  72. package/dist/types/features/session_replay/aggregate/index.d.ts +4 -0
  73. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  74. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  75. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  76. package/package.json +8 -3
  77. package/src/cdn/experimental.js +36 -0
  78. package/src/common/config/state/init.js +1 -2
  79. package/src/common/context/shared-context.js +0 -1
  80. package/src/common/event-emitter/contextual-ee.test.js +10 -10
  81. package/src/common/harvest/harvest-scheduler.js +18 -3
  82. package/src/common/harvest/harvest-scheduler.test.js +25 -0
  83. package/src/common/harvest/harvest.js +15 -20
  84. package/src/common/harvest/harvest.test.js +169 -0
  85. package/src/common/session/session-entity.test.js +0 -1
  86. package/src/common/timer/timer.js +0 -1
  87. package/src/common/url/encode.js +2 -2
  88. package/src/common/util/console.test.js +34 -0
  89. package/src/common/util/get-or-set.js +8 -1
  90. package/src/common/util/get-or-set.test.js +58 -0
  91. package/src/common/util/stringify.test.js +49 -0
  92. package/src/common/util/submit-data.js +15 -16
  93. package/src/common/util/submit-data.test.js +218 -0
  94. package/src/common/util/traverse.js +18 -27
  95. package/src/common/util/traverse.test.js +50 -0
  96. package/src/common/window/nreum.js +0 -1
  97. package/src/features/metrics/aggregate/endpoint-map.js +7 -0
  98. package/src/features/metrics/aggregate/index.js +3 -2
  99. package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
  100. package/src/features/metrics/instrument/index.js +0 -2
  101. package/src/features/page_view_event/aggregate/index.js +48 -51
  102. package/src/features/page_view_event/instrument/index.js +0 -1
  103. package/src/features/session_replay/aggregate/index.js +12 -7
  104. package/src/features/utils/handler-cache.js +0 -1
  105. package/src/loaders/configure/configure.js +0 -1
  106. package/dist/cjs/common/util/s-hash.js +0 -19
  107. package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
  108. package/dist/esm/common/util/s-hash.js +0 -13
  109. package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
  110. package/dist/types/common/util/s-hash.d.ts +0 -2
  111. package/dist/types/common/util/s-hash.d.ts.map +0 -1
  112. package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
  113. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +0 -1
  114. package/src/common/util/s-hash.js +0 -14
  115. package/src/features/metrics/instrument/workers-helper.js +0 -113
@@ -0,0 +1,45 @@
1
+ import { getOrSet } from './get-or-set';
2
+ test('should return the current value of an existing property', () => {
3
+ const obj = {
4
+ foo: 'bar'
5
+ };
6
+ const prop = 'foo';
7
+ const getVal = jest.fn();
8
+ const result = getOrSet(obj, prop, getVal);
9
+ expect(result).toBe('bar');
10
+ expect(getVal).not.toHaveBeenCalled();
11
+ });
12
+ test('should set and return the value from getVal if the property does not exist', () => {
13
+ const obj = {};
14
+ const prop = 'foo';
15
+ const getVal = jest.fn().mockReturnValue('baz');
16
+ const result = getOrSet(obj, prop, getVal);
17
+ expect(result).toBe('baz');
18
+ expect(getVal).toHaveBeenCalled();
19
+ expect(obj.foo).toBe('baz');
20
+ });
21
+ test('should set the property as non-enumerable if Object.defineProperty is supported', () => {
22
+ const obj = {};
23
+ const prop = 'foo';
24
+ const getVal = jest.fn().mockReturnValue('baz');
25
+ jest.spyOn(Object, 'defineProperty');
26
+ const result = getOrSet(obj, prop, getVal);
27
+ expect(result).toBe('baz');
28
+ expect(Object.defineProperty).toHaveBeenCalledWith(obj, prop, {
29
+ value: 'baz',
30
+ writable: true,
31
+ enumerable: false
32
+ });
33
+ });
34
+ test('should set the property from getVal if Object.defineProperty and Object.keys are not supported', () => {
35
+ const obj = {};
36
+ const prop = 'foo';
37
+ const getVal = jest.fn(() => 'baz');
38
+ const originalFn = Object.defineProperty;
39
+ Object.defineProperty = null;
40
+ const result = getOrSet(obj, prop, getVal);
41
+ expect(result).toBe('baz');
42
+ expect(obj.foo).toBe('baz');
43
+ expect(Object.prototype.propertyIsEnumerable.call(obj, 'foo')).toBe(true);
44
+ Object.defineProperty = originalFn;
45
+ });
@@ -0,0 +1,46 @@
1
+ import { stringify } from './stringify';
2
+ var mockEmit = jest.fn();
3
+ jest.mock('../event-emitter/contextual-ee', () => ({
4
+ __esModule: true,
5
+ get ee() {
6
+ return {
7
+ emit: mockEmit
8
+ };
9
+ }
10
+ }));
11
+ test('should return a JSON string representation of the value', () => {
12
+ const obj = {
13
+ a: 1,
14
+ b: {
15
+ nested: true
16
+ }
17
+ };
18
+ const expected = '{"a":1,"b":{"nested":true}}';
19
+ const result = stringify(obj);
20
+ expect(result).toBe(expected);
21
+ });
22
+ test('should handle circular references and exclude them from the JSON output', () => {
23
+ const obj = {
24
+ a: 1
25
+ };
26
+ obj.b = obj; // Create a circular reference
27
+ const expected = '{"a":1}';
28
+ const result = stringify(obj);
29
+ expect(result).toBe(expected);
30
+ });
31
+ test('should handle non-object values and return their string representation', () => {
32
+ const value = 42;
33
+ const expected = '42';
34
+ const result = stringify(value);
35
+ expect(result).toBe(expected);
36
+ });
37
+ test('should emit an "internal-error" event if an error occurs during JSON.stringify', () => {
38
+ const obj = {
39
+ a: 1
40
+ };
41
+ jest.spyOn(JSON, 'stringify').mockImplementation(() => {
42
+ throw new Error('message');
43
+ });
44
+ stringify(obj);
45
+ expect(mockEmit).toHaveBeenCalledWith('internal-error', expect.any(Array));
46
+ });
@@ -42,6 +42,14 @@ submitData.jsonp = function jsonp(_ref) {
42
42
  // do nothing
43
43
  }
44
44
  };
45
+
46
+ /**
47
+ * Performs an asynchronous GET request using XMLHttpRequest.
48
+ *
49
+ * @param {Object} args - An object containing a `url` property.
50
+ * @param {string} args.url - The URL to send the GET request to.
51
+ * @returns {XMLHttpRequest} - An XMLHttpRequest object.
52
+ */
45
53
  submitData.xhrGet = function xhrGet(_ref2) {
46
54
  let {
47
55
  url
@@ -55,18 +63,18 @@ submitData.xhrGet = function xhrGet(_ref2) {
55
63
 
56
64
  /**
57
65
  * Send via XHR
58
- * @param {Object} args - The args
59
- * @param {string} args.url - The URL to send to
60
- * @param {string=} args.body - The Stringified body
61
- * @param {boolean=} args.sync - Run XHR as Synchronous
62
- * @param {string=} [args.method=POST] - The XHR method to use
63
- * @param {{key: string, value: string}[]} [args.headers] - The headers to attach
66
+ * @param {Object} args - The args.
67
+ * @param {string} args.url - The URL to send to.
68
+ * @param {string=} args.body - The Stringified body. Default null to prevent IE11 from breaking.
69
+ * @param {boolean=} args.sync - Run XHR synchronously.
70
+ * @param {string=} [args.method=POST] - The XHR method to use.
71
+ * @param {{key: string, value: string}[]} [args.headers] - The headers to attach.
64
72
  * @returns {XMLHttpRequest}
65
73
  */
66
74
  submitData.xhr = function xhr(_ref3) {
67
75
  let {
68
76
  url,
69
- body,
77
+ body = null,
70
78
  sync,
71
79
  method = 'POST',
72
80
  headers = [{
@@ -89,13 +97,6 @@ submitData.xhr = function xhr(_ref3) {
89
97
  return request;
90
98
  };
91
99
 
92
- /**
93
- * Unused at the moment -- DEPRECATED
94
- */
95
- // submitData.xhrSync = function xhrSync (url, body) {
96
- // return submitData.xhr(url, body, true)
97
- // }
98
-
99
100
  /**
100
101
  * Send by appending an <img> element to the page. Do NOT call this function outside of a guaranteed web window environment.
101
102
  * @param {Object} args - The args
@@ -106,7 +107,6 @@ submitData.img = function img(_ref4) {
106
107
  let {
107
108
  url
108
109
  } = _ref4;
109
- console.log('img url', url);
110
110
  var element = new Image();
111
111
  element.src = url;
112
112
  return element;
@@ -0,0 +1,219 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ * @jest-environment-options {"html": "<html><head><script></script></head><body></body></html>", "url": "https://example.com/"}
4
+ */
5
+
6
+ import { submitData } from './submit-data';
7
+ const mockWorkerScope = jest.fn().mockImplementation(() => false);
8
+ jest.mock('./global-scope', () => ({
9
+ __esModule: true,
10
+ get isWorkerScope() {
11
+ return mockWorkerScope();
12
+ }
13
+ }));
14
+ const url = 'https://example.com/api';
15
+ beforeEach(() => {
16
+ jest.restoreAllMocks();
17
+ mockWorkerScope.mockReturnValue(false);
18
+ });
19
+ describe('submitData.jsonp', () => {
20
+ // This test requires a script tag to exist in the html set by this file's jest-environment-options header block.
21
+ test('should return an HTMLScriptElement when called from a web window environment', () => {
22
+ mockWorkerScope.mockReturnValue(false);
23
+ const jsonp = 'callback';
24
+ const result = submitData.jsonp({
25
+ url,
26
+ jsonp
27
+ });
28
+ expect(result).toBeInstanceOf(HTMLScriptElement);
29
+ expect(result.type).toBe('text/javascript');
30
+ expect(result.src).toBe(url + '&jsonp=' + jsonp);
31
+ });
32
+ test('should try to use importScripts when called from a worker scope', () => {
33
+ mockWorkerScope.mockReturnValueOnce(true);
34
+ const jsonp = 'callback';
35
+ global.importScripts = jest.fn();
36
+ submitData.jsonp({
37
+ url,
38
+ jsonp
39
+ });
40
+ expect(importScripts).toHaveBeenCalledWith(url + '&jsonp=' + jsonp);
41
+ delete global.importScripts;
42
+ });
43
+ test('should fall back to an xhrGet call and return false when called from a worker scope', () => {
44
+ mockWorkerScope.mockReturnValueOnce(true);
45
+ const jsonp = 'callback';
46
+ jest.spyOn(submitData, 'xhrGet').mockImplementation(jest.fn());
47
+ const result = submitData.jsonp({
48
+ url,
49
+ jsonp
50
+ });
51
+ expect(result).toBe(false);
52
+ expect(submitData.xhrGet).toHaveBeenCalledTimes(1);
53
+ });
54
+ test('should not throw an error if any error occurs during execution', () => {
55
+ jest.spyOn(document, 'createElement').mockImplementation(() => {
56
+ throw new Error('message');
57
+ });
58
+ const jsonp = 'callback';
59
+ expect(() => {
60
+ submitData.jsonp({
61
+ url,
62
+ jsonp
63
+ });
64
+ }).not.toThrow();
65
+ });
66
+ });
67
+ describe('submitData.xhrGet', () => {
68
+ test('should return an XMLHttpRequest object', () => {
69
+ const result = submitData.xhrGet({
70
+ url
71
+ });
72
+ expect(result).toBeInstanceOf(XMLHttpRequest);
73
+ });
74
+ test('should not throw an error if URL is not provided', () => {
75
+ expect(() => {
76
+ submitData.xhrGet({});
77
+ }).not.toThrow();
78
+ });
79
+ test('should not throw an error if an invalid URL is provided', () => {
80
+ expect(() => {
81
+ submitData.xhrGet({
82
+ url: 'invalid url'
83
+ });
84
+ }).not.toThrow();
85
+ });
86
+ });
87
+ describe('submitData.xhr', () => {
88
+ test('should return an XMLHttpRequest object', () => {
89
+ const result = submitData.xhrGet({
90
+ url
91
+ });
92
+ expect(result).toBeInstanceOf(XMLHttpRequest);
93
+ });
94
+ test('should not throw an error if URL is not provided', () => {
95
+ expect(() => {
96
+ submitData.xhr({});
97
+ }).not.toThrow();
98
+ });
99
+ test('should not throw an error if an invalid URL is provided', () => {
100
+ expect(() => {
101
+ submitData.xhr({
102
+ url: 'invalid url'
103
+ });
104
+ }).not.toThrow();
105
+ });
106
+ test('should send a POST request by default', () => {
107
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
108
+ submitData.xhr({
109
+ url
110
+ });
111
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('POST', url, true);
112
+ });
113
+ test('should send a GET request if specified', () => {
114
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
115
+ submitData.xhr({
116
+ url,
117
+ method: 'GET'
118
+ });
119
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', url, true);
120
+ });
121
+
122
+ // This test requires a same-origin url to be set by this file's jest-environment-options header block.
123
+ test('should send a request synchronously if specified', () => {
124
+ jest.spyOn(XMLHttpRequest.prototype, 'open');
125
+ submitData.xhr({
126
+ url,
127
+ sync: true
128
+ });
129
+ expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('POST', url, false);
130
+ });
131
+ test('should set custom headers if provided', () => {
132
+ const headers = [{
133
+ key: 'Content-Type',
134
+ value: 'application/json'
135
+ }];
136
+ jest.spyOn(XMLHttpRequest.prototype, 'setRequestHeader');
137
+ submitData.xhr({
138
+ url,
139
+ headers
140
+ });
141
+ headers.forEach(header => {
142
+ expect(XMLHttpRequest.prototype.setRequestHeader).toHaveBeenCalledWith(header.key, header.value);
143
+ });
144
+ });
145
+ test('should send a request with the specified body', () => {
146
+ const body = JSON.stringify({
147
+ key: 'value'
148
+ });
149
+ jest.spyOn(XMLHttpRequest.prototype, 'send');
150
+ submitData.xhr({
151
+ url,
152
+ body
153
+ });
154
+ expect(XMLHttpRequest.prototype.send).toHaveBeenCalledWith(body);
155
+ });
156
+ });
157
+ describe('submitData.img', () => {
158
+ test('should return an HTMLImageElement', () => {
159
+ const imageUrl = 'https://example.com/image.png';
160
+ const result = submitData.img({
161
+ url: imageUrl
162
+ });
163
+ expect(result).toBeInstanceOf(HTMLImageElement);
164
+ });
165
+ test('should not throw an error if URL is not provided', () => {
166
+ expect(() => {
167
+ submitData.img({});
168
+ }).not.toThrow();
169
+ });
170
+ test('should set the src attribute of the image element to the provided URL', () => {
171
+ const imageUrl = 'https://example.com/image.png';
172
+ const result = submitData.img({
173
+ url: imageUrl
174
+ });
175
+ expect(result.src).toBe(imageUrl);
176
+ });
177
+ });
178
+ describe('submitData.beacon', () => {
179
+ test('should return true when beacon request succeeds', () => {
180
+ const body = JSON.stringify({
181
+ key: 'value'
182
+ });
183
+ window.navigator.sendBeacon = {
184
+ bind: jest.fn(() => () => true)
185
+ };
186
+ const result = submitData.beacon({
187
+ url,
188
+ body
189
+ });
190
+ expect(result).toBe(true);
191
+ });
192
+ test('should return false when beacon request fails', () => {
193
+ const body = JSON.stringify({
194
+ key: 'value'
195
+ });
196
+ window.navigator.sendBeacon = {
197
+ bind: jest.fn(() => () => {
198
+ throw new Error('message');
199
+ })
200
+ };
201
+ const result = submitData.beacon({
202
+ url,
203
+ body
204
+ });
205
+ expect(result).toBe(false);
206
+ });
207
+ test('should error if sendBeacon is not supported', () => {
208
+ const body = JSON.stringify({
209
+ key: 'value'
210
+ });
211
+ window.navigator.sendBeacon = undefined;
212
+ expect(() => {
213
+ submitData.beacon({
214
+ url,
215
+ body
216
+ });
217
+ }).toThrow();
218
+ });
219
+ });
@@ -3,33 +3,25 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- // traverses an object and applies a fn to property values of a certain type
7
- export function applyFnToProps(obj, fn, type, ignoreKeys) {
6
+ /**
7
+ * Applies a function to properties of a specified type in an object, recursively.
8
+ *
9
+ * @param {Object} obj - The object to apply the function to.
10
+ * @param {Function} fn - The function to apply to matching properties.
11
+ * @param {string} [type='string'] - The type of properties to apply the function to.
12
+ * @param {Array<string>} [ignoreKeys=[]] - The keys of properties to ignore and not modify.
13
+ * @returns {Object} - The object with function recursively applied.
14
+ */
15
+ export function applyFnToProps(obj, fn) {
16
+ let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'string';
17
+ let ignoreKeys = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
8
18
  if (!obj || typeof obj !== 'object') return obj;
9
- type = type || 'string';
10
- ignoreKeys = ignoreKeys || [];
11
- return traverse(obj);
12
- function traverse(obj) {
13
- for (var property in obj) {
14
- // eslint-disable-next-line
15
- if (obj.hasOwnProperty(property)) {
16
- if (typeof obj[property] === 'object') {
17
- traverse(obj[property]);
18
- } else {
19
- if (typeof obj[property] === type && !shouldIgnore(property)) obj[property] = fn(obj[property]);
20
- }
21
- }
22
- }
23
- return obj;
24
- }
25
- function shouldIgnore(key) {
26
- var ignore = false;
27
- for (var i = 0; i < ignoreKeys.length; i++) {
28
- if (ignoreKeys[i] === key) {
29
- ignore = true;
30
- break;
31
- }
19
+ Object.keys(obj).forEach(property => {
20
+ if (typeof obj[property] === 'object') {
21
+ applyFnToProps(obj[property], fn, type, ignoreKeys);
22
+ } else {
23
+ if (typeof obj[property] === type && !ignoreKeys.includes(property)) obj[property] = fn(obj[property]);
32
24
  }
33
- return ignore;
34
- }
25
+ });
26
+ return obj;
35
27
  }
@@ -0,0 +1,42 @@
1
+ import { applyFnToProps } from './traverse';
2
+ test.each(['not an object', null, undefined])('should return input unchanged when input is %p', input => {
3
+ const result = applyFnToProps(input, jest.fn());
4
+ expect(result).toEqual(input);
5
+ });
6
+ test('should apply the provided function only to properties of the specified type', () => {
7
+ const obj = {
8
+ stringProp: 'Hello',
9
+ numberProp: 42,
10
+ arrayProp: [1, 2, 3],
11
+ objectProp: {
12
+ foo: 'bar'
13
+ }
14
+ };
15
+ const fn = jest.fn(value => value.toUpperCase());
16
+ const result = applyFnToProps(obj, fn, 'string');
17
+ expect(result.stringProp).toBe('HELLO');
18
+ expect(result.numberProp).toBe(42);
19
+ expect(result.arrayProp).toEqual([1, 2, 3]);
20
+ expect(result.objectProp).toEqual({
21
+ foo: 'BAR'
22
+ });
23
+ expect(fn).toHaveBeenCalledTimes(2);
24
+ expect(fn).toHaveBeenCalledWith('Hello');
25
+ expect(fn).toHaveBeenCalledWith('bar');
26
+ });
27
+ test('should ignore properties specified in ignoreKeys', () => {
28
+ const obj = {
29
+ a: 1,
30
+ b: 2,
31
+ c: 3
32
+ };
33
+ const fn = jest.fn(value => value + 1);
34
+ const ignoreKeys = ['c'];
35
+ const result = applyFnToProps(obj, fn, 'number', ignoreKeys);
36
+ expect(result.a).toBe(2);
37
+ expect(result.b).toBe(3);
38
+ expect(result.c).toBe(3);
39
+ expect(fn).toHaveBeenCalledTimes(2);
40
+ expect(fn).toHaveBeenCalledWith(1);
41
+ expect(fn).toHaveBeenCalledWith(2);
42
+ });
@@ -0,0 +1,7 @@
1
+ export const endpointMap = {
2
+ rum: '1',
3
+ events: 'Events',
4
+ ins: 'Ins',
5
+ jserrors: 'Jserrors',
6
+ resources: 'Resources'
7
+ };
@@ -13,6 +13,7 @@ import { windowAddEventListener } from '../../../common/event-listener/event-lis
13
13
  import { isBrowserScope } from '../../../common/util/global-scope';
14
14
  import { AggregateBase } from '../../utils/aggregate-base';
15
15
  import { stringify } from '../../../common/util/stringify';
16
+ import { endpointMap } from './endpoint-map';
16
17
  export class Aggregate extends AggregateBase {
17
18
  static featureName = FEATURE_NAME;
18
19
  constructor(agentIdentifier, aggregator) {
@@ -131,12 +132,12 @@ export class Aggregate extends AggregateBase {
131
132
 
132
133
  // Capture per-agent bytes sent for each endpoint (see harvest) and RUM call (see page_view_event aggregator).
133
134
  Object.keys(agentRuntime.bytesSent).forEach(endpoint => {
134
- this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/BytesSent"), agentRuntime.bytesSent[endpoint]);
135
+ this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpointMap[endpoint], "/BytesSent"), agentRuntime.bytesSent[endpoint]);
135
136
  });
136
137
 
137
138
  // Capture per-agent query bytes sent for each endpoint (see harvest) and RUM call (see page_view_event aggregator).
138
139
  Object.keys(agentRuntime.bytesSent).forEach(endpoint => {
139
- this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpoint.charAt(0).toUpperCase() + endpoint.slice(1), "/QueryBytesSent"), agentRuntime.queryBytesSent[endpoint]);
140
+ this.storeSupportabilityMetrics("PageSession/Endpoint/".concat(endpointMap[endpoint], "/QueryBytesSent"), agentRuntime.queryBytesSent[endpoint]);
140
141
  });
141
142
 
142
143
  // Capture metrics for session trace if active (`ptid` is set when returned by replay ingest).
@@ -1,5 +1,4 @@
1
1
  import { InstrumentBase } from '../../utils/instrument-base';
2
- import { insertSupportMetrics } from './workers-helper';
3
2
  import { FEATURE_NAME, SUPPORTABILITY_METRIC_CHANNEL } from '../constants';
4
3
  import { handle } from '../../../common/event-emitter/handle';
5
4
  import { FEATURE_NAMES } from '../../../loaders/features/features';
@@ -8,7 +7,6 @@ export class Instrument extends InstrumentBase {
8
7
  constructor(agentIdentifier, aggregator) {
9
8
  let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
10
9
  super(agentIdentifier, aggregator, FEATURE_NAME, auto);
11
- insertSupportMetrics(tag => handle(SUPPORTABILITY_METRIC_CHANNEL, [tag], undefined, FEATURE_NAMES.metrics, this.ee));
12
10
  this.importAggregator();
13
11
  }
14
12
  }