@newrelic/browser-agent 0.1.230 → 0.1.231

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 (221) hide show
  1. package/README.md +25 -1
  2. package/dist/cjs/common/browser-version/ios-version.js +4 -3
  3. package/dist/cjs/common/config/state/configurable.js +1 -1
  4. package/dist/cjs/common/config/state/info.js +1 -1
  5. package/dist/cjs/common/config/state/init.js +1 -1
  6. package/dist/cjs/common/config/state/loader-config.js +1 -1
  7. package/dist/cjs/common/config/state/runtime.js +5 -5
  8. package/dist/cjs/common/constants/env.cdn.js +29 -0
  9. package/dist/cjs/common/constants/env.js +32 -0
  10. package/dist/cjs/common/constants/env.npm.js +30 -0
  11. package/dist/cjs/common/event-emitter/contextual-ee.test.js +282 -0
  12. package/dist/cjs/common/event-emitter/handle.test.js +58 -0
  13. package/dist/cjs/common/event-emitter/register-handler.test.js +55 -0
  14. package/dist/cjs/common/harvest/harvest.js +2 -2
  15. package/dist/cjs/common/ids/id.js +14 -6
  16. package/dist/cjs/common/ids/id.test.js +85 -0
  17. package/dist/cjs/common/ids/unique-id.js +75 -51
  18. package/dist/cjs/common/ids/unique-id.test.js +49 -0
  19. package/dist/cjs/common/timing/nav-timing.js +51 -30
  20. package/dist/cjs/common/timing/nav-timing.test.js +192 -0
  21. package/dist/cjs/common/url/clean-url.test.js +9 -0
  22. package/dist/cjs/common/url/encode.test.js +74 -0
  23. package/dist/cjs/common/url/location.js +4 -0
  24. package/dist/cjs/common/url/location.test.js +13 -0
  25. package/dist/cjs/common/url/parse-url.test.js +111 -0
  26. package/dist/cjs/common/url/protocol.js +2 -12
  27. package/dist/cjs/common/url/protocol.test.js +16 -0
  28. package/dist/cjs/common/util/console.js +1 -1
  29. package/dist/cjs/common/util/map-own.test.js +3 -3
  30. package/dist/cjs/common/util/obfuscate.js +1 -1
  31. package/dist/cjs/common/window/page-visibility.js +2 -1
  32. package/dist/cjs/common/wrap/index.js +0 -7
  33. package/dist/cjs/common/wrap/wrap-events.js +6 -9
  34. package/dist/cjs/common/wrap/wrap-fetch.js +6 -6
  35. package/dist/cjs/common/wrap/wrap-history.js +7 -6
  36. package/dist/cjs/common/wrap/wrap-jsonp.js +7 -6
  37. package/dist/cjs/common/wrap/wrap-mutation.js +7 -6
  38. package/dist/cjs/common/wrap/wrap-promise.js +7 -6
  39. package/dist/cjs/common/wrap/wrap-promise.test.js +119 -0
  40. package/dist/cjs/common/wrap/wrap-raf.js +6 -6
  41. package/dist/cjs/common/wrap/wrap-timer.js +6 -6
  42. package/dist/cjs/common/wrap/wrap-xhr.js +5 -6
  43. package/dist/cjs/features/ajax/aggregate/index.js +1 -1
  44. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +5 -5
  45. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +1 -1
  46. package/dist/cjs/features/jserrors/aggregate/index.js +3 -3
  47. package/dist/cjs/features/jserrors/instrument/index.js +2 -2
  48. package/dist/cjs/features/metrics/aggregate/index.js +6 -7
  49. package/dist/cjs/features/metrics/instrument/index.js +0 -25
  50. package/dist/cjs/features/metrics/instrument/workers-helper.js +5 -5
  51. package/dist/cjs/features/page_action/aggregate/index.js +1 -1
  52. package/dist/cjs/features/page_view_event/aggregate/index.js +17 -6
  53. package/dist/cjs/features/page_view_timing/aggregate/index.js +36 -26
  54. package/dist/cjs/features/session_trace/aggregate/index.js +16 -13
  55. package/dist/cjs/features/utils/instrument-base.js +6 -2
  56. package/dist/cjs/features/utils/lazy-loader.js +1 -1
  57. package/dist/cjs/loaders/agent.js +1 -1
  58. package/dist/cjs/loaders/api/api.js +8 -5
  59. package/dist/cjs/loaders/features/enabled-features.js +1 -1
  60. package/dist/cjs/loaders/micro-agent.js +2 -1
  61. package/dist/esm/common/browser-version/ios-version.js +4 -3
  62. package/dist/esm/common/config/state/configurable.js +1 -1
  63. package/dist/esm/common/config/state/info.js +1 -1
  64. package/dist/esm/common/config/state/init.js +1 -1
  65. package/dist/esm/common/config/state/loader-config.js +1 -1
  66. package/dist/esm/common/config/state/runtime.js +2 -2
  67. package/dist/esm/common/constants/env.cdn.js +20 -0
  68. package/dist/esm/common/constants/env.js +23 -0
  69. package/dist/esm/common/constants/env.npm.js +21 -0
  70. package/dist/esm/common/event-emitter/contextual-ee.test.js +278 -0
  71. package/dist/esm/common/event-emitter/handle.test.js +54 -0
  72. package/dist/esm/common/event-emitter/register-handler.test.js +51 -0
  73. package/dist/esm/common/harvest/harvest.js +1 -1
  74. package/dist/esm/common/ids/id.js +16 -6
  75. package/dist/esm/common/ids/id.test.js +81 -0
  76. package/dist/esm/common/ids/unique-id.js +75 -51
  77. package/dist/esm/common/ids/unique-id.test.js +44 -0
  78. package/dist/esm/common/timing/nav-timing.js +51 -29
  79. package/dist/esm/common/timing/nav-timing.test.js +190 -0
  80. package/dist/esm/common/url/clean-url.test.js +7 -0
  81. package/dist/esm/common/url/encode.test.js +70 -0
  82. package/dist/esm/common/url/location.js +4 -0
  83. package/dist/esm/common/url/location.test.js +11 -0
  84. package/dist/esm/common/url/parse-url.test.js +107 -0
  85. package/dist/esm/common/url/protocol.js +3 -12
  86. package/dist/esm/common/url/protocol.test.js +14 -0
  87. package/dist/esm/common/util/console.js +1 -1
  88. package/dist/esm/common/util/map-own.test.js +3 -3
  89. package/dist/esm/common/util/obfuscate.js +2 -2
  90. package/dist/esm/common/window/page-visibility.js +2 -1
  91. package/dist/esm/common/wrap/index.js +1 -2
  92. package/dist/esm/common/wrap/wrap-events.js +6 -9
  93. package/dist/esm/common/wrap/wrap-fetch.js +6 -6
  94. package/dist/esm/common/wrap/wrap-history.js +7 -6
  95. package/dist/esm/common/wrap/wrap-jsonp.js +7 -6
  96. package/dist/esm/common/wrap/wrap-mutation.js +7 -6
  97. package/dist/esm/common/wrap/wrap-promise.js +7 -6
  98. package/dist/esm/common/wrap/wrap-promise.test.js +115 -0
  99. package/dist/esm/common/wrap/wrap-raf.js +6 -6
  100. package/dist/esm/common/wrap/wrap-timer.js +6 -6
  101. package/dist/esm/common/wrap/wrap-xhr.js +5 -6
  102. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  103. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +5 -5
  104. package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +1 -1
  105. package/dist/esm/features/jserrors/aggregate/index.js +3 -3
  106. package/dist/esm/features/jserrors/instrument/index.js +2 -2
  107. package/dist/esm/features/metrics/aggregate/index.js +7 -8
  108. package/dist/esm/features/metrics/instrument/index.js +0 -25
  109. package/dist/esm/features/metrics/instrument/workers-helper.js +5 -5
  110. package/dist/esm/features/page_action/aggregate/index.js +1 -1
  111. package/dist/esm/features/page_view_event/aggregate/index.js +17 -6
  112. package/dist/esm/features/page_view_timing/aggregate/index.js +36 -26
  113. package/dist/esm/features/session_trace/aggregate/index.js +16 -13
  114. package/dist/esm/features/utils/instrument-base.js +1 -1
  115. package/dist/esm/features/utils/lazy-loader.js +1 -1
  116. package/dist/esm/loaders/agent.js +1 -1
  117. package/dist/esm/loaders/api/api.js +4 -4
  118. package/dist/esm/loaders/features/enabled-features.js +1 -1
  119. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  120. package/dist/types/common/constants/env.cdn.d.ts +18 -0
  121. package/dist/types/common/constants/env.cdn.d.ts.map +1 -0
  122. package/dist/types/common/constants/env.d.ts +13 -0
  123. package/dist/types/common/constants/env.d.ts.map +1 -0
  124. package/dist/types/common/constants/env.npm.d.ts +19 -0
  125. package/dist/types/common/constants/env.npm.d.ts.map +1 -0
  126. package/dist/types/common/ids/id.d.ts +11 -1
  127. package/dist/types/common/ids/id.d.ts.map +1 -1
  128. package/dist/types/common/ids/unique-id.d.ts +24 -1
  129. package/dist/types/common/ids/unique-id.d.ts.map +1 -1
  130. package/dist/types/common/timing/nav-timing.d.ts +1 -2
  131. package/dist/types/common/timing/nav-timing.d.ts.map +1 -1
  132. package/dist/types/common/unload/eol.d.ts.map +1 -1
  133. package/dist/types/common/url/location.d.ts +4 -0
  134. package/dist/types/common/url/location.d.ts.map +1 -1
  135. package/dist/types/common/url/parse-url.d.ts.map +1 -1
  136. package/dist/types/common/url/protocol.d.ts +1 -6
  137. package/dist/types/common/url/protocol.d.ts.map +1 -1
  138. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  139. package/dist/types/common/wrap/index.d.ts +1 -2
  140. package/dist/types/common/wrap/index.d.ts.map +1 -1
  141. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  142. package/dist/types/common/wrap/wrap-history.d.ts.map +1 -1
  143. package/dist/types/common/wrap/wrap-jsonp.d.ts.map +1 -1
  144. package/dist/types/common/wrap/wrap-mutation.d.ts.map +1 -1
  145. package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
  146. package/dist/types/common/wrap/wrap-raf.d.ts.map +1 -1
  147. package/dist/types/common/wrap/wrap-timer.d.ts.map +1 -1
  148. package/dist/types/common/wrap/wrap-xhr.d.ts.map +1 -1
  149. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  150. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  151. package/dist/types/features/metrics/instrument/index.d.ts +0 -1
  152. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  153. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +1 -1
  154. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  155. package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -2
  156. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  157. package/dist/types/features/session_trace/aggregate/index.d.ts +1 -1
  158. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  160. package/dist/types/features/spa/instrument/index.d.ts.map +1 -1
  161. package/package.json +9 -30
  162. package/src/common/browser-version/ios-version.js +4 -3
  163. package/src/common/config/state/runtime.js +26 -24
  164. package/src/common/constants/env.cdn.js +20 -0
  165. package/src/common/constants/env.js +23 -0
  166. package/src/common/constants/env.npm.js +21 -0
  167. package/src/common/event-emitter/contextual-ee.test.js +310 -0
  168. package/src/common/event-emitter/handle.test.js +56 -0
  169. package/src/common/event-emitter/register-handler.test.js +61 -0
  170. package/src/common/harvest/harvest.js +2 -2
  171. package/src/common/ids/id.js +15 -6
  172. package/src/common/ids/id.test.js +92 -0
  173. package/src/common/ids/unique-id.js +77 -54
  174. package/src/common/ids/unique-id.test.js +58 -0
  175. package/src/common/timing/nav-timing.js +50 -30
  176. package/src/common/timing/nav-timing.test.js +161 -0
  177. package/src/common/unload/eol.js +1 -2
  178. package/src/common/url/clean-url.test.js +25 -0
  179. package/src/common/url/encode.test.js +80 -0
  180. package/src/common/url/location.js +4 -0
  181. package/src/common/url/location.test.js +15 -0
  182. package/src/common/url/parse-url.js +1 -2
  183. package/src/common/url/parse-url.test.js +110 -0
  184. package/src/common/url/protocol.js +3 -13
  185. package/src/common/url/protocol.test.js +18 -0
  186. package/src/common/util/global-scope.js +1 -2
  187. package/src/common/util/obfuscate.js +2 -2
  188. package/src/common/window/page-visibility.js +1 -1
  189. package/src/common/wrap/index.js +1 -2
  190. package/src/common/wrap/wrap-events.js +5 -5
  191. package/src/common/wrap/wrap-fetch.js +4 -3
  192. package/src/common/wrap/wrap-history.js +6 -3
  193. package/src/common/wrap/wrap-jsonp.js +5 -3
  194. package/src/common/wrap/wrap-mutation.js +6 -3
  195. package/src/common/wrap/wrap-promise.js +7 -6
  196. package/src/common/wrap/wrap-promise.test.js +140 -0
  197. package/src/common/wrap/wrap-raf.js +5 -3
  198. package/src/common/wrap/wrap-timer.js +5 -3
  199. package/src/common/wrap/wrap-xhr.js +4 -3
  200. package/src/features/ajax/instrument/index.js +1 -1
  201. package/src/features/jserrors/instrument/index.js +4 -2
  202. package/src/features/metrics/aggregate/index.js +3 -4
  203. package/src/features/metrics/instrument/index.js +0 -30
  204. package/src/features/metrics/instrument/workers-helper.js +9 -6
  205. package/src/features/page_view_event/aggregate/index.js +15 -6
  206. package/src/features/page_view_timing/aggregate/index.js +36 -25
  207. package/src/features/page_view_timing/long-tasks.js +10 -10
  208. package/src/features/session_trace/aggregate/index.js +15 -12
  209. package/src/features/session_trace/instrument/index.js +3 -2
  210. package/src/features/spa/instrument/index.js +4 -2
  211. package/src/loaders/api/api.js +1 -1
  212. package/dist/cjs/common/constants/environment-variables.js +0 -20
  213. package/dist/cjs/common/wrap/wrap-console.js +0 -54
  214. package/dist/esm/common/constants/environment-variables.js +0 -11
  215. package/dist/esm/common/wrap/wrap-console.js +0 -46
  216. package/dist/types/common/constants/environment-variables.d.ts +0 -4
  217. package/dist/types/common/constants/environment-variables.d.ts.map +0 -1
  218. package/dist/types/common/wrap/wrap-console.d.ts +0 -16
  219. package/dist/types/common/wrap/wrap-console.d.ts.map +0 -1
  220. package/src/common/constants/environment-variables.js +0 -11
  221. package/src/common/wrap/wrap-console.js +0 -47
