@newrelic/browser-agent 1.233.1 → 1.235.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 (273) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/common/constants/env.cdn.js +1 -1
  3. package/dist/cjs/common/constants/env.npm.js +1 -1
  4. package/dist/cjs/common/constants/shared-channel.js +19 -0
  5. package/dist/cjs/common/event-emitter/contextual-ee.test.js +10 -10
  6. package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  7. package/dist/cjs/common/harvest/harvest-scheduler.js +21 -5
  8. package/dist/cjs/common/harvest/harvest.component-test.js +224 -0
  9. package/dist/cjs/common/harvest/harvest.js +4 -11
  10. package/dist/cjs/common/session/{session-entity.test.js → session-entity.component-test.js} +79 -42
  11. package/dist/cjs/common/session/session-entity.js +19 -11
  12. package/dist/cjs/common/timer/interaction-timer.js +1 -1
  13. package/dist/cjs/common/url/canonicalize-url.test.js +26 -30
  14. package/dist/cjs/common/url/encode.js +2 -2
  15. package/dist/cjs/common/util/console.test.js +30 -0
  16. package/dist/cjs/common/util/data-size.test.js +37 -20
  17. package/dist/cjs/common/util/feature-flags.js +23 -12
  18. package/dist/cjs/common/util/feature-flags.test.js +84 -0
  19. package/dist/cjs/common/util/get-or-set.js +8 -1
  20. package/dist/cjs/common/util/get-or-set.test.js +47 -0
  21. package/dist/cjs/common/util/global-scope.js +1 -32
  22. package/dist/cjs/common/util/global-scope.test.js +72 -0
  23. package/dist/cjs/common/util/obfuscate.component-test.js +129 -0
  24. package/dist/cjs/common/util/obfuscate.js +2 -2
  25. package/dist/cjs/common/util/stringify.test.js +48 -0
  26. package/dist/cjs/common/util/submit-data.js +18 -18
  27. package/dist/cjs/common/util/submit-data.test.js +245 -0
  28. package/dist/cjs/common/util/traverse.js +19 -27
  29. package/dist/cjs/common/util/traverse.test.js +44 -0
  30. package/dist/cjs/common/wrap/wrap-raf.js +1 -1
  31. package/dist/cjs/common/wrap/wrap-timer.js +1 -1
  32. package/dist/cjs/features/jserrors/aggregate/index.js +4 -0
  33. package/dist/cjs/features/jserrors/instrument/index.js +2 -15
  34. package/dist/cjs/features/metrics/aggregate/endpoint-map.js +14 -0
  35. package/dist/cjs/features/metrics/aggregate/index.js +3 -2
  36. package/dist/cjs/features/metrics/instrument/index.js +0 -2
  37. package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
  38. package/dist/cjs/features/session_replay/aggregate/index.component-test.js +457 -0
  39. package/dist/cjs/features/session_replay/aggregate/index.js +99 -82
  40. package/dist/cjs/features/session_replay/replay-mode.js +28 -0
  41. package/dist/cjs/features/session_trace/aggregate/index.js +222 -99
  42. package/dist/cjs/features/session_trace/constants.js +1 -3
  43. package/dist/cjs/features/session_trace/instrument/index.js +0 -16
  44. package/dist/cjs/features/spa/constants.js +0 -1
  45. package/dist/cjs/features/utils/agent-session.js +20 -36
  46. package/dist/cjs/features/utils/agent-session.test.js +211 -0
  47. package/dist/cjs/features/utils/aggregate-base.js +7 -12
  48. package/dist/cjs/features/utils/aggregate-base.test.js +110 -0
  49. package/dist/cjs/features/utils/feature-base.test.js +42 -0
  50. package/dist/cjs/features/utils/handler-cache.js +28 -23
  51. package/dist/cjs/features/utils/handler-cache.test.js +53 -0
  52. package/dist/cjs/features/utils/instrument-base.js +58 -39
  53. package/dist/cjs/features/utils/instrument-base.test.js +179 -0
  54. package/dist/cjs/features/utils/lazy-feature-loader.test.js +30 -0
  55. package/dist/cjs/loaders/agent.js +0 -1
  56. package/dist/cjs/loaders/api/api.js +1 -1
  57. package/dist/cjs/loaders/configure/configure.js +0 -1
  58. package/dist/cjs/loaders/features/featureDependencies.js +2 -0
  59. package/dist/esm/common/constants/env.cdn.js +1 -1
  60. package/dist/esm/common/constants/env.npm.js +1 -1
  61. package/dist/esm/common/constants/shared-channel.js +12 -0
  62. package/dist/esm/common/event-emitter/contextual-ee.test.js +10 -10
  63. package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  64. package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
  65. package/dist/esm/common/harvest/harvest.component-test.js +222 -0
  66. package/dist/esm/common/harvest/harvest.js +4 -11
  67. package/dist/esm/common/session/{session-entity.test.js → session-entity.component-test.js} +77 -40
  68. package/dist/esm/common/session/session-entity.js +17 -11
  69. package/dist/esm/common/timer/interaction-timer.js +1 -1
  70. package/dist/esm/common/url/canonicalize-url.test.js +25 -29
  71. package/dist/esm/common/url/encode.js +2 -2
  72. package/dist/esm/common/util/console.test.js +28 -0
  73. package/dist/esm/common/util/data-size.test.js +35 -20
  74. package/dist/esm/common/util/feature-flags.js +23 -12
  75. package/dist/esm/common/util/feature-flags.test.js +80 -0
  76. package/dist/esm/common/util/get-or-set.js +8 -1
  77. package/dist/esm/common/util/get-or-set.test.js +45 -0
  78. package/dist/esm/common/util/global-scope.js +1 -29
  79. package/dist/esm/common/util/global-scope.test.js +70 -0
  80. package/dist/esm/common/util/obfuscate.component-test.js +125 -0
  81. package/dist/esm/common/util/obfuscate.js +2 -2
  82. package/dist/esm/common/util/stringify.test.js +46 -0
  83. package/dist/esm/common/util/submit-data.js +18 -18
  84. package/dist/esm/common/util/submit-data.test.js +241 -0
  85. package/dist/esm/common/util/traverse.js +19 -27
  86. package/dist/esm/common/util/traverse.test.js +42 -0
  87. package/dist/esm/common/wrap/wrap-raf.js +1 -1
  88. package/dist/esm/common/wrap/wrap-timer.js +1 -1
  89. package/dist/esm/features/jserrors/aggregate/index.js +4 -0
  90. package/dist/esm/features/jserrors/instrument/index.js +2 -15
  91. package/dist/esm/features/metrics/aggregate/endpoint-map.js +7 -0
  92. package/dist/esm/features/metrics/aggregate/index.js +3 -2
  93. package/dist/esm/features/metrics/instrument/index.js +0 -2
  94. package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
  95. package/dist/esm/features/session_replay/aggregate/index.component-test.js +453 -0
  96. package/dist/esm/features/session_replay/aggregate/index.js +92 -78
  97. package/dist/esm/features/session_replay/replay-mode.js +23 -0
  98. package/dist/esm/features/session_trace/aggregate/index.js +223 -100
  99. package/dist/esm/features/session_trace/constants.js +0 -1
  100. package/dist/esm/features/session_trace/instrument/index.js +1 -17
  101. package/dist/esm/features/spa/constants.js +0 -1
  102. package/dist/esm/features/utils/agent-session.js +21 -37
  103. package/dist/esm/features/utils/agent-session.test.js +207 -0
  104. package/dist/esm/features/utils/aggregate-base.js +7 -12
  105. package/dist/esm/features/utils/aggregate-base.test.js +108 -0
  106. package/dist/esm/features/utils/feature-base.test.js +40 -0
  107. package/dist/esm/features/utils/handler-cache.js +28 -23
  108. package/dist/esm/features/utils/handler-cache.test.js +51 -0
  109. package/dist/esm/features/utils/instrument-base.js +58 -39
  110. package/dist/esm/features/utils/instrument-base.test.js +175 -0
  111. package/dist/esm/features/utils/lazy-feature-loader.test.js +29 -0
  112. package/dist/esm/loaders/agent.js +0 -1
  113. package/dist/esm/loaders/api/api.js +2 -2
  114. package/dist/esm/loaders/configure/configure.js +0 -1
  115. package/dist/esm/loaders/features/featureDependencies.js +2 -0
  116. package/dist/types/common/config/state/init.d.ts.map +1 -1
  117. package/dist/types/common/constants/shared-channel.d.ts +5 -0
  118. package/dist/types/common/constants/shared-channel.d.ts.map +1 -0
  119. package/dist/types/common/context/shared-context.d.ts.map +1 -1
  120. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +2 -0
  121. package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +1 -0
  122. package/dist/types/common/harvest/harvest-scheduler.d.ts +4 -0
  123. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  124. package/dist/types/common/harvest/harvest.component-test.d.ts +2 -0
  125. package/dist/types/common/harvest/harvest.component-test.d.ts.map +1 -0
  126. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  127. package/dist/types/common/session/session-entity.component-test.d.ts +2 -0
  128. package/dist/types/common/session/session-entity.component-test.d.ts.map +1 -0
  129. package/dist/types/common/session/session-entity.d.ts +9 -5
  130. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  131. package/dist/types/common/timer/interaction-timer.component-test.d.ts +2 -0
  132. package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +1 -0
  133. package/dist/types/common/timer/timer.d.ts.map +1 -1
  134. package/dist/types/common/url/encode.component-test.d.ts +2 -0
  135. package/dist/types/common/url/encode.component-test.d.ts.map +1 -0
  136. package/dist/types/common/url/protocol.component-test.d.ts +2 -0
  137. package/dist/types/common/url/protocol.component-test.d.ts.map +1 -0
  138. package/dist/types/common/util/feature-flags.d.ts +1 -0
  139. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  140. package/dist/types/common/util/get-or-set.d.ts +9 -1
  141. package/dist/types/common/util/get-or-set.d.ts.map +1 -1
  142. package/dist/types/common/util/global-scope.d.ts +0 -9
  143. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  144. package/dist/types/common/util/obfuscate.component-test.d.ts +2 -0
  145. package/dist/types/common/util/obfuscate.component-test.d.ts.map +1 -0
  146. package/dist/types/common/util/submit-data.d.ts +14 -10
  147. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  148. package/dist/types/common/util/traverse.d.ts +10 -1
  149. package/dist/types/common/util/traverse.d.ts.map +1 -1
  150. package/dist/types/common/window/nreum.d.ts.map +1 -1
  151. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -0
  152. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  153. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +8 -0
  154. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
  155. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  156. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
  157. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  158. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  160. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +2 -0
  161. package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +1 -0
  162. package/dist/types/features/session_replay/aggregate/index.d.ts +14 -5
  163. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  164. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  165. package/dist/types/features/session_replay/replay-mode.d.ts +9 -0
  166. package/dist/types/features/session_replay/replay-mode.d.ts.map +1 -0
  167. package/dist/types/features/session_trace/aggregate/index.d.ts +21 -3
  168. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  169. package/dist/types/features/session_trace/constants.d.ts +0 -1
  170. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  171. package/dist/types/features/session_trace/instrument/index.d.ts +0 -2
  172. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  173. package/dist/types/features/spa/constants.d.ts.map +1 -1
  174. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  175. package/dist/types/features/utils/aggregate-base.d.ts +6 -1
  176. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  177. package/dist/types/features/utils/handler-cache.d.ts +12 -11
  178. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  179. package/dist/types/features/utils/instrument-base.d.ts +17 -1
  180. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  181. package/dist/types/loaders/agent.d.ts.map +1 -1
  182. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  183. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  184. package/package.json +14 -8
  185. package/src/common/config/state/init.js +0 -1
  186. package/src/common/constants/shared-channel.js +13 -0
  187. package/src/common/context/shared-context.js +0 -1
  188. package/src/common/event-emitter/contextual-ee.test.js +10 -10
  189. package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
  190. package/src/common/harvest/harvest-scheduler.js +17 -6
  191. package/src/common/harvest/harvest.component-test.js +169 -0
  192. package/src/common/harvest/harvest.js +5 -9
  193. package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -48
  194. package/src/common/session/session-entity.js +15 -12
  195. package/src/common/timer/interaction-timer.js +1 -1
  196. package/src/common/timer/timer.js +0 -1
  197. package/src/common/url/canonicalize-url.test.js +32 -21
  198. package/src/common/url/encode.js +2 -2
  199. package/src/common/util/console.test.js +34 -0
  200. package/src/common/util/data-size.test.js +27 -20
  201. package/src/common/util/feature-flags.js +24 -12
  202. package/src/common/util/feature-flags.test.js +98 -0
  203. package/src/common/util/get-or-set.js +8 -1
  204. package/src/common/util/get-or-set.test.js +58 -0
  205. package/src/common/util/global-scope.js +0 -26
  206. package/src/common/util/global-scope.test.js +87 -0
  207. package/src/common/util/obfuscate.component-test.js +173 -0
  208. package/src/common/util/obfuscate.js +2 -2
  209. package/src/common/util/stringify.test.js +49 -0
  210. package/src/common/util/submit-data.js +18 -19
  211. package/src/common/util/submit-data.test.js +226 -0
  212. package/src/common/util/traverse.js +18 -27
  213. package/src/common/util/traverse.test.js +50 -0
  214. package/src/common/window/nreum.js +0 -1
  215. package/src/common/wrap/wrap-raf.js +1 -1
  216. package/src/common/wrap/wrap-timer.js +1 -1
  217. package/src/features/jserrors/aggregate/index.js +5 -0
  218. package/src/features/jserrors/instrument/index.js +2 -15
  219. package/src/features/metrics/aggregate/endpoint-map.js +7 -0
  220. package/src/features/metrics/aggregate/index.js +3 -2
  221. package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
  222. package/src/features/metrics/instrument/index.js +0 -2
  223. package/src/features/page_view_event/aggregate/index.js +48 -51
  224. package/src/features/page_view_event/instrument/index.js +0 -1
  225. package/src/features/session_replay/aggregate/index.component-test.js +368 -0
  226. package/src/features/session_replay/aggregate/index.js +96 -71
  227. package/src/features/session_replay/instrument/index.js +0 -1
  228. package/src/features/session_replay/replay-mode.js +23 -0
  229. package/src/features/session_trace/aggregate/index.js +198 -79
  230. package/src/features/session_trace/constants.js +0 -1
  231. package/src/features/session_trace/instrument/index.js +2 -19
  232. package/src/features/spa/constants.js +0 -1
  233. package/src/features/utils/agent-session.js +22 -34
  234. package/src/features/utils/agent-session.test.js +194 -0
  235. package/src/features/utils/aggregate-base.js +12 -9
  236. package/src/features/utils/aggregate-base.test.js +122 -0
  237. package/src/features/utils/feature-base.test.js +45 -0
  238. package/src/features/utils/handler-cache.js +29 -24
  239. package/src/features/utils/handler-cache.test.js +72 -0
  240. package/src/features/utils/instrument-base.js +45 -29
  241. package/src/features/utils/instrument-base.test.js +190 -0
  242. package/src/features/utils/lazy-feature-loader.test.js +37 -0
  243. package/src/loaders/agent.js +0 -1
  244. package/src/loaders/api/api.js +2 -2
  245. package/src/loaders/configure/configure.js +0 -1
  246. package/src/loaders/features/featureDependencies.js +2 -0
  247. package/dist/cjs/common/storage/local-memory.js +0 -35
  248. package/dist/cjs/common/storage/local-memory.test.js +0 -20
  249. package/dist/cjs/common/util/s-hash.js +0 -19
  250. package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
  251. package/dist/esm/common/storage/local-memory.js +0 -28
  252. package/dist/esm/common/storage/local-memory.test.js +0 -18
  253. package/dist/esm/common/util/s-hash.js +0 -13
  254. package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
  255. package/dist/types/common/storage/local-memory.d.ts +0 -8
  256. package/dist/types/common/storage/local-memory.d.ts.map +0 -1
  257. package/dist/types/common/util/s-hash.d.ts +0 -2
  258. package/dist/types/common/util/s-hash.d.ts.map +0 -1
  259. package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
  260. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +0 -1
  261. package/src/common/storage/local-memory.js +0 -30
  262. package/src/common/storage/local-memory.test.js +0 -19
  263. package/src/common/util/s-hash.js +0 -14
  264. package/src/features/metrics/instrument/workers-helper.js +0 -113
  265. /package/dist/cjs/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  266. /package/dist/cjs/common/url/{encode.test.js → encode.component-test.js} +0 -0
  267. /package/dist/cjs/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  268. /package/dist/esm/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  269. /package/dist/esm/common/url/{encode.test.js → encode.component-test.js} +0 -0
  270. /package/dist/esm/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
  271. /package/src/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
  272. /package/src/common/url/{encode.test.js → encode.component-test.js} +0 -0
  273. /package/src/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
