rollbar 2.25.1 → 2.26.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.
@@ -105,6 +105,60 @@ describe('getTransportFromOptions', function() {
105
105
  expect(t.proxy).to.eql(options.proxy);
106
106
  expect(t.timeout).to.eql(undefined);
107
107
  });
108
+ describe('getTransportFromOptions', function() {
109
+ var defaults = {
110
+ hostname: 'api.com',
111
+ protocol: 'https:',
112
+ path: '/api/1',
113
+ search: '?abc=456',
114
+ };
115
+ var url = {
116
+ parse: function(_) {
117
+ return {
118
+ hostname: 'whatever.com',
119
+ protocol: 'http:',
120
+ pathname: '/api/42'
121
+ };
122
+ }
123
+ };
124
+ it('should use xhr by default', function(done) {
125
+ var options = {};
126
+ var t = u.getTransportFromOptions(options, defaults, url);
127
+ expect(t.transport).to.eql('xhr');
128
+ done();
129
+ });
130
+ it('should use fetch when requested', function(done) {
131
+ var options = {defaultTransport: 'fetch'};
132
+ var t = u.getTransportFromOptions(options, defaults, url);
133
+ expect(t.transport).to.eql('fetch');
134
+ done();
135
+ });
136
+ it('should use xhr when requested', function(done) {
137
+ var options = {defaultTransport: 'xhr'};
138
+ var t = u.getTransportFromOptions(options, defaults, url);
139
+ expect(t.transport).to.eql('xhr');
140
+ done();
141
+ });
142
+ it('should use xhr when fetch is unavailable', function(done) {
143
+ var options = {defaultTransport: 'fetch'};
144
+ var oldFetch = window.fetch;
145
+ self.fetch = undefined;
146
+ var t = u.getTransportFromOptions(options, defaults, url);
147
+ expect(t.transport).to.eql('xhr');
148
+ self.fetch = oldFetch;
149
+ done();
150
+ });
151
+ it('should use fetch when xhr is unavailable', function(done) {
152
+ var options = {defaultTransport: 'xhr'};
153
+ var oldXhr = window.XMLHttpRequest;
154
+ self.XMLHttpRequest = undefined;
155
+ var t = u.getTransportFromOptions(options, defaults, url);
156
+ expect(t.transport).to.eql('fetch');
157
+ self.XMLHttpRequest = oldXhr;
158
+ done();
159
+ });
160
+ });
161
+
108
162
  });
109
163
 
