rollbar 2.26.4 → 3.0.0-alpha.2

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 (140) hide show
  1. package/.claude/settings.local.json +3 -0
  2. package/.cursor/rules/guidelines.mdc +154 -0
  3. package/.github/workflows/ci.yml +4 -6
  4. package/CLAUDE.local.md +297 -0
  5. package/CLAUDE.md +201 -0
  6. package/CLAUDE.testrunner.md +470 -0
  7. package/Gruntfile.js +59 -16
  8. package/Makefile +3 -3
  9. package/SECURITY.md +5 -0
  10. package/babel.config.json +9 -0
  11. package/codex.md +148 -0
  12. package/dist/plugins/jquery.min.js +1 -1
  13. package/dist/rollbar.js +19332 -6596
  14. package/dist/rollbar.js.map +1 -1
  15. package/dist/rollbar.min.js +2 -1
  16. package/dist/rollbar.min.js.LICENSE.txt +1 -0
  17. package/dist/rollbar.min.js.map +1 -1
  18. package/dist/rollbar.named-amd.js +19332 -6596
  19. package/dist/rollbar.named-amd.js.map +1 -1
  20. package/dist/rollbar.named-amd.min.js +2 -1
  21. package/dist/rollbar.named-amd.min.js.LICENSE.txt +1 -0
  22. package/dist/rollbar.named-amd.min.js.map +1 -1
  23. package/dist/rollbar.noconflict.umd.js +19319 -6581
  24. package/dist/rollbar.noconflict.umd.js.map +1 -1
  25. package/dist/rollbar.noconflict.umd.min.js +2 -1
  26. package/dist/rollbar.noconflict.umd.min.js.LICENSE.txt +1 -0
  27. package/dist/rollbar.noconflict.umd.min.js.map +1 -1
  28. package/dist/rollbar.snippet.js +1 -1
  29. package/dist/rollbar.umd.js +19333 -6597
  30. package/dist/rollbar.umd.js.map +1 -1
  31. package/dist/rollbar.umd.min.js +2 -1
  32. package/dist/rollbar.umd.min.js.LICENSE.txt +1 -0
  33. package/dist/rollbar.umd.min.js.map +1 -1
  34. package/eslint.config.mjs +33 -0
  35. package/karma.conf.js +5 -14
  36. package/package.json +19 -20
  37. package/src/api.js +57 -4
  38. package/src/apiUtility.js +2 -3
  39. package/src/browser/core.js +37 -9
  40. package/src/browser/replay/defaults.js +70 -0
  41. package/src/browser/replay/recorder.js +194 -0
  42. package/src/browser/replay/replayMap.js +195 -0
  43. package/src/browser/rollbar.js +11 -7
  44. package/src/browser/telemetry.js +3 -3
  45. package/src/browser/transport/fetch.js +17 -4
  46. package/src/browser/transport/xhr.js +17 -1
  47. package/src/browser/transport.js +11 -8
  48. package/src/defaults.js +1 -1
  49. package/src/queue.js +65 -4
  50. package/src/react-native/rollbar.js +1 -1
  51. package/src/rollbar.js +52 -10
  52. package/src/server/rollbar.js +3 -2
  53. package/src/telemetry.js +76 -11
  54. package/src/tracing/context.js +24 -0
  55. package/src/tracing/contextManager.js +37 -0
  56. package/src/tracing/defaults.js +7 -0
  57. package/src/tracing/exporter.js +188 -0
  58. package/src/tracing/hrtime.js +98 -0
  59. package/src/tracing/id.js +24 -0
  60. package/src/tracing/session.js +55 -0
  61. package/src/tracing/span.js +92 -0
  62. package/src/tracing/spanProcessor.js +15 -0
  63. package/src/tracing/tracer.js +46 -0
  64. package/src/tracing/tracing.js +89 -0
  65. package/src/utility.js +34 -0
  66. package/test/api.test.js +57 -12
  67. package/test/apiUtility.test.js +5 -6
  68. package/test/browser.core.test.js +1 -10
  69. package/test/browser.domUtility.test.js +1 -1
  70. package/test/browser.predicates.test.js +1 -1
  71. package/test/browser.replay.recorder.test.js +430 -0
  72. package/test/browser.rollbar.test.js +58 -12
  73. package/test/browser.telemetry.test.js +1 -1
  74. package/test/browser.transforms.test.js +20 -13
  75. package/test/browser.transport.test.js +5 -4
  76. package/test/browser.url.test.js +1 -1
  77. package/test/fixtures/replay/index.js +20 -0
  78. package/test/fixtures/replay/payloads.fixtures.js +229 -0
  79. package/test/fixtures/replay/rrwebEvents.fixtures.js +251 -0
  80. package/test/fixtures/replay/rrwebSyntheticEvents.fixtures.js +328 -0
  81. package/test/notifier.test.js +1 -1
  82. package/test/predicates.test.js +1 -1
  83. package/test/queue.test.js +1 -1
  84. package/test/rateLimiter.test.js +1 -1
  85. package/test/react-native.rollbar.test.js +1 -1
  86. package/test/react-native.transforms.test.js +2 -2
  87. package/test/react-native.transport.test.js +3 -3
  88. package/test/replay/index.js +2 -0
  89. package/test/replay/integration/api.spans.test.js +136 -0
  90. package/test/replay/integration/e2e.test.js +228 -0
  91. package/test/replay/integration/index.js +9 -0
  92. package/test/replay/integration/queue.replayMap.test.js +332 -0
  93. package/test/replay/integration/replayMap.test.js +163 -0
  94. package/test/replay/integration/sessionRecording.test.js +390 -0
  95. package/test/replay/unit/api.postSpans.test.js +150 -0
  96. package/test/replay/unit/index.js +7 -0
  97. package/test/replay/unit/queue.replayMap.test.js +225 -0
  98. package/test/replay/unit/replayMap.test.js +348 -0
  99. package/test/replay/util/index.js +5 -0
  100. package/test/replay/util/mockRecordFn.js +80 -0
  101. package/test/server.lambda.mocha.test.mjs +172 -0
  102. package/test/server.locals.constructor.mocha.test.mjs +80 -0
  103. package/test/server.locals.error-handling.mocha.test.mjs +387 -0
  104. package/test/server.locals.merge.mocha.test.mjs +267 -0
  105. package/test/server.locals.test-utils.mjs +114 -0
  106. package/test/server.parser.mocha.test.mjs +87 -0
  107. package/test/server.predicates.mocha.test.mjs +63 -0
  108. package/test/server.rollbar.constructor.mocha.test.mjs +199 -0
  109. package/test/server.rollbar.handlers.mocha.test.mjs +253 -0
  110. package/test/server.rollbar.logging.mocha.test.mjs +326 -0
  111. package/test/server.rollbar.misc.mocha.test.mjs +44 -0
  112. package/test/server.rollbar.test-utils.mjs +57 -0
  113. package/test/server.telemetry.mocha.test.mjs +377 -0
  114. package/test/server.transforms.data.mocha.test.mjs +163 -0
  115. package/test/server.transforms.error.mocha.test.mjs +199 -0
  116. package/test/server.transforms.request.mocha.test.mjs +208 -0
  117. package/test/server.transforms.scrub.mocha.test.mjs +140 -0
  118. package/test/server.transforms.sourcemaps.mocha.test.mjs +122 -0
  119. package/test/server.transforms.test-utils.mjs +62 -0
  120. package/test/server.transport.mocha.test.mjs +269 -0
  121. package/test/telemetry.test.js +132 -1
  122. package/test/tracing/contextManager.test.js +28 -0
  123. package/test/tracing/exporter.toPayload.test.js +400 -0
  124. package/test/tracing/id.test.js +24 -0
  125. package/test/tracing/span.test.js +183 -0
  126. package/test/tracing/spanProcessor.test.js +73 -0
  127. package/test/tracing/tracing.test.js +105 -0
  128. package/test/transforms.test.js +2 -2
  129. package/test/truncation.test.js +2 -2
  130. package/test/utility.test.js +44 -6
  131. package/webpack.config.js +6 -44
  132. package/.eslintignore +0 -7
  133. package/test/server.lambda.test.js +0 -194
  134. package/test/server.locals.test.js +0 -1068
  135. package/test/server.parser.test.js +0 -78
  136. package/test/server.predicates.test.js +0 -91
  137. package/test/server.rollbar.test.js +0 -728
  138. package/test/server.telemetry.test.js +0 -443
  139. package/test/server.transforms.test.js +0 -1193
  140. package/test/server.transport.test.js +0 -269