@@ -0,0 +1,453 @@
1
+ import { Aggregate as SessionReplayAgg, AVG_COMPRESSION, MAX_PAYLOAD_SIZE, IDEAL_PAYLOAD_SIZE } from '.';
2
+ import { Aggregator } from '../../../common/aggregate/aggregator';
3
+ import { SESSION_EVENTS, SessionEntity, MODE } from '../../../common/session/session-entity';
4
+ import { setConfiguration } from '../../../common/config/config';
5
+ import { configure } from '../../../loaders/configure/configure';
6
+ class LocalMemory {
7
+ constructor() {
8
+ let initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
9
+ this.state = initialState;
10
+ }
11
+ get(key) {
12
+ try {
13
+ return this.state[key];
14
+ } catch (err) {
15
+ return '';
16
+ }
17
+ }
18
+ set(key, value) {
19
+ try {
20
+ if (value === undefined || value === null) return this.remove(key);
21
+ this.state[key] = value;
22
+ } catch (err) {
23
+ return;
24
+ }
25
+ }
26
+ remove(key) {
27
+ try {
28
+ delete this.state[key];
29
+ } catch (err) {
30
+ return;
31
+ }
32
+ }
33
+ }
34
+ let sr, session;
35
+ const agentIdentifier = 'abcd';
36
+ const info = {
37
+ licenseKey: 1234,
38
+ applicationID: 9876
39
+ };
40
+ const init = {
41
+ session_replay: {
42
+ enabled: true,
43
+ sampleRate: 1,
44
+ errorSampleRate: 0
45
+ }
46
+ };
47
+ describe('Session Replay', () => {
48
+ beforeEach(async () => {
49
+ primeSessionAndReplay();
50
+ });
51
+ afterEach(async () => {
52
+ sr.abort();
53
+ jest.clearAllMocks();
54
+ });
55
+ describe('Session Replay Session Behavior', () => {
56
+ test('When Session Ends', async () => {
57
+ const xhrMockClass = () => ({
58
+ open: jest.fn(),
59
+ send: jest.fn(),
60
+ setRequestHeader: jest.fn(),
61
+ addEventListener: jest.fn()
62
+ });
63
+ global.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
64
+ setConfiguration(agentIdentifier, {
65
+ ...init
66
+ });
67
+ sr.ee.emit('rumresp-sr', [true]);
68
+ await wait(1);
69
+ expect(sr.initialized).toBeTruthy();
70
+ expect(sr.recording).toBeTruthy();
71
+ sr.ee.emit(SESSION_EVENTS.RESET);
72
+ expect(global.XMLHttpRequest).toHaveBeenCalled();
73
+ expect(sr.recording).toBeFalsy();
74
+ expect(sr.blocked).toBeTruthy();
75
+ });
76
+ test('When Session Is Paused/Resumed', async () => {
77
+ setConfiguration(agentIdentifier, {
78
+ ...init
79
+ });
80
+ sr.ee.emit('rumresp-sr', [true]);
81
+ await wait(1);
82
+ expect(sr.initialized).toBeTruthy();
83
+ expect(sr.recording).toBeTruthy();
84
+ sr.ee.emit(SESSION_EVENTS.PAUSE);
85
+ expect(sr.recording).toBeFalsy();
86
+ sr.ee.emit(SESSION_EVENTS.RESUME);
87
+ expect(sr.recording).toBeTruthy();
88
+ });
89
+ test('Session SR mode matches SR mode -- FULL', async () => {
90
+ setConfiguration(agentIdentifier, {
91
+ ...init
92
+ });
93
+ sr.ee.emit('rumresp-sr', [true]);
94
+ await wait(1);
95
+ expect(session.state.sessionReplay).toEqual(sr.mode);
96
+ });
97
+ test('Session SR mode matches SR mode -- ERROR', async () => {
98
+ setConfiguration(agentIdentifier, {
99
+ session_replay: {
100
+ sampleRate: 0,
101
+ errorSampleRate: 1
102
+ }
103
+ });
104
+ sr.ee.emit('rumresp-sr', [true]);
105
+ await wait(1);
106
+ expect(session.state.sessionReplay).toEqual(sr.mode);
107
+ return;
108
+ });
109
+ test('Session SR mode matches SR mode -- OFF', async () => {
110
+ setConfiguration(agentIdentifier, {
111
+ session_replay: {
112
+ sampleRate: 0,
113
+ errorSampleRate: 0
114
+ }
115
+ });
116
+ sr.ee.emit('rumresp-sr', [true]);
117
+ await wait(1);
118
+ expect(session.state.sessionReplay).toEqual(sr.mode);
119
+ return;
120
+ });
121
+ });
122
+ describe('Session Replay Initialization Behavior', () => {
123
+ test('Waits for SR', async () => {
124
+ setConfiguration(agentIdentifier, {
125
+ ...init
126
+ });
127
+ // do not emit sr flag
128
+ await wait(1000);
129
+ expect(sr.initialized).toEqual(false);
130
+ expect(sr.recording).toEqual(false);
131
+
132
+ // emit a false flag
133
+ sr.ee.emit('rumresp-sr', [false]);
134
+ await wait(1);
135
+ expect(sr.initialized).toEqual(true);
136
+ expect(sr.recording).toEqual(false);
137
+ return;
138
+ });
139
+ test('Does not run if cookies_enabled is false', async () => {
140
+ setConfiguration(agentIdentifier, {
141
+ ...init,
142
+ privacy: {
143
+ cookies_enabled: false
144
+ }
145
+ });
146
+ sr = new SessionReplayAgg(agentIdentifier, new Aggregator({}));
147
+ sr.ee.emit('rumresp-sr', [true]);
148
+ await wait(1);
149
+ expect(sr.initialized).toEqual(false);
150
+ expect(sr.recording).toEqual(false);
151
+ return;
152
+ });
153
+ test('Does not run if session_trace is disabled', async () => {
154
+ setConfiguration(agentIdentifier, {
155
+ ...init,
156
+ session_trace: {
157
+ enabled: false
158
+ }
159
+ });
160
+ sr = new SessionReplayAgg(agentIdentifier, new Aggregator({}));
161
+ sr.ee.emit('rumresp-sr', [true]);
162
+ await wait(1);
163
+ expect(sr.initialized).toEqual(false);
164
+ expect(sr.recording).toEqual(false);
165
+ return;
166
+ });
167
+ });
168
+ describe('Session Replay Sample -> Mode Behaviors', () => {
169
+ test('New Session -- Full 1 Error 1 === FULL', async () => {
170
+ setConfiguration(agentIdentifier, {
171
+ session_replay: {
172
+ errorSampleRate: 1,
173
+ sampleRate: 1
174
+ }
175
+ });
176
+ sr.ee.emit('rumresp-sr', [true]);
177
+ await wait(1);
178
+ expect(sr.mode).toEqual(MODE.FULL);
179
+ return;
180
+ });
181
+ test('New Session -- Full 1 Error 0 === FULL', async () => {
182
+ setConfiguration(agentIdentifier, {
183
+ session_replay: {
184
+ errorSampleRate: 0,
185
+ sampleRate: 1
186
+ }
187
+ });
188
+ sr.ee.emit('rumresp-sr', [true]);
189
+ await wait(1);
190
+ expect(sr.mode).toEqual(MODE.FULL);
191
+ return;
192
+ });
193
+ test('New Session -- Full 0 Error 1 === ERROR', async () => {
194
+ setConfiguration(agentIdentifier, {
195
+ session_replay: {
196
+ errorSampleRate: 1,
197
+ sampleRate: 0
198
+ }
199
+ });
200
+ sr.ee.emit('rumresp-sr', [true]);
201
+ await wait(1);
202
+ expect(sr.mode).toEqual(MODE.ERROR);
203
+ return;
204
+ });
205
+ test('New Session -- Full 0 Error 0 === OFF', async () => {
206
+ setConfiguration(agentIdentifier, {
207
+ session_replay: {
208
+ errorSampleRate: 0,
209
+ sampleRate: 0
210
+ }
211
+ });
212
+ sr.ee.emit('rumresp-sr', [true]);
213
+ await wait(1);
214
+ expect(sr.mode).toEqual(MODE.OFF);
215
+ return;
216
+ });
217
+ test('Existing Session -- Should inherit mode from session entity and ignore samples', async () => {
218
+ const storage = new LocalMemory({
219
+ NRBA_SESSION: {
220
+ value: 'abcdefghijklmnop',
221
+ expiresAt: Date.now() + 10000,
222
+ inactiveAt: Date.now() + 10000,
223
+ updatedAt: Date.now(),
224
+ sessionReplay: MODE.FULL,
225
+ sessionTraceMode: MODE.FULL,
226
+ custom: {}
227
+ }
228
+ });
229
+ session = new SessionEntity({
230
+ agentIdentifier,
231
+ key: 'SESSION',
232
+ storage
233
+ });
234
+ expect(session.isNew).toBeFalsy();
235
+ primeSessionAndReplay(session);
236
+ // configure to get "error" sample ---> but should inherit FULL from session manager
237
+ setConfiguration(agentIdentifier, {
238
+ session_replay: {
239
+ errorSampleRate: 1,
240
+ sampleRate: 0
241
+ }
242
+ });
243
+ sr.ee.emit('rumresp-sr', [true]);
244
+ await wait(1);
245
+ expect(sr.mode).toEqual(MODE.FULL);
246
+ return;
247
+ });
248
+ });
249
+ describe('Session Replay Error Mode Behaviors', () => {
250
+ test('An error BEFORE rrweb import starts running in FULL from beginning', async () => {
251
+ setConfiguration(agentIdentifier, {
252
+ session_replay: {
253
+ errorSampleRate: 1,
254
+ sampleRate: 0
255
+ }
256
+ });
257
+ sr.ee.emit('errorAgg');
258
+ sr.ee.emit('rumresp-sr', [true]);
259
+ await wait(1);
260
+ expect(sr.mode).toEqual(MODE.FULL);
261
+ expect(sr.scheduler.started).toEqual(true);
262
+ return;
263
+ });
264
+ test('An error AFTER rrweb import changes mode and starts harvester', async () => {
265
+ setConfiguration(agentIdentifier, {
266
+ session_replay: {
267
+ errorSampleRate: 1,
268
+ sampleRate: 0
269
+ }
270
+ });
271
+ sr.ee.emit('rumresp-sr', [true]);
272
+ await wait(1);
273
+ expect(sr.mode).toEqual(MODE.ERROR);
274
+ expect(sr.scheduler.started).toEqual(false);
275
+ sr.ee.emit('errorAgg');
276
+ expect(sr.mode).toEqual(MODE.FULL);
277
+ expect(sr.scheduler.started).toEqual(true);
278
+ return;
279
+ });
280
+ });
281
+ describe('Session Replay Payload Validation', () => {
282
+ test('Payload', async () => {
283
+ setConfiguration(agentIdentifier, {
284
+ ...init
285
+ });
286
+ sr.ee.emit('rumresp-sr', [true]);
287
+ await wait(1);
288
+ const harvestContents = sr.getHarvestContents();
289
+ // query attrs
290
+ expect(harvestContents.qs).toMatchObject({
291
+ protocol_version: '0',
292
+ content_encoding: 'gzip',
293
+ browser_monitoring_key: info.licenseKey
294
+ });
295
+ expect(harvestContents.body).toMatchObject({
296
+ type: 'SessionReplay',
297
+ appId: info.applicationID,
298
+ timestamp: expect.any(Number),
299
+ blob: expect.any(String),
300
+ attributes: {
301
+ session: session.state.value,
302
+ hasSnapshot: expect.any(Boolean),
303
+ hasError: expect.any(Boolean),
304
+ agentVersion: expect.any(String),
305
+ isFirstChunk: expect.any(Boolean),
306
+ 'nr.rrweb.version': expect.any(String)
307
+ }
308
+ });
309
+ expect(JSON.parse(harvestContents.body.blob).length).toBeGreaterThan(0);
310
+ });
311
+ });
312
+ describe('Session Replay Harvest Behaviors', () => {
313
+ test('Compressed payload is provided to harvester', async () => {
314
+ const {
315
+ gunzipSync,
316
+ strFromU8
317
+ } = await import('fflate');
318
+ setConfiguration(agentIdentifier, {
319
+ ...init
320
+ });
321
+ sr.ee.emit('rumresp-sr', [true]);
322
+ await wait(1);
323
+ const [harvestContents] = sr.prepareHarvest();
324
+ expect(harvestContents.qs).toMatchObject({
325
+ protocol_version: '0',
326
+ content_encoding: 'gzip',
327
+ browser_monitoring_key: info.licenseKey
328
+ });
329
+ expect(harvestContents.body).toEqual(expect.any(Uint8Array));
330
+ expect(JSON.parse(strFromU8(gunzipSync(harvestContents.body)))).toMatchObject({
331
+ type: 'SessionReplay',
332
+ appId: info.applicationID,
333
+ timestamp: expect.any(Number),
334
+ blob: expect.any(String),
335
+ attributes: {
336
+ session: session.state.value,
337
+ hasSnapshot: expect.any(Boolean),
338
+ hasError: expect.any(Boolean),
339
+ agentVersion: expect.any(String),
340
+ isFirstChunk: expect.any(Boolean),
341
+ 'nr.rrweb.version': expect.any(String)
342
+ }
343
+ });
344
+ });
345
+ test('Uncompressed payload is provided to harvester', async () => {
346
+ jest.doMock('fflate', () => ({
347
+ __esModule: true,
348
+ gzipSync: jest.fn().mockImplementation(() => {
349
+ throw new Error();
350
+ })
351
+ }));
352
+ setConfiguration(agentIdentifier, {
353
+ ...init
354
+ });
355
+ sr.shouldCompress = false;
356
+ sr.ee.emit('rumresp-sr', [true]);
357
+ await wait(1);
358
+ const [harvestContents] = sr.prepareHarvest();
359
+ expect(harvestContents.qs).toMatchObject({
360
+ protocol_version: '0',
361
+ // content_encoding is omitted when the payload is not compressed
362
+ browser_monitoring_key: info.licenseKey
363
+ });
364
+ expect(harvestContents.qs.content_encoding).toBeUndefined();
365
+ expect(harvestContents.body).toMatchObject({
366
+ type: 'SessionReplay',
367
+ appId: info.applicationID,
368
+ timestamp: expect.any(Number),
369
+ blob: expect.any(String),
370
+ attributes: {
371
+ session: session.state.value,
372
+ hasSnapshot: expect.any(Boolean),
373
+ hasError: expect.any(Boolean),
374
+ agentVersion: expect.any(String),
375
+ isFirstChunk: expect.any(Boolean),
376
+ 'nr.rrweb.version': expect.any(String)
377
+ }
378
+ });
379
+ });
380
+ test('Clears the event buffer when staged for harvesting', async () => {
381
+ setConfiguration(agentIdentifier, {
382
+ ...init
383
+ });
384
+ sr.shouldCompress = false;
385
+ sr.ee.emit('rumresp-sr', [true]);
386
+ await wait(1);
387
+ sr.prepareHarvest();
388
+ expect(sr.events.length).toEqual(0);
389
+ });
390
+ test('Harvests early if exceeds limit', async () => {
391
+ let after = 0;
392
+ const spy = jest.spyOn(sr.scheduler, 'runHarvest').mockImplementation(() => {
393
+ after = Date.now();
394
+ });
395
+ setConfiguration(agentIdentifier, {
396
+ ...init
397
+ });
398
+ sr.payloadBytesEstimation = IDEAL_PAYLOAD_SIZE / AVG_COMPRESSION;
399
+ const before = Date.now();
400
+ sr.ee.emit('rumresp-sr', [true]);
401
+ await wait(1);
402
+ expect(spy).toHaveBeenCalled();
403
+ expect(after - before).toBeLessThan(sr.harvestTimeSeconds * 1000);
404
+ });
405
+ test('Aborts if exceeds total limit', async () => {
406
+ const spy = jest.spyOn(sr.scheduler, 'runHarvest');
407
+ setConfiguration(agentIdentifier, {
408
+ ...init
409
+ });
410
+ sr.payloadBytesEstimation = (MAX_PAYLOAD_SIZE + 1) / AVG_COMPRESSION;
411
+ const before = Date.now();
412
+ sr.ee.emit('rumresp-sr', [true]);
413
+ await wait(1);
414
+ expect(spy).not.toHaveBeenCalled();
415
+ expect(sr.blocked).toEqual(true);
416
+ expect(sr.mode).toEqual(MODE.OFF);
417
+ });
418
+ test('Aborts if 429 response', async () => {
419
+ setConfiguration(agentIdentifier, {
420
+ ...init
421
+ });
422
+ sr.ee.emit('rumresp-sr', [true]);
423
+ await wait(1);
424
+ expect(sr.mode).toEqual(MODE.FULL);
425
+ sr.onHarvestFinished({
426
+ status: 429
427
+ });
428
+ expect(sr.blocked).toEqual(true);
429
+ expect(sr.mode).toEqual(MODE.OFF);
430
+ });
431
+ });
432
+ });
433
+ function wait() {
434
+ let ms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
435
+ return new Promise(resolve => {
436
+ setTimeout(resolve, ms);
437
+ });
438
+ }
439
+ function primeSessionAndReplay() {
440
+ let sess = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new SessionEntity({
441
+ agentIdentifier,
442
+ key: 'SESSION',
443
+ storage: new LocalMemory()
444
+ });
445
+ session = sess;
446
+ configure(agentIdentifier, {
447
+ info,
448
+ runtime: {
449
+ session
450
+ }
451
+ }, 'test', true);
452
+ sr = new SessionReplayAgg(agentIdentifier, new Aggregator({}));
453
+ }