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