Skip to content

Commit 9402557

Browse files
graingertbenvinegar
authored andcommitted
Angular and reactNative data callback should return updated data. (#891)
* ensure angular and react-native wrap callbacks without altering Raven API * abstract setCallback wrapping into single function
1 parent b7e98e5 commit 9402557

File tree

5 files changed

+99
-21
lines changed

5 files changed

+99
-21
lines changed

plugins/angular.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
'use strict';
77

8+
var wrappedCallback = require('../src/utils').wrappedCallback;
9+
810
// See https://github.com/angular/angular.js/blob/v1.4.7/src/minErr.js
911
var angularPattern = /^\[((?:[$a-zA-Z0-9]+:)?(?:[$a-zA-Z0-9]+))\] (.*?)\n?(\S+)$/;
1012
var moduleName = 'ngRaven';
@@ -39,11 +41,9 @@ function angularPlugin(Raven, angular) {
3941
.provider('Raven', RavenProvider)
4042
.config(['$provide', ExceptionHandlerProvider]);
4143

42-
Raven.setDataCallback(function(data, original) {
43-
angularPlugin._normalizeData(data);
44-
45-
original && original(data);
46-
});
44+
Raven.setDataCallback(wrappedCallback(function(data) {
45+
return angularPlugin._normalizeData(data);
46+
}));
4747
}
4848

4949
angularPlugin._normalizeData = function (data) {
@@ -63,6 +63,8 @@ angularPlugin._normalizeData = function (data) {
6363
data.extra.angularDocs = matches[3].substr(0, 250);
6464
}
6565
}
66+
67+
return data;
6668
};
6769

6870
angularPlugin.moduleName = moduleName;

plugins/react-native.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
'use strict';
2121

22+
var wrappedCallback = require('../src/utils').wrappedCallback;
23+
2224
// Example React Native path format (iOS):
2325
// /var/containers/Bundle/Application/{DEVICE_ID}/HelloWorld.app/main.jsbundle
2426

@@ -60,9 +62,9 @@ function reactNativePlugin(Raven, options) {
6062
Raven.setTransport(reactNativePlugin._transport);
6163

6264
// Use data callback to strip device-specific paths from stack traces
63-
Raven.setDataCallback(function(data) {
64-
reactNativePlugin._normalizeData(data, options.pathStrip)
65-
});
65+
Raven.setDataCallback(wrappedCallback(function(data) {
66+
return reactNativePlugin._normalizeData(data, options.pathStrip);
67+
}));
6668

6769
// Check for a previously persisted payload, and report it.
6870
reactNativePlugin._restorePayload()
@@ -224,6 +226,7 @@ reactNativePlugin._normalizeData = function (data, pathStripRe) {
224226
frame.filename = normalizeUrl(frame.filename, pathStripRe);
225227
});
226228
}
229+
return data;
227230
};
228231

229232
module.exports = reactNativePlugin;

src/raven.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ var _window = typeof window !== 'undefined' ? window
2626
var _document = _window.document;
2727
var _navigator = _window.navigator;
2828

29+
30+
function keepOriginalCallback(original, callback) {
31+
return isFunction(callback) ?
32+
function (data) { return callback(data, original) } :
33+
callback;
34+
}
35+
2936
// First, check for JSON support
3037
// If there is no JSON, we no-op the core features of Raven
3138
// since JSON is required to encode the payload
@@ -573,10 +580,8 @@ Raven.prototype = {
573580
*/
574581
setDataCallback: function(callback) {
575582
var original = this._globalOptions.dataCallback;
576-
this._globalOptions.dataCallback = isFunction(callback)
577-
? function (data) { return callback(data, original); }
578-
: callback;
579-
583+
this._globalOptions.dataCallback =
584+
keepOriginalCallback(original, callback);
580585
return this;
581586
},
582587

@@ -589,10 +594,8 @@ Raven.prototype = {
589594
*/
590595
setBreadcrumbCallback: function(callback) {
591596
var original = this._globalOptions.breadcrumbCallback;
592-
this._globalOptions.breadcrumbCallback = isFunction(callback)
593-
? function (data) { return callback(data, original); }
594-
: callback;
595-
597+
this._globalOptions.breadcrumbCallback =
598+
keepOriginalCallback(original, callback);
596599
return this;
597600
},
598601

@@ -605,10 +608,8 @@ Raven.prototype = {
605608
*/
606609
setShouldSendCallback: function(callback) {
607610
var original = this._globalOptions.shouldSendCallback;
608-
this._globalOptions.shouldSendCallback = isFunction(callback)
609-
? function (data) { return callback(data, original); }
610-
: callback;
611-
611+
this._globalOptions.shouldSendCallback =
612+
keepOriginalCallback(original, callback);
612613
return this;
613614
},
614615

src/utils.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,20 @@ function isError(value) {
1515
}
1616
}
1717

18+
function wrappedCallback(callback) {
19+
function dataCallback(data, original) {
20+
var normalizedData = callback(data) || data;
21+
if (original) {
22+
return original(normalizedData) || normalizedData;
23+
}
24+
return normalizedData;
25+
}
26+
27+
return dataCallback;
28+
}
29+
1830
module.exports = {
1931
isObject: isObject,
20-
isError: isError
32+
isError: isError,
33+
wrappedCallback: wrappedCallback
2134
};

test/utils.test.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
'use strict';
44

55
var Raven = require('../src/raven');
6+
var wrappedCallback = require('../src/utils').wrappedCallback;
67
var utils = Raven.utils;
78
var RavenConfigError = require('../src/configError');
89

@@ -290,4 +291,62 @@ describe('utils', function () {
290291
});
291292
});
292293
});
294+
295+
describe('wrappedCallback', function () {
296+
it('should return data from callback', function () {
297+
var expected = 'yup';
298+
var cb = wrappedCallback(function() {
299+
return expected;
300+
});
301+
assert.equal(cb(), expected);
302+
});
303+
304+
it('should return mutated data from callback', function () {
305+
var cb = wrappedCallback(function(data) {
306+
data.mutated = true;
307+
});
308+
assert.deepEqual(cb({}), {mutated: true});
309+
});
310+
311+
it('should return data from original', function () {
312+
var expected = 'yup';
313+
var cb = wrappedCallback(function(data) {
314+
return 'nope';
315+
});
316+
317+
function original() {
318+
return expected;
319+
}
320+
assert.equal(cb({}, original), expected);
321+
});
322+
323+
it('should return mutated data from original', function () {
324+
var cb = wrappedCallback(function(data) {
325+
data.mutatedSomeMore = true;
326+
});
327+
328+
function original(data) {
329+
data.mutated = true;
330+
}
331+
assert.deepEqual(cb({}, original), {
332+
mutated: true,
333+
mutatedSomeMore: true
334+
});
335+
});
336+
337+
it('should call callback and original in the right order', function () {
338+
var cb = wrappedCallback(function(data) {
339+
return data + 'callback first, ';
340+
});
341+
342+
function original(data) {
343+
return data + 'then the original.';
344+
}
345+
346+
assert.equal(
347+
cb('it will run the ', original),
348+
'it will run the callback first, then the original.'
349+
);
350+
});
351+
});
293352
});

0 commit comments

Comments
 (0)