@@ -0,0 +1,430 @@
1
+ /* globals expect */
2
+ /* globals describe */
3
+ /* globals it */
4
+ /* globals beforeEach */
5
+ /* globals sinon */
6
+
7
+ import { expect } from 'chai';
8
+ import { EventType } from '@rrweb/types';
9
+
10
+ import Recorder from '../src/browser/replay/recorder.js';
11
+
12
+ describe('Recorder', function () {
13
+ let mockTracing;
14
+ let mockSpan;
15
+ let stopFnSpy;
16
+ let recordFnStub;
17
+ let emitCallback;
18
+ let testReplayId;
19
+
20
+ beforeEach(function () {
21
+ mockSpan = {
22
+ addEvent: sinon.spy(),
23
+ setAttribute: sinon.spy(),
24
+ span: { startTime: null },
25
+ end: sinon.spy(),
26
+ };
27
+
28
+ mockTracing = {
29
+ startSpan: sinon.stub().returns(mockSpan),
30
+ exporter: {
31
+ toPayload: sinon.stub().returns([{ id: 'span1' }]),
32
+ },
33
+ };
34
+
35
+ testReplayId = 'test-replay-id-123';
36
+ stopFnSpy = sinon.spy();
37
+ recordFnStub = sinon.stub().callsFake(function (options) {
38
+ emitCallback = options.emit;
39
+ return stopFnSpy;
40
+ });
41
+ });
42
+
43
+ describe('constructor', function () {
44
+ it('should initialize with default properties', function () {
45
+ const recorder = new Recorder({}, recordFnStub);
46
+
47
+ expect(recorder.isRecording).to.equal(false);
48
+ expect(recorder.options).to.deep.equal({
49
+ enabled: undefined,
50
+ autoStart: undefined,
51
+ maxSeconds: undefined,
52
+ triggerOptions: undefined,
53
+ debug: undefined,
54
+ });
55
+ });
56
+
57
+ it('should initialize removing disallowed options', function () {
58
+ const options = { enabled: true, checkoutEveryNms: 1000 };
59
+ const recorder = new Recorder(options, recordFnStub);
60
+
61
+ expect(recorder.options).to.deep.equal({
62
+ enabled: true,
63
+ autoStart: undefined,
64
+ maxSeconds: undefined,
65
+ triggerOptions: undefined,
66
+ debug: undefined,
67
+ });
68
+ });
69
+
70
+ it('should throw error if no record function is passed', function () {
71
+ expect(() => new Recorder({}, null)).to.throw(
72
+ TypeError,
73
+ "Expected 'recordFn' to be provided",
74
+ );
75
+ });
76
+ });
77
+
78
+ describe('recording management', function () {
79
+ it('should start recording correctly', function () {
80
+ const recorder = new Recorder(
81
+ { enabled: true },
82
+ recordFnStub,
83
+ );
84
+ recorder.start();
85
+
86
+ expect(recorder.isRecording).to.be.true;
87
+ expect(recordFnStub.calledOnce).to.be.true;
88
+ expect(stopFnSpy.called).to.be.false;
89
+
90
+ const recordOptions = recordFnStub.firstCall.args[0];
91
+ expect(recordOptions.checkoutEveryNms).to.equal(5000);
92
+ expect(typeof recordOptions.emit).to.equal('function');
93
+ });
94
+
95
+ it('should not start if already recording', function () {
96
+ const recorder = new Recorder(
97
+ { enabled: true },
98
+ recordFnStub,
99
+ );
100
+ recorder.start();
101
+ recorder.start();
102
+
103
+ expect(recordFnStub.calledOnce).to.be.true;
104
+ });
105
+
106
+ it('should not start if disabled', function () {
107
+ const recorder = new Recorder(
108
+ { enabled: false },
109
+ recordFnStub,
110
+ );
111
+ recorder.start();
112
+
113
+ expect(recorder.isRecording).to.be.false;
114
+ expect(recordFnStub.called).to.be.false;
115
+ });
116
+
117
+ it('should stop recording correctly', function () {
118
+ const recorder = new Recorder(
119
+ { enabled: true },
120
+ recordFnStub,
121
+ );
122
+ recorder.start();
123
+ recorder.stop();
124
+
125
+ expect(recorder.isRecording).to.be.false;
126
+ expect(recordFnStub.calledOnce).to.be.true;
127
+ expect(stopFnSpy.calledOnce).to.be.true;
128
+ });
129
+
130
+ it('should handle stop when not recording', function () {
131
+ const recorder = new Recorder({}, recordFnStub);
132
+ recorder.stop();
133
+
134
+ expect(recorder.isRecording).to.be.false;
135
+ expect(stopFnSpy.called).to.be.false;
136
+ });
137
+ });
138
+
139
+ describe('event handling', function () {
140
+ it('should handle events correctly', function () {
141
+ const recorder = new Recorder({}, recordFnStub);
142
+ recorder.start();
143
+
144
+ const event1 = { timestamp: 1000, type: 'event1', data: { a: 1 } };
145
+ const event2 = { timestamp: 2000, type: 'event2', data: { b: 2 } };
146
+
147
+ emitCallback(event1, false);
148
+ emitCallback(event2, false);
149
+
150
+ const result = recorder.dump(mockTracing, testReplayId);
151
+
152
+ expect(mockTracing.startSpan.calledOnce).to.be.true;
153
+ expect(mockSpan.addEvent.calledTwice).to.be.true;
154
+ expect(mockSpan.setAttribute.calledOnce).to.be.true;
155
+ expect(mockSpan.setAttribute.calledWith('rollbar.replay.id', testReplayId)).to.be.true;
156
+
157
+ const firstCallData = mockSpan.addEvent.firstCall.args[1];
158
+ expect(firstCallData.eventType).to.equal('event1');
159
+ expect(JSON.parse(firstCallData.json)).to.deep.equal({ a: 1 });
160
+ expect(firstCallData['rollbar.replay.id']).to.equal(testReplayId);
161
+
162
+ const secondCallData = mockSpan.addEvent.secondCall.args[1];
163
+ expect(secondCallData.eventType).to.equal('event2');
164
+ expect(JSON.parse(secondCallData.json)).to.deep.equal({ b: 2 });
165
+ expect(secondCallData['rollbar.replay.id']).to.equal(testReplayId);
166
+ });
167
+
168
+ it('should handle checkout events correctly', function () {
169
+ const recorder = new Recorder({}, recordFnStub);
170
+ recorder.start();
171
+
172
+ // First checkout
173
+ emitCallback({ timestamp: 0, type: EventType.Meta, data: {} }, true);
174
+ emitCallback(
175
+ { timestamp: 10, type: EventType.FullSnapshot, data: {} },
176
+ true,
177
+ );
178
+ emitCallback(
179
+ {
180
+ timestamp: 1000,
181
+ type: EventType.IncrementalSnapshot,
182
+ data: { a: 1 },
183
+ },
184
+ false,
185
+ );
186
+ emitCallback(
187
+ {
188
+ timestamp: 2000,
189
+ type: EventType.IncrementalSnapshot,
190
+ data: { b: 2 },
191
+ },
192
+ false,
193
+ );
194
+
195
+ // Second checkout
196
+ emitCallback({ timestamp: 3050, type: EventType.Meta, data: {} }, true);
197
+ emitCallback(
198
+ { timestamp: 3100, type: EventType.FullSnapshot, data: {} },
199
+ true,
200
+ );
201
+ emitCallback(
202
+ {
203
+ timestamp: 4000,
204
+ type: EventType.IncrementalSnapshot,
205
+ data: { c: 3 },
206
+ },
207
+ false,
208
+ );
209
+
210
+ // Third checkout
211
+ emitCallback({ timestamp: 4500, type: EventType.Meta, data: {} }, true);
212
+ emitCallback(
213
+ { timestamp: 5000, type: EventType.FullSnapshot, data: {} },
214
+ true,
215
+ );
216
+ emitCallback(
217
+ {
218
+ timestamp: 6000,
219
+ type: EventType.IncrementalSnapshot,
220
+ data: { d: 4 },
221
+ },
222
+ false,
223
+ );
224
+
225
+ recorder.dump(mockTracing, testReplayId);
226
+
227
+ // 2nd checkout (meta + fs) + event3 + 3rd checkout (meta + fs) + event4
228
+ expect(mockSpan.span.startTime).to.be.deep.equal([3, 50000000]); // otel time
229
+ expect(mockSpan.span.endTime).not.to.be.null;
230
+
231
+ expect(mockSpan.addEvent.callCount).to.equal(6);
232
+
233
+ [
234
+ {
235
+ name: 'rrweb-replay-events',
236
+ attributes: {
237
+ eventType: EventType.Meta,
238
+ json: JSON.stringify({}),
239
+ 'rollbar.replay.id': testReplayId,
240
+ },
241
+ timestamp: [3, 50000000],
242
+ },
243
+ {
244
+ name: 'rrweb-replay-events',
245
+ attributes: {
246
+ eventType: EventType.FullSnapshot,
247
+ json: JSON.stringify({}),
248
+ 'rollbar.replay.id': testReplayId,
249
+ },
250
+ timestamp: [3, 100000000],
251
+ },
252
+ {
253
+ name: 'rrweb-replay-events',
254
+ attributes: {
255
+ eventType: EventType.IncrementalSnapshot,
256
+ json: JSON.stringify({ c: 3 }),
257
+ 'rollbar.replay.id': testReplayId,
258
+ },
259
+ timestamp: [4, 0],
260
+ },
261
+ {
262
+ name: 'rrweb-replay-events',
263
+ attributes: {
264
+ eventType: EventType.Meta,
265
+ json: JSON.stringify({}),
266
+ 'rollbar.replay.id': testReplayId,
267
+ },
268
+ timestamp: [4, 500000000],
269
+ },
270
+ {
271
+ name: 'rrweb-replay-events',
272
+ attributes: {
273
+ eventType: EventType.FullSnapshot,
274
+ json: JSON.stringify({}),
275
+ 'rollbar.replay.id': testReplayId,
276
+ },
277
+ timestamp: [5, 0],
278
+ },
279
+ {
280
+ name: 'rrweb-replay-events',
281
+ attributes: {
282
+ eventType: EventType.IncrementalSnapshot,
283
+ json: JSON.stringify({ d: 4 }),
284
+ 'rollbar.replay.id': testReplayId,
285
+ },
286
+ timestamp: [6, 0],
287
+ },
288
+ ].forEach((expected, index) => {
289
+ const call = mockSpan.addEvent.getCall(index);
290
+ expect(call.args[0]).to.equal(expected.name);
291
+ expect(call.args[1]).to.deep.equal(expected.attributes);
292
+ expect(call.args[2]).to.deep.equal(expected.timestamp);
293
+ });
294
+ });
295
+ });
296
+
297
+ describe('dump functionality', function () {
298
+ it('should create a span with events and return formatted payload', function () {
299
+ const recorder = new Recorder({}, recordFnStub);
300
+ recorder.start();
301
+
302
+ emitCallback({ timestamp: 1000, type: 'event1', data: { a: 1 } }, false);
303
+ emitCallback({ timestamp: 2000, type: 'event2', data: { b: 2 } }, false);
304
+
305
+ const result = recorder.dump(mockTracing, testReplayId);
306
+
307
+ expect(result).to.deep.equal([{ id: 'span1' }]);
308
+ expect(mockTracing.startSpan.calledOnce).to.be.true;
309
+ expect(mockSpan.addEvent.calledTwice).to.be.true;
310
+ expect(mockSpan.end.calledOnce).to.be.true;
311
+ expect(mockTracing.exporter.toPayload.calledOnce).to.be.true;
312
+ });
313
+
314
+ it('should create a span with the correct span name', function () {
315
+ const recorder = new Recorder({}, recordFnStub);
316
+ recorder.start();
317
+
318
+ emitCallback({ timestamp: 1000, type: 'event1', data: { a: 1 } }, false);
319
+ emitCallback({ timestamp: 2000, type: 'event2', data: { b: 2 } }, false);
320
+
321
+ recorder.dump(mockTracing, testReplayId);
322
+
323
+ expect(mockTracing.startSpan.calledOnce).to.be.true;
324
+ const spanName = mockTracing.startSpan.firstCall.args[0];
325
+ expect(spanName).to.equal('rrweb-replay-recording');
326
+ });
327
+
328
+ it('should add events with the correct event name and replayId', function () {
329
+ const recorder = new Recorder({}, recordFnStub);
330
+ recorder.start();
331
+
332
+ emitCallback(
333
+ { timestamp: 1000, type: 'fullSnapshot', data: { a: 1 } },
334
+ false,
335
+ );
336
+ emitCallback(
337
+ { timestamp: 2000, type: 'mouseMove', data: { b: 2 } },
338
+ false,
339
+ );
340
+ emitCallback({ timestamp: 3000, type: 'input', data: { c: 3 } }, false);
341
+
342
+ recorder.dump(mockTracing, testReplayId);
343
+
344
+ expect(mockSpan.addEvent.callCount).to.equal(3);
345
+
346
+ for (let i = 0; i < mockSpan.addEvent.callCount; i++) {
347
+ const eventName = mockSpan.addEvent.getCall(i).args[0];
348
+ const eventAttrs = mockSpan.addEvent.getCall(i).args[1];
349
+ expect(eventName).to.equal(
350
+ 'rrweb-replay-events',
351
+ `Event at index ${i} should have name "rrweb-replay-events"`
352
+ );
353
+ expect(eventAttrs['rollbar.replay.id']).to.equal(testReplayId);
354
+ }
355
+ });
356
+
357
+ it('should handle no events', function () {
358
+ const recorder = new Recorder({}, recordFnStub);
359
+
360
+ const result = recorder.dump(mockTracing, testReplayId);
361
+
362
+ expect(result).to.be.null;
363
+ expect(mockTracing.startSpan.called).to.be.false;
364
+ expect(mockTracing.exporter.toPayload.called).to.be.false;
365
+ });
366
+
367
+ it('should handle less than 2 events (invalid recording)', function () {
368
+ const recorder = new Recorder({}, recordFnStub);
369
+ recorder.start();
370
+
371
+ emitCallback({ timestamp: 1000, type: 'event1', data: { a: 1 } }, false);
372
+
373
+ const result = recorder.dump(mockTracing, testReplayId);
374
+
375
+ expect(result).to.be.null;
376
+ expect(mockTracing.startSpan.called).to.be.false;
377
+ expect(mockTracing.exporter.toPayload.called).to.be.false;
378
+ });
379
+ });
380
+
381
+ describe('configure', function () {
382
+ it('should update options', function () {
383
+ const recorder = new Recorder(
384
+ { enabled: true },
385
+ recordFnStub,
386
+ );
387
+
388
+ recorder.configure({ enabled: false, maxSeconds: 20 });
389
+
390
+ expect(recorder.options).to.deep.equal({
391
+ enabled: false,
392
+ autoStart: undefined,
393
+ maxSeconds: 20,
394
+ triggerOptions: undefined,
395
+ debug: undefined,
396
+ });
397
+ });
398
+
399
+ it('should set correct checkoutEveryNms', function () {
400
+ const recorder = new Recorder({ enabled: false });
401
+
402
+ recorder.configure({ enabled: true, maxSeconds: 15 });
403
+
404
+ expect(recorder.options).to.deep.equal({
405
+ enabled: true,
406
+ autoStart: undefined,
407
+ maxSeconds: 15,
408
+ triggerOptions: undefined,
409
+ debug: undefined,
410
+ });
411
+
412
+ expect(recorder.checkoutEveryNms()).to.equal(7500);
413
+ });
414
+
415
+ it('should stop recording if enabled set to false', function () {
416
+ const recorder = new Recorder(
417
+ { enabled: true },
418
+ recordFnStub,
419
+ );
420
+ recorder.start();
421
+
422
+ expect(recorder.isRecording).to.be.true;
423
+
424
+ recorder.configure({ enabled: false });
425
+
426
+ expect(recorder.isRecording).to.be.false;
427
+ expect(stopFnSpy.calledOnce).to.be.true;
428
+ });
429
+ });
430
+ });
@@ -3,7 +3,7 @@
3
3
  /* globals it */