110
164
  describe('transportOptions', function() {
@@ -1495,17 +1495,21 @@ describe('options.autoInstrument', function() {
1495
1495
  if(xhr.readyState === 4) {
1496
1496
  try {
1497
1497
  setTimeout(function() {
1498
- server.respond();
1498
+ try {
1499
+ server.respond();
1499
1500
 
1500
- expect(server.requests.length).to.eql(2);
1501
- var body = JSON.parse(server.requests[1].requestBody);
1501
+ expect(server.requests.length).to.eql(2);
1502
+ var body = JSON.parse(server.requests[1].requestBody);
1502
1503
 
1503
- expect(body.data.body.trace.exception.message).to.eql('HTTP request failed with Status 404');
1504
+ expect(body.data.body.trace.exception.message).to.eql('HTTP request failed with Status 404');
1504
1505
 
1505
- // Just knowing a stack is present is enough for this test.
1506
- expect(body.data.body.trace.frames.length).to.be.above(1);
1506
+ // Just knowing a stack is present is enough for this test.
1507
+ expect(body.data.body.trace.frames.length).to.be.above(1);
1507
1508
 
1508
- done();
1509
+ done();
1510
+ } catch (e) {
1511
+ done(e);
1512
+ }
1509
1513
  }, 1);
1510
1514
  } catch (e) {
1511
1515
  done(e);
@@ -1525,15 +1529,9 @@ describe('options.autoInstrument', function() {
1525
1529
 
1526
1530
  window.fetchStub = sinon.stub(window, 'fetch');
1527
1531
 
1528
- var readableStream = new ReadableStream({
1529
- start(controller) {
1530
- controller.enqueue(JSON.stringify({name: 'foo', password: '123456'}));
1531
- controller.close();
1532
- }
1533
- });
1534
-
1532
+ var responseBody = JSON.stringify({name: 'foo', password: '123456'});
1535
1533
  window.fetch.returns(Promise.resolve(new Response(
1536
- readableStream,
1534
+ responseBody,
1537
1535
  { status: 200, statusText: 'OK', headers: { 'content-type': 'application/json', 'password': '123456' }}
1538
1536
  )));
1539
1537
 
@@ -1557,11 +1555,18 @@ describe('options.autoInstrument', function() {
1557
1555
  const fetchInit = {
1558
1556
  method: 'POST',
1559
1557
  headers: fetchHeaders,
1560
- body: JSON.stringify({name: 'bar', secret: 'xhr post'})
1558
+ body: JSON.stringify({name: 'bar', secret: 'fetch post'})
1561
1559
  };
1562
- var fetchRequest = new Request('https://example.com/xhr-test');
1560
+ var fetchRequest = new Request('https://example.com/fetch-test');
1563
1561
  window.fetch(fetchRequest, fetchInit)
1564
1562
  .then(function(response) {
1563
+ // Assert that the original stream reader hasn't been read.
1564
+ expect(response.bodyUsed).to.eql(false);
1565
+ return response.text()
1566
+ })
1567
+ .then(function(text) {
1568
+ expect(text).to.eql(responseBody);
1569
+
1565
1570
  try {
1566
1571
  rollbar.log('test'); // generate a payload to inspect
1567
1572
  } catch (e) {
@@ -1573,8 +1578,9 @@ describe('options.autoInstrument', function() {
1573
1578
  try {
1574
1579
  server.respond();
1575
1580
 
1576
- expect(server.requests.length).to.eql(2);
1577
- var body = JSON.parse(server.requests[1].requestBody);
1581
+ expect(window.fetchStub.called).to.be.ok();
1582
+ expect(server.requests.length).to.eql(1);
1583
+ var body = JSON.parse(server.requests[0].requestBody);
1578
1584
 
1579
1585
  // Verify request capture and scrubbing
1580
1586
  expect(body.data.body.telemetry[0].body.request).to.eql('{"name":"bar","secret":"********"}');
@@ -1582,19 +1588,12 @@ describe('options.autoInstrument', function() {
1582
1588
  // Verify request headers capture and case-insensitive scrubbing
1583
1589
  expect(body.data.body.telemetry[0].body.request_headers).to.eql({'content-type': 'application/json', secret: '********'});
1584
1590
 
1585
- // When using the Sinon test stub, the response body is populated in Headless Chrome 73,
1586
- // but not in 77. When using the Fetch API normally, it is populated in all tested Chrome versions.
1587
- // Disable here due to the Sinon limitation.
1588
- //
1589
1591
  // Verify response capture and scrubbing
1590
- // expect(body.data.body.telemetry[0].body.response.body).to.eql('{"name":"foo","password":"********"}');
1592
+ expect(body.data.body.telemetry[0].body.response.body).to.eql('{"name":"foo","password":"********"}');
1591
1593
 
1592
1594
  // Verify response headers capture and case-insensitive scrubbing
1593
1595
  expect(body.data.body.telemetry[0].body.response.headers).to.eql({'content-type': 'application/json', password: '********'});
1594
1596
 
1595
- // Assert that the original stream reader hasn't been read.
1596
- expect(response.bodyUsed).to.eql(false);
1597
-
1598
1597
  rollbar.configure({ autoInstrument: false });
1599
1598
  window.fetch.restore();
1600
1599
  done();
@@ -1606,7 +1605,7 @@ describe('options.autoInstrument', function() {
1606
1605
  })
1607
1606
  });
1608
1607
 
1609
- it('should add telemetry events for fetch calls', function(done) {
1608
+ it('should report error for http 4xx fetch calls, when enabled', function(done) {
1610
1609
  var server = window.server;
1611
1610
  stubResponse(server);
1612
1611
  server.requests.length = 0;
@@ -1659,6 +1658,80 @@ describe('options.autoInstrument', function() {
1659
1658
  })
1660
1659
  });
1661
1660
 
1661
+ it('should add telemetry headers when fetch Headers object is undefined', function(done) {
1662
+ var server = window.server;
1663
+ stubResponse(server);
1664
+ server.requests.length = 0;
1665
+
1666
+ window.fetchStub = sinon.stub(window, 'fetch');
1667
+
1668
+ var readableStream = new ReadableStream({
1669
+ start(controller) {
1670
+ controller.enqueue(JSON.stringify({name: 'foo', password: '123456'}));
1671
+ controller.close();
1672
+ }
1673
+ });
1674
+
1675
+ window.fetch.returns(Promise.resolve(new Response(
1676
+ readableStream,
1677
+ { status: 200, statusText: 'OK', headers: { 'content-type': 'application/json', 'password': '123456' }}
1678
+ )));
1679
+
1680
+ var options = {
1681
+ accessToken: 'POST_CLIENT_ITEM_TOKEN',
1682
+ autoInstrument: {
1683
+ log: false,
1684
+ network: true,
1685
+ networkResponseHeaders: true,
1686
+ networkRequestHeaders: true
1687
+ }
1688
+ };
1689
+ var rollbar = window.rollbar = new Rollbar(options);
1690
+
1691
+ // Remove Headers from window object
1692
+ var originalHeaders = window.Headers;
1693
+ delete window.Headers;
1694
+
1695
+ const fetchInit = {
1696
+ method: 'POST',
1697
+ headers: {'Content-Type': 'application/json', Secret: '123456'},
1698
+ body: JSON.stringify({name: 'bar', secret: 'xhr post'})
1699
+ };
1700
+ var fetchRequest = new Request('https://example.com/xhr-test');
1701
+ window.fetch(fetchRequest, fetchInit)
1702
+ .then(function(response) {
1703
+ try {
1704
+ rollbar.log('test'); // generate a payload to inspect
1705
+ setTimeout(function() {
1706
+ try {
1707
+ server.respond();
1708
+
1709
+ expect(server.requests.length).to.eql(1);
1710
+ var body = JSON.parse(server.requests[0].requestBody);
1711
+
1712
+ // Verify request headers capture and case-insensitive scrubbing
1713
+ expect(body.data.body.telemetry[0].body.request_headers).to.eql({'content-type': 'application/json', secret: '********'});
1714
+
1715
+ // Verify response headers capture and case-insensitive scrubbing
1716
+ expect(body.data.body.telemetry[0].body.response.headers).to.eql({'content-type': 'application/json', password: '********'});
1717
+
1718
+ // Assert that the original stream reader hasn't been read.
1719
+ expect(response.bodyUsed).to.eql(false);
1720
+
1721
+ rollbar.configure({ autoInstrument: false });
1722
+ window.fetch.restore();
1723
+ window.Headers = originalHeaders;
1724
+ done();
1725
+ } catch (e) {
1726
+ done(e);
1727
+ }
1728
+ });
1729
+ } catch (e) {
1730
+ done(e);
1731
+ }
1732
+ })
1733
+ });
1734
+
1662
1735
  it('should add a diagnostic message when wrapConsole fails', function(done) {
1663
1736
  var server = window.server;
1664
1737
  stubResponse(server);
@@ -226,9 +226,10 @@ describe('addRequestInfo', function() {
226
226
  it('should use window info to set request properties', function(done) {
227
227
  var args = ['a message'];
228
228
  var item = itemFromArgs(args);
229
- var options = {};
229
+ var options = { captureIp: 'anonymize' };
230
230
  t.addRequestInfo(window)(item, options, function(e, i) {
231
231
  expect(i.data.request).to.be.ok();
232
+ expect(i.data.request.user_ip).to.eql('$remote_ip_anonymize');
232
233
  done(e);
233
234
  });
234
235
  });
@@ -243,6 +244,19 @@ describe('addRequestInfo', function() {
243
244
  done(e);
244
245
  });
245
246
  });
247
+ it('should honor captureIp without window', function(done) {
248
+ var args = ['a message'];
249
+ var item = itemFromArgs(args);
250
+ item.data = {};
251
+ var options = { captureIp: true };
252
+ var w = null;
253
+ t.addRequestInfo(w)(item, options, function(e, i) {
254
+ expect(i.data.request.url).to.not.be.ok();
255
+ expect(i.data.request.query_string).to.not.be.ok();
256
+ expect(i.data.request.user_ip).to.eql('$remote_ip');
257
+ done(e);
258
+ });
259
+ });
246
260
  });
247
261
 
248
262
  describe('addClientInfo', function() {
@@ -86,6 +86,65 @@ describe('post', function() {
86
86
  };
87
87
  t.post(accessToken, options, payload, callback, requestFactory.getInstance);
88
88
  });
89
+ describe('post', function() {
90
+ beforeEach(function (done) {
91
+ window.fetchStub = sinon.stub(window, 'fetch');
92
+ window.server = sinon.createFakeServer();
93
+ done();
94
+ });
95
+
96
+ afterEach(function () {
97
+ window.fetch.restore();
98
+ window.server.restore();
99
+ });
100
+
101
+ function stubFetchResponse() {
102
+ window.fetch.returns(Promise.resolve(new Response(
103
+ JSON.stringify({ err: 0, message: 'OK', result: { uuid: uuid }}),
104
+ { status: 200, statusText: 'OK', headers: { 'Content-Type': 'application/json' }}
105
+ )));
106
+ }
107
+
108
+ function stubXhrResponse() {
109
+ window.server.respondWith(
110
+ [
111
+ 200,
112
+ { 'Content-Type': 'application/json' },
113
+ '{"err": 0, "result":{ "uuid": "d4c7acef55bf4c9ea95e4fe9428a8287"}}'
114
+ ]
115
+ );
116
+ }
117
+
118
+ var uuid = 'd4c7acef55bf4c9ea95e4fe9428a8287';
119
+
120
+ it('should use fetch when requested', function(done) {
121
+ var callback = function(err, resp) {
122
+ expect(window.fetchStub.called).to.be.ok();
123
+ expect(server.requests.length).to.eql(0);
124
+ done(err);
125
+ };
126
+ stubFetchResponse();
127
+ stubXhrResponse();
128
+ server.requests.length = 0;
129
+ options.transport = 'fetch';
130
+ t.post(accessToken, options, payload, callback);
131
+ });
132
+ it('should use xhr when requested', function(done) {
133
+ var callback = function(err, resp) {
134
+ expect(window.fetchStub.called).to.not.be.ok();
135
+ expect(server.requests.length).to.eql(1);
136
+ done(err);
137
+ };
138
+ stubFetchResponse();
139
+ stubXhrResponse();
140
+ server.requests.length = 0;
141
+ options.transport = 'xhr';
142
+ t.post(accessToken, options, payload, callback);
143
+ setTimeout(function() {
144
+ server.respond();
145
+ }, 1);
146
+ });
147
+ });
89
148
  });
90
149
 
91
150
  var TestRequest = function(response, status, shouldThrowOnSend) {