@@ -4,72 +4,96 @@
4
4
  */
5
5
 
6
6
  import { globalScope } from '../util/global-scope';
7
+ const uuidv4Template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
8
+
9
+ /**
10
+ * Creates a random single hexadecimal value from a provided random value
11
+ * table and corresponding index. If a random value table is not provided,
12
+ * Math.random will be used to generate the value.
13
+ *
14
+ * @param {Uint8Array} valueTable Random value table typically generated using
15
+ * the built-in crypto engine.
16
+ * @param {int} tableIndex The index of the value table to use for generating
17
+ * the hexadecimal value.
18
+ * @returns {int} single hexadecimal value in decimal format
19
+ */
20
+ function getRandomValue(valueTable, tableIndex) {
21
+ if (valueTable) {
22
+ /**
23
+ * The value table could have any number value in the given index. Use
24
+ * bitwise AND to ensure the value we generate is a valid hex value.
25
+ * x & 15 will ensure the value converted to hex using `toString(16)`
26
+ * falls within the range of 0 and 15 inclusively.
27
+ */
28
+ return valueTable[tableIndex] & 15;
29
+ } else {
30
+ return Math.random() * 16 | 0;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Generates a RFC compliant UUIDv4 using native browser crypto engine. If the browser
36
+ * does not support the crypto engine, the function will fallback to insecure Math.random()
37
+ * @returns {string} uuid version 4 string
38
+ */
7
39
  export function generateUuid() {
8
- var randomVals = null;
9
- var rvIndex = 0;
10
- var crypto = globalScope?.crypto || globalScope?.msCrypto;
40
+ const crypto = globalScope?.crypto || globalScope?.msCrypto;
41
+ let randomValueTable;
42
+ let randomValueIndex = 0;
11
43
  if (crypto && crypto.getRandomValues) {
12
44
  // eslint-disable-next-line
13
- randomVals = crypto.getRandomValues(new Uint8Array(31));
14
- }
15
- function getRandomValue() {
16
- if (randomVals) {
17
- // same as % 16
18
- return randomVals[rvIndex++] & 15;
19
- } else {
20
- return Math.random() * 16 | 0;
21
- }
45
+ randomValueTable = crypto.getRandomValues(new Uint8Array(31));
22
46
  }
23
-
24
- // v4 UUID
25
- var template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
26
- var id = '';
27
- var c;
28
- for (var i = 0; i < template.length; i++) {
29
- c = template[i];
30
- if (c === 'x') {
31
- id += getRandomValue().toString(16);
32
- } else if (c === 'y') {
47
+ return uuidv4Template.split('').map(templateInput => {
48
+ if (templateInput === 'x') {
49
+ return getRandomValue(randomValueTable, ++randomValueIndex).toString(16);
50
+ } else if (templateInput === 'y') {
33
51
  // this is the uuid variant per spec (8, 9, a, b)
34
52
  // % 4, then shift to get values 8-11
35
- c = getRandomValue() & 0x3 | 0x8;
36
- id += c.toString(16);
53
+ return (getRandomValue() & 0x3 | 0x8).toString(16);
37
54
  } else {
38
- id += c;
55
+ return templateInput;
39
56
  }
57
+ }).join('');
58
+ }
59
+
60
+ /**
61
+ * Generates a string of the given length containing only hexadecimal
62
+ * value 0-9 and a-f.
63
+ * @param {int} length length of the string to generate
64
+ * @returns {string} generated hex string
65
+ */
66
+ export function generateRandomHexString(length) {
67
+ const crypto = globalScope?.crypto || globalScope?.msCrypto;
68
+ let randomValueTable;
69
+ let randomValueIndex = 0;
70
+ if (crypto && crypto.getRandomValues) {
71
+ // eslint-disable-next-line
72
+ randomValueTable = crypto.getRandomValues(new Uint8Array(31));
40
73
  }
41
- return id;
74
+ const chars = [];
75
+ for (var i = 0; i < length; i++) {
76
+ chars.push(getRandomValue(randomValueTable, ++randomValueIndex).toString(16));
77
+ }
78
+ return chars.join('');
42
79
  }
43
80
 
44
- // 16-character hex string (per DT spec)
81
+ /**
82
+ * Generates a 16 character length hexadecimal string.
83
+ * per DT-spec.
84
+ * @see generateRandomHexString
85
+ * @returns {string} generated hex string
86
+ */
45
87
  export function generateSpanId() {
46
88
  return generateRandomHexString(16);
47
89
  }
48
90
 
49
- // 32-character hex string (per DT spec)
91
+ /**
92
+ * Generates a 32 character length hexadecimal string.
93
+ * per DT-spec.
94
+ * @see generateRandomHexString
95
+ * @returns {string} generated hex string
96
+ */
50
97
  export function generateTraceId() {
51
98
  return generateRandomHexString(32);
52
- }
53
- export function generateRandomHexString(length) {
54
- var randomVals = null;
55
- var rvIndex = 0;
56
- var crypto = self.crypto || self.msCrypto;
57
- // eslint-disable-next-line
58
- if (crypto && crypto.getRandomValues && Uint8Array) {
59
- // eslint-disable-next-line
60
- randomVals = crypto.getRandomValues(new Uint8Array(31));
61
- }
62
- var chars = [];
63
- for (var i = 0; i < length; i++) {
64
- chars.push(getRandomValue().toString(16));
65
- }
66
- return chars.join('');
67
- function getRandomValue() {
68
- if (randomVals) {
69
- // same as % 16
70
- return randomVals[rvIndex++] & 15;
71
- } else {
72
- return Math.random() * 16 | 0;
73
- }
74
- }
75
99
  }
@@ -0,0 +1,44 @@
1
+ import crypto from 'crypto';
2
+ import * as uniqueId from './unique-id';
3
+ const getRandomValues = jest.fn(arr => crypto.randomBytes(arr.length));
4
+ afterEach(() => {
5
+ delete global.crypto;
6
+ });
7
+ describe('generateUuid', () => {
8
+ const uuidv4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
9
+ test('should generate a uuidv4 that matches the expected format', () => {
10
+ const id = uniqueId.generateUuid();
11
+ expect(uuidv4Regex.test(id)).toEqual(true);
12
+ });
13
+ test('should support using native crypto library', () => {
14
+ global.crypto = {
15
+ getRandomValues
16
+ };
17
+ const id = uniqueId.generateUuid();
18
+ expect(uuidv4Regex.test(id)).toEqual(true);
19
+ expect(getRandomValues).toHaveBeenCalledTimes(1);
20
+ });
21
+ });
22
+ describe('generateRandomHexString', () => {
23
+ const hexRegex = /^[0-9a-f]{8}$/;
24
+ test('should generate a valid hex string', () => {
25
+ const id = uniqueId.generateRandomHexString(8);
26
+ expect(hexRegex.test(id)).toEqual(true);
27
+ });
28
+ test('should support using native crypto library', () => {
29
+ global.crypto = {
30
+ getRandomValues
31
+ };
32
+ const id = uniqueId.generateRandomHexString(8);
33
+ expect(hexRegex.test(id)).toEqual(true);
34
+ expect(getRandomValues).toHaveBeenCalledTimes(1);
35
+ });
36
+ });
37
+ test('generateSpanId should generate a 16 character hex string', () => {
38
+ const id = uniqueId.generateSpanId();
39
+ expect(/^[0-9a-f]{16}$/.test(id)).toEqual(true);
40
+ });
41
+ test('generateTraceId should generate a 32 character hex string', () => {
42
+ const id = uniqueId.generateTraceId();
43
+ expect(/^[0-9a-f]{32}$/.test(id)).toEqual(true);
44
+ });
@@ -25,43 +25,65 @@ var RESPONSE = 'response';
25
25
  var LOAD_EVENT = 'loadEvent';
26
26
  var DOM_CONTENT_LOAD_EVENT = 'domContentLoadedEvent';
27
27
  export var navTimingValues = [];
28
- export function addPT(offset, pt, v) {
28
+ function getPntType(type) {
29
+ if (typeof type == 'number') return type;
30
+ const types = {
31
+ navigate: undefined,
32
+ reload: 1,
33
+ back_forward: 2,
34
+ prerender: 3
35
+ };
36
+ return types[type];
37
+ }
38
+ export function addPT(offset, pt) {
39
+ let v = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
40
+ let isL1Api = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
41
+ if (!pt) return;
29
42
  v.of = offset;
30
- addRel(offset, offset, v, 'n');
31
- addRel(pt[UNLOAD_EVENT + START], offset, v, 'u');
32
- addRel(pt[REDIRECT + START], offset, v, 'r');
33
- addRel(pt[UNLOAD_EVENT + END], offset, v, 'ue');
34
- addRel(pt[REDIRECT + END], offset, v, 're');
35
- addRel(pt['fetch' + START], offset, v, 'f');
36
- addRel(pt[DOMAIN_LOOKUP + START], offset, v, 'dn');
37
- addRel(pt[DOMAIN_LOOKUP + END], offset, v, 'dne');
38
- addRel(pt['c' + ONNECT + START], offset, v, 'c');
39
- addRel(pt['secureC' + ONNECT + 'ion' + START], offset, v, 's');
40
- addRel(pt['c' + ONNECT + END], offset, v, 'ce');
41
- addRel(pt[REQUEST + START], offset, v, 'rq');
42
- addRel(pt[RESPONSE + START], offset, v, 'rp');
43
- addRel(pt[RESPONSE + END], offset, v, 'rpe');
44
- addRel(pt.domLoading, offset, v, 'dl');
45
- addRel(pt.domInteractive, offset, v, 'di');
46
- addRel(pt[DOM_CONTENT_LOAD_EVENT + START], offset, v, 'ds');
47
- addRel(pt[DOM_CONTENT_LOAD_EVENT + END], offset, v, 'de');
48
- addRel(pt.domComplete, offset, v, 'dc');
49
- addRel(pt[LOAD_EVENT + START], offset, v, 'l');
50
- addRel(pt[LOAD_EVENT + END], offset, v, 'le');
43
+ handleValue(v.of, v, 'n', true);
44
+ handleValue(pt[UNLOAD_EVENT + START], v, 'u', isL1Api);
45
+ handleValue(pt[REDIRECT + START], v, 'r', isL1Api);
46
+ handleValue(pt[UNLOAD_EVENT + END], v, 'ue', isL1Api);
47
+ handleValue(pt[REDIRECT + END], v, 're', isL1Api);
48
+ handleValue(pt['fetch' + START], v, 'f', isL1Api);
49
+ handleValue(pt[DOMAIN_LOOKUP + START], v, 'dn', isL1Api);
50
+ handleValue(pt[DOMAIN_LOOKUP + END], v, 'dne', isL1Api);
51
+ handleValue(pt['c' + ONNECT + START], v, 'c', isL1Api);
52
+ handleValue(pt['secureC' + ONNECT + 'ion' + START], v, 's', isL1Api);
53
+ handleValue(pt['c' + ONNECT + END], v, 'ce', isL1Api);
54
+ handleValue(pt[REQUEST + START], v, 'rq', isL1Api);
55
+ handleValue(pt[RESPONSE + START], v, 'rp', isL1Api);
56
+ handleValue(pt[RESPONSE + END], v, 'rpe', isL1Api);
57
+ handleValue(pt.domLoading, v, 'dl', isL1Api);
58
+ handleValue(pt.domInteractive, v, 'di', isL1Api);
59
+ handleValue(pt[DOM_CONTENT_LOAD_EVENT + START], v, 'ds', isL1Api);
60
+ handleValue(pt[DOM_CONTENT_LOAD_EVENT + END], v, 'de', isL1Api);
61
+ handleValue(pt.domComplete, v, 'dc', isL1Api);
62
+ handleValue(pt[LOAD_EVENT + START], v, 'l', isL1Api);
63
+ handleValue(pt[LOAD_EVENT + END], v, 'le', isL1Api);
51
64
  return v;
52
65
  }
53
66
 
54
67
  // Add Performance Navigation values to the given object
55
68
  export function addPN(pn, v) {
56
- addRel(pn.type, 0, v, 'ty');
57
- addRel(pn.redirectCount, 0, v, 'rc');
69
+ handleValue(getPntType(pn.type), v, 'ty');
70
+ handleValue(pn.redirectCount, v, 'rc');
58
71
  return v;
59
72
  }
60
- export function addRel(value, offset, obj, prop) {
61
- var relativeValue;
73
+ function handleValue(value, obj, prop, isOldApi) {
74
+ /*
75
+ For L2 Timing API, the value will already be a relative-to-previous-document DOMHighResTimeStamp.
76
+ For L1 (deprecated) Timing, the value is an UNIX epoch timestamp, which we will convert to a relative time using our offset.
77
+ PNT.type is reported as undefined, 1, 2, etc -- note that zero-value properties will be recorded as 'undefined', however DEM interprets undefined "types" as "navigate"
78
+ */
62
79
  if (typeof value === 'number' && value > 0) {
63
- relativeValue = Math.max(Math.round(value - offset), 0);
64
- obj[prop] = relativeValue;
80
+ // note that zero-value properties will be recorded as 'undefined'
81
+ if (isOldApi) {
82
+ const offset = obj?.of > 0 ? obj.of : 0; // expect an epoch timestamp, if called by addPT
83
+ value = Math.max(value - offset, 0);
84
+ }
85
+ value = Math.round(value);
86
+ obj[prop] = value;
65
87
  }
66
- navTimingValues.push(relativeValue);
88
+ navTimingValues.push(value);
67
89
  }
@@ -0,0 +1,190 @@
1
+ import { addPT, addPN, navTimingValues } from './nav-timing';
2
+ const offset = 123;
3
+ const testValues = {
4
+ unloadEventStart: 1,
5
+ redirectStart: 2,
6
+ unloadEventEnd: 3,
7
+ redirectEnd: 4,
8
+ fetchStart: 5,
9
+ domainLookupStart: 6,
10
+ domainLookupEnd: 7,
11
+ connectStart: 8,
12
+ secureConnectionStart: 9,
13
+ connectEnd: 10,
14
+ requestStart: 11,
15
+ responseStart: 12,
16
+ responseEnd: 13,
17
+ domLoading: 14,
18
+ domInteractive: 15,
19
+ domContentLoadedEventStart: 16,
20
+ domContentLoadedEventEnd: 17,
21
+ domComplete: 18,
22
+ loadEventStart: 19,
23
+ loadEventEnd: 20,
24
+ type: 'reload',
25
+ redirectCount: 22
26
+ };
27
+ const legacyTestValues = {
28
+ unloadEventStart: offset + 1,
29
+ redirectStart: offset + 2,
30
+ unloadEventEnd: offset + 3,
31
+ redirectEnd: offset + 4,
32
+ fetchStart: offset + 5,
33
+ domainLookupStart: offset + 6,
34
+ domainLookupEnd: offset + 7,
35
+ connectStart: offset + 8,
36
+ secureConnectionStart: offset + 9,
37
+ connectEnd: offset + 10,
38
+ requestStart: offset + 11,
39
+ responseStart: offset + 12,
40
+ responseEnd: offset + 13,
41
+ domLoading: offset + 14,
42
+ domInteractive: offset + 15,
43
+ domContentLoadedEventStart: offset + 16,
44
+ domContentLoadedEventEnd: offset + 17,
45
+ domComplete: offset + 18,
46
+ loadEventStart: offset + 19,
47
+ loadEventEnd: offset + 20,
48
+ type: 'reload',
49
+ redirectCount: offset + 22
50
+ };
51
+ const expectedPT = {
52
+ of: offset,
53
+ n: 0,
54
+ u: 1,
55
+ r: 2,
56
+ ue: 3,
57
+ re: 4,
58
+ f: 5,
59
+ dn: 6,
60
+ dne: 7,
61
+ c: 8,
62
+ s: 9,
63
+ ce: 10,
64
+ rq: 11,
65
+ rp: 12,
66
+ rpe: 13,
67
+ dl: 14,
68
+ di: 15,
69
+ ds: 16,
70
+ de: 17,
71
+ dc: 18,
72
+ l: 19,
73
+ le: 20
74
+ };
75
+ const expectedPN = {
76
+ ty: 1,
77
+ rc: 22
78
+ };
79
+ describe('addPT()', () => {
80
+ test('an output object is populated with valid values', () => {
81
+ const output = addPT(offset, testValues, {});
82
+ expect(output).toEqual(expectedPT);
83
+ });
84
+ test('an object with invalid values is handled', () => {
85
+ const output = addPT(offset, {
86
+ ...testValues,
87
+ invalidValue: 'test'
88
+ }, {});
89
+ expect(output).toEqual(expectedPT);
90
+ const output2 = addPT(offset, {
91
+ ...testValues,
92
+ loadEventEnd: -1
93
+ }, {});
94
+ let expected = {
95
+ ...expectedPT
96
+ };
97
+ delete expected.le;
98
+ expect(output2).toEqual(expected);
99
+ const output3 = addPT(offset, {
100
+ ...testValues,
101
+ loadEventEnd: 'test'
102
+ }, {});
103
+ expected = {
104
+ ...expectedPT
105
+ };
106
+ delete expected.le;
107
+ expect(output3).toEqual(expected);
108
+ const output4 = addPT(offset, {
109
+ ...testValues,
110
+ loadEventEnd: null
111
+ }, {});
112
+ expected = {
113
+ ...expectedPT
114
+ };
115
+ delete expected.le;
116
+ expect(output4).toEqual(expected);
117
+ const legacyoutput = addPT(offset, {
118
+ ...legacyTestValues,
119
+ invalidValue: 'test'
120
+ }, {}, true);
121
+ expect(legacyoutput).toEqual(expectedPT);
122
+ const legacyoutput2 = addPT(offset, {
123
+ ...legacyTestValues,
124
+ loadEventEnd: -1
125
+ }, {}, true);
126
+ let legacyexpected = {
127
+ ...expectedPT
128
+ };
129
+ delete legacyexpected.le;
130
+ expect(legacyoutput2).toEqual(expected);
131
+ const legacyoutput3 = addPT(offset, {
132
+ ...legacyTestValues,
133
+ loadEventEnd: 'test'
134
+ }, {}, true);
135
+ legacyexpected = {
136
+ ...expectedPT
137
+ };
138
+ delete legacyexpected.le;
139
+ expect(legacyoutput3).toEqual(legacyexpected);
140
+ const legacyoutput4 = addPT(offset, {
141
+ ...legacyTestValues,
142
+ loadEventEnd: null
143
+ }, {}, true);
144
+ legacyexpected = {
145
+ ...expectedPT
146
+ };
147
+ delete legacyexpected.le;
148
+ expect(legacyoutput4).toEqual(legacyexpected);
149
+ });
150
+ test('rounds values to integers', () => {
151
+ const output = addPT(offset, {
152
+ unloadEventStart: 3.14159
153
+ }, {});
154
+ expect(output.u).toEqual(3);
155
+ const legacyoutput = addPT(0, {
156
+ unloadEventStart: 3.14159
157
+ }, {}, true);
158
+ expect(legacyoutput.u).toEqual(3);
159
+ });
160
+ test('adds entries to navTimingValues', () => {
161
+ const beforeLength = navTimingValues.length;
162
+ addPT(offset, {
163
+ testValues
164
+ }, {});
165
+ const afterLength = navTimingValues.length;
166
+ expect(afterLength - beforeLength).toEqual(21); // 20 + value of n
167
+
168
+ const legacybeforeLength = navTimingValues.length;
169
+ addPT(offset, {
170
+ legacyTestValues
171
+ }, {}, true);
172
+ const legacyafterLength = navTimingValues.length;
173
+ expect(legacyafterLength - legacybeforeLength).toEqual(21); // 20 + value of n
174
+ });
175
+ });
176
+
177
+ describe('addPN()', () => {
178
+ test('an output object is populated with valid values', () => {
179
+ const output = addPN(testValues, {});
180
+ expect(output).toEqual(expectedPN);
181
+ });
182
+ test('adds entries to navTimingValues', () => {
183
+ const beforeLength = navTimingValues.length;
184
+ addPN(offset, {
185
+ testValues
186
+ }, {});
187
+ const afterLength = navTimingValues.length;
188
+ expect(afterLength - beforeLength).toEqual(2);
189
+ });
190
+ });
@@ -0,0 +1,7 @@
1
+ import { cleanURL } from './clean-url';
2
+ test.each([['http://domain.com/path?query=5', 'http://domain.com/path'], ['http://domain.com/path#fragment', 'http://domain.com/path'], ['http://domain.com/path?query=5#fragment', 'http://domain.com/path'], ['http://domain.com/path?query=5?dumb#fragment', 'http://domain.com/path'], ['http://domain.com/path?query=5#fragment#dumb', 'http://domain.com/path'], ['http://domain.com/path?query=5#fragment#dumb?additional_query', 'http://domain.com/path'], ['http://domain.com/path?query=5#fragment/silly/dumber#dumbest?additional_query=silly#what_is_this_even', 'http://domain.com/path']])('cleanURL should remove hash', (input, expected) => {
3
+ expect(cleanURL(input)).toEqual(expected);
4
+ });
5
+ test.each([['http://domain.com/path?query=5', 'http://domain.com/path'], ['http://domain.com/path#fragment', 'http://domain.com/path#fragment'], ['http://domain.com/path?query=5#fragment', 'http://domain.com/path#fragment'], ['http://domain.com/path?query=5?dumb#fragment', 'http://domain.com/path#fragment'], ['http://domain.com/path?query=5#fragment#dumb', 'http://domain.com/path#fragment#dumb'], ['http://domain.com/path?query=5#fragment#dumb?additional_query', 'http://domain.com/path#fragment#dumb'], ['http://domain.com/path?query=5#fragment/silly/dumber#dumbest?additional_query=silly#what_is_this_even', 'http://domain.com/path#fragment/silly/dumber#dumbest']])('cleanURL should retain hash if second argument is true', (input, expected) => {
6
+ expect(cleanURL(input, true)).toEqual(expected);
7
+ });
@@ -0,0 +1,70 @@
1
+ import * as encode from './encode';
2
+ describe('query string encoding', () => {
3
+ test('escapes string components except safe characters', () => {
4
+ const input = 'Asdf:, :, /@$;';
5
+ const expected = 'Asdf:,%20:,%20/@$;';
6
+ expect(encode.qs(input)).toEqual(expected);
7
+ });
8
+ test('null and undefined value returns \'null\'', () => {
9
+ expect(encode.qs(null)).toEqual('null');
10
+ expect(encode.qs(undefined)).toEqual('null');
11
+ });
12
+ });
13
+ describe('fromArray encoding', () => {
14
+ test('cuts cleanly at end of byte', () => {
15
+ const input = ['a', 'b', 'c'];
16
+ const expected = 'ab';
17
+ expect(encode.fromArray(input, 2)).toEqual(expected);
18
+ });
19
+ test('fall back to largest whole chunk', () => {
20
+ const input = ['aa', 'bb', 'cc'];
21
+ const expected = 'aabb';
22
+ expect(encode.fromArray(input, 5)).toEqual(expected);
23
+ });
24
+ });
25
+ describe('object encoding', () => {
26
+ test('cuts cleanly at end of byte', () => {
27
+ const input = {
28
+ foo: [1, 2, 3]
29
+ };
30
+ const expected = '&foo=%5B1,2%5D';
31
+ expect(encode.obj(input, 12)).toEqual(expected);
32
+ });
33
+ test('fall back to largest whole chunk', () => {
34
+ const input = {
35
+ bar: ['a', 'b', 'c']
36
+ };
37
+ const expected = '&bar=%5B%22a%22,%22b%22%5D';
38
+ expect(encode.obj(input, 30)).toEqual(expected);
39
+ });
40
+ test('handles circular objects', () => {
41
+ const circular = {};
42
+ circular.circular = circular;
43
+ const input = {
44
+ bar: ['a', circular, 'c']
45
+ };
46
+ const expected = '&bar=%5B%22a%22,%7B%7D,%22c%22%5D';
47
+ expect(encode.obj(input, 1000)).toEqual(expected);
48
+ });
49
+ test('handles circular arrays', () => {
50
+ const circular = [];
51
+ circular.push(circular);
52
+ const input = {
53
+ bar: ['a', circular, 'c']
54
+ };
55
+ const expected = '&bar=%5B%22a%22,%5Bnull%5D,%22c%22%5D';
56
+ expect(encode.obj(input, 1000)).toEqual(expected);
57
+ });
58
+ });
59
+ describe('encode key value pairs as query params', () => {
60
+ test('ignores input when value is null or undefined', () => {
61
+ expect(encode.param('foo', null)).toEqual('');
62
+ expect(encode.param('foo', undefined)).toEqual('');
63
+ });
64
+ test('encodes key value pair correctly', () => {
65
+ expect(encode.param('foo', 'bar')).toEqual('&foo=bar');
66
+ });
67
+ test('ignores input when value is not a string', () => {
68
+ expect(encode.param('foo', {})).toEqual('');
69
+ });
70
+ });
@@ -3,6 +3,10 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
+ /**
7
+ * This method only exists to support testing in JIL and can be removed once tests are migrated to WDIO.
8
+ * @returns global scope location
9
+ */
6
10
  export function getLocation() {
7
11
  return '' + location;
8
12
  }
@@ -0,0 +1,11 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import { getLocation } from './location';
3
+ test('should always return a string', () => {
4
+ jest.spyOn(window, 'location', 'get').mockReturnValue({});
5
+ expect(typeof getLocation()).toEqual('string');
6
+ });
7
+ test('should return window location', () => {
8
+ const expected = faker.internet.url();
9
+ jest.spyOn(window, 'location', 'get').mockReturnValue(expected);
10
+ expect(getLocation()).toEqual(expected);
11
+ });