4
4
  /* globals sinon */
5
5
 
6
- var Rollbar = require('../src/browser/rollbar');
6
+ import Rollbar from '../src/browser/rollbar.js';
7
7
 
8
8
  const DUMMY_TRACE_ID = 'some-trace-id';
9
9
  const DUMMY_SPAN_ID = 'some-span-id';
@@ -115,11 +115,21 @@ describe('Rollbar()', function () {
115
115
  var client = new (TestClientGen())();
116
116
  var options = {
117
117
  scrubFields: ['foobar'],
118
+ recorder: {
119
+ enabled: true,
120
+ },
121
+ tracing: {
122
+ endpoint: 'api.rollbar.com/api/1/tracing/',
123
+ },
118
124
  };
119
125
  var rollbar = (window.rollbar = new Rollbar(options, client));
120
126
 
121
127
  expect(rollbar.options.scrubFields).to.contain('foobar');
122
128
  expect(rollbar.options.scrubFields).to.contain('password');
129
+ expect(rollbar.options.recorder.enabled).to.eql(true);
130
+ expect(rollbar.options.recorder.triggerOptions.item.levels).to.eql(['error', 'critical']);
131
+ expect(rollbar.options.tracing.endpoint).to.eql('api.rollbar.com/api/1/tracing/');
132
+ expect(rollbar.options.tracing.enabled).to.eql(false);
123
133
  done();
124
134
  });
125
135
 
@@ -191,6 +201,7 @@ describe('Rollbar()', function () {
191
201
  done();
192
202
  });
193
203
 
204
+ // Legacy OpenTracing support
194
205
  it('should have a tracer if valid tracer is provided', function (done) {
195
206
  var options = { tracer: ValidOpenTracingTracerStub };
196
207
  var rollbar = (window.rollbar = new Rollbar(options));
@@ -200,6 +211,7 @@ describe('Rollbar()', function () {
200
211
  done();
201
212
  });
202
213
 
214
+ // Legacy OpenTracing support
203
215
  it('should not have a tracer if invalid tracer is provided', function (done) {
204
216
  var options = { tracer: InvalidOpenTracingTracerStub };
205
217
  var rollbar = (window.rollbar = new Rollbar(options));
@@ -351,7 +363,6 @@ describe('options.captureUncaught', function () {
351
363
 
352
364
  var body = JSON.parse(server.requests[0].requestBody);
353
365
 
354
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
355
366
  expect(body.data.body.trace.exception.message).to.eql('test error');
356
367
  expect(body.data.notifier.diagnostic.raw_error.message).to.eql(
357
368
  'test error',
@@ -399,7 +410,6 @@ describe('options.captureUncaught', function () {
399
410
 
400
411
  var body = JSON.parse(server.requests[0].requestBody);
401
412
 
402
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
403
413
  expect(body.data.body.trace.exception.message).to.eql('test error');
404
414
  expect(body.data.notifier.diagnostic.is_anonymous).to.not.be.ok();
405
415
 
@@ -453,7 +463,6 @@ describe('options.captureUncaught', function () {
453
463
 
454
464
  var body = JSON.parse(server.requests[0].requestBody);
455
465
 
456
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
457
466
  expect(body.data.body.trace.exception.message).to.eql('anon error');
458
467
  expect(body.data.notifier.diagnostic.is_anonymous).to.eql(true);
459
468
 
@@ -494,7 +503,6 @@ describe('options.captureUncaught', function () {
494
503
 
495
504
  var body = JSON.parse(server.requests[0].requestBody);
496
505
 
497
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
498
506
  expect(body.data.body.trace.exception.message).to.eql('test error');
499
507
 
500
508
  // karma doesn't unload the browser between tests, so the onerror handler
@@ -535,7 +543,6 @@ describe('options.captureUncaught', function () {
535
543
 
536
544
  var body = JSON.parse(server.requests[0].requestBody);
537
545
 
538
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
539
546
  expect(body.data.body.trace.exception.message).to.eql('test error');
540
547
 
541
548
  // karma doesn't unload the browser between tests, so the onerror handler
@@ -567,7 +574,6 @@ describe('options.captureUncaught', function () {
567
574
 
568
575
  var body = JSON.parse(server.requests[0].requestBody);
569
576
 
570
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
571
577
  expect(body.data.body.trace_chain[0].exception.message).to.eql(
572
578
  'test DOMException',
573
579
  );
@@ -604,7 +610,6 @@ describe('options.captureUncaught', function () {
604
610
 
605
611
  var body = JSON.parse(server.requests[0].requestBody);
606
612
 
607
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
608
613
  expect(body.data.body.trace.exception.message).to.eql('deep stack error');
609
614
  expect(body.data.body.trace.frames.length).to.be.above(20);
610
615
 
@@ -640,7 +645,6 @@ describe('options.captureUncaught', function () {
640
645
 
641
646
  var body = JSON.parse(server.requests[0].requestBody);
642
647
 
643
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
644
648
  expect(body.data.body.trace.exception.message).to.eql(
645
649
  'event handler error',
646
650
  );
@@ -696,7 +700,6 @@ describe('options.captureUnhandledRejections', function () {
696
700
 
697
701
  var body = JSON.parse(server.requests[0].requestBody);
698
702
 
699
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
700
703
  expect(body.data.body.trace.exception.message).to.eql('test reject');
701
704
  expect(body.data.notifier.diagnostic.is_uncaught).to.eql(true);
702
705
 
@@ -731,7 +734,6 @@ describe('options.captureUnhandledRejections', function () {
731
734
 
732
735
  var body = JSON.parse(server.requests[0].requestBody);
733
736
 
734
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
735
737
  expect(body.data.body.trace.exception.message).to.eql('test reject');
736
738
 
737
739
  server.requests.length = 0;
@@ -881,6 +883,51 @@ describe('log', function () {
881
883
  }, 1);
882
884
  });
883
885
 
886
+ it('should add tracing attributes when called in an active span', function (done) {
887
+ const server = window.server;
888
+ stubResponse(server);
889
+ server.requests.length = 0;
890
+
891
+ const options = {
892
+ accessToken: 'POST_CLIENT_ITEM_TOKEN',
893
+ recorder: {
894
+ enabled: true,
895
+ },
896
+ };
897
+ const rollbar = (window.rollbar = new Rollbar(options));
898
+
899
+ const err = new Error('test error');
900
+
901
+ rollbar.tracing.withSpan('test', {}, () => {
902
+ rollbar.error(err);
903
+ });
904
+
905
+ setTimeout(function () {
906
+ try{
907
+ server.respond();
908
+
909
+ var body = JSON.parse(server.requests[0].requestBody);
910
+
911
+ expect(body.data.body.trace.exception.message).to.eql('test error');
912
+ expect(body.data.attributes).to.be.an('array');
913
+ expect(body.data.attributes.length).to.eql(4);
914
+ expect(body.data.attributes[0].key).to.eql('replay_id');
915
+ expect(body.data.attributes[0].value).to.match(/^[a-f0-9]{16}$/);
916
+ expect(body.data.attributes[1].key).to.eql('session_id');
917
+ expect(body.data.attributes[1].value).to.match(/^[a-f0-9]{32}$/);
918
+ expect(body.data.attributes[2].key).to.eql('span_id');
919
+ expect(body.data.attributes[2].value).to.match(/^[a-f0-9]{16}$/);
920
+ expect(body.data.attributes[3].key).to.eql('trace_id');
921
+ expect(body.data.attributes[3].value).to.match(/^[a-f0-9]{32}$/);
922
+
923
+ done();
924
+ } catch (e) {
925
+ done(e);
926
+ }
927
+ }, 1);
928
+ });
929
+
930
+
884
931
  it('should send message when called with only null arguments', function (done) {
885
932
  var server = window.server;
886
933
  stubResponse(server);
@@ -1019,7 +1066,6 @@ describe('onerror', function () {
1019
1066
 
1020
1067
  var body = JSON.parse(server.requests[0].requestBody);
1021
1068
 
1022
- expect(body.access_token).to.eql('POST_CLIENT_ITEM_TOKEN');
1023
1069
  expect(body.data.body.trace.exception.message).to.eql(
1024
1070
  'testing window.onerror',
1025
1071
  );
@@ -3,7 +3,7 @@
3
3
  /* globals it */
4
4
  /* globals sinon */
5
5
 
6
- var Instrumenter = require('../src/browser/telemetry');
6
+ import Instrumenter from '../src/browser/telemetry.js';
7
7
 
8
8
  describe('instrumentNetwork', function () {
9
9
  it('should capture XHR requests with string URL', function (done) {
@@ -3,8 +3,8 @@
3
3
  /* globals it */
4
4
  /* globals sinon */
5
5
 
6
- var Rollbar = require('../src/browser/rollbar');
7
- var t = require('../src/browser/transforms');
6
+ import Rollbar from '../src/browser/rollbar.js';
7
+ import t from '../src/browser/transforms.js';
8
8
 
9
9
  function TestClientGen() {
10
10
  var TestClient = function () {
@@ -527,7 +527,7 @@ describe('addBody', function () {
527
527
  });
528
528
 
529
529
  describe('scrubPayload', function () {
530
- it('only scrubs payload data', function (done) {
530
+ it('only scrubs payload data', async function () {
531
531
  var args = [
532
532
  'a message',
533
533
  { scooby: 'doo', okay: 'fizz=buzz&fuzz=baz', user: { id: 42 } },
@@ -547,16 +547,23 @@ describe('scrubPayload', function () {
547
547
  expect(payload.data.custom.okay).to.eql('fizz=buzz&fuzz=baz');
548
548
  expect(payload.data.custom.user.id).to.eql(42);
549
549
 
550
- var scrub = require('../src/scrub');
551
- t.addScrubber(scrub)(payload, options, function (e, i) {
552
- expect(i.access_token).to.eql(accessToken);
553
- expect(i.data.custom.scooby).to.not.eql('doo');
554
- expect(payload.data.custom.okay).to.not.eql('fizz=buzz&fuzz=baz');
555
- expect(payload.data.custom.okay).to.match(/fizz=\*+&fuzz=baz/);
556
- expect(payload.data.custom.user.id).to.not.be.ok();
557
- expect(payload.data.custom.user).to.match(/\*+/);
558
- expect(i.data.message).to.eql('a message');
559
- done(e);
550
+ const scrubModule = await import('../src/scrub.js');
551
+ const scrub = scrubModule.default;
552
+
553
+ const scrubberFn = t.addScrubber(scrub);
554
+ const result = await new Promise((resolve, reject) => {
555
+ scrubberFn(payload, options, (err, result) => {
556
+ if (err) reject(err);
557
+ else resolve(result);
558
+ });
560
559
  });
560
+
561
+ expect(result.access_token).to.eql(accessToken);
562
+ expect(result.data.custom.scooby).to.not.eql('doo');
563
+ expect(payload.data.custom.okay).to.not.eql('fizz=buzz&fuzz=baz');
564
+ expect(payload.data.custom.okay).to.match(/fizz=\*+&fuzz=baz/);
565
+ expect(payload.data.custom.user.id).to.not.be.ok();
566
+ expect(payload.data.custom.user).to.match(/\*+/);
567
+ expect(result.data.message).to.eql('a message');
561
568
  });
562
569
  });
@@ -3,10 +3,10 @@
3
3
  /* globals it */
4
4
  /* globals sinon */
5
5
 
6
- var truncation = require('../src/truncation');
7
- var Transport = require('../src/browser/transport');
8
- var t = new Transport(truncation);
9
- var utility = require('../src/utility');
6
+ import truncation from '../src/truncation.js';
7
+ import Transport from '../src/browser/transport.js';
8
+ const t = new Transport(truncation);
9
+ import * as utility from '../src/utility.js';
10
10
  utility.setupJSON();
11
11
 
12
12
  describe('post', function () {
@@ -166,6 +166,7 @@ var TestRequest = function (response, status, shouldThrowOnSend) {
166
166
  this.onreadystatechange = null;
167
167
  this.readyState = 0;
168
168
  this.shouldThrowOnSend = shouldThrowOnSend;
169
+ this.getResponseHeader = (key) => undefined;
169
170
  };
170
171
  TestRequest.prototype.open = function (m, u, a) {
171
172
  this.method = m;