Skip to content

Commit f261ec2

Browse files
authored
fix: Handle Schrodingers Error (#1261)
* fix: Handle Schrodingers Error * ref: Create better description for Schrodinger's Error
1 parent 3c65e28 commit f261ec2

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

src/raven.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -461,18 +461,18 @@ Raven.prototype = {
461461
captureException: function(ex, options) {
462462
options = objectMerge({trimHeadFrames: 0}, options ? options : {});
463463

464-
if (isPlainObject(ex)) {
465-
// If it is plain Object, serialize it manually and extract options
466-
// This will allow us to group events based on top-level keys
467-
// which is much better than creating new group when any key/value change
468-
options = this._getCaptureExceptionOptionsFromPlainObject(options, ex);
469-
ex = new Error(options.message);
470-
} else if (isErrorEvent(ex) && ex.error) {
464+
if (isErrorEvent(ex) && ex.error) {
471465
// If it is an ErrorEvent with `error` property, extract it to get actual Error
472466
ex = ex.error;
473467
} else if (isError(ex)) {
474468
// we have a real Error object
475469
ex = ex;
470+
} else if (isPlainObject(ex)) {
471+
// If it is plain Object, serialize it manually and extract options
472+
// This will allow us to group events based on top-level keys
473+
// which is much better than creating new group when any key/value change
474+
options = this._getCaptureExceptionOptionsFromPlainObject(options, ex);
475+
ex = new Error(options.message);
476476
} else {
477477
// If none of previous checks were valid, then it means that
478478
// it's not a plain Object

test/raven.test.js

+40
Original file line numberDiff line numberDiff line change
@@ -3066,8 +3066,10 @@ describe('Raven (public API)', function() {
30663066
var error = new ErrorEvent('pickleRick', {error: new Error('pickleRick')});
30673067
this.sinon.stub(Raven, 'isSetup').returns(true);
30683068
this.sinon.stub(Raven, '_handleStackInfo');
3069+
this.sinon.spy(Raven, '_getCaptureExceptionOptionsFromPlainObject');
30693070
Raven.captureException(error, {foo: 'bar'});
30703071
assert.isTrue(Raven._handleStackInfo.calledOnce);
3072+
assert.isFalse(Raven._getCaptureExceptionOptionsFromPlainObject.called);
30713073
});
30723074

30733075
it('should send ErrorEvents without Errors as messages', function() {
@@ -3079,6 +3081,44 @@ describe('Raven (public API)', function() {
30793081
});
30803082
}
30813083

3084+
it("should treat Schrodinger's Error in the same way as regular Error", function() {
3085+
// Schrodinger's Error is an object that is and is not an Error at the same time
3086+
// Like... error, but not really.
3087+
// But error.
3088+
//
3089+
// To be more exact, it's an object literal or an instance of constructor function
3090+
// that has it's prototype set to the Error object itself.
3091+
// When using `isPlanObject`, which makes a call to `Object.prototype.toString`,
3092+
// it returns `[object Object]`, because any instance created with `new X`
3093+
// where X is a custom constructor like `function X () {}`, it's return value
3094+
// is an object literal.
3095+
// However, because it has it's prototype set to an Error object,
3096+
// when using `instanceof Error` check, it returns `true`, because calls
3097+
// like this, are always going up the prototype chain and will verify
3098+
// all possible constructors. For example:
3099+
//
3100+
// class Foo extends Bar {}
3101+
// class Bar extends Error {}
3102+
//
3103+
// var foo = new Foo();
3104+
//
3105+
// and now `foo` is instance of every "extension" ever created in the chain
3106+
//
3107+
// foo instanceof Foo; // true
3108+
// foo instanceof Bar; // true (because Foo extends Bar)
3109+
// foo instanceof Error; // true (because Foo extends Bar that extends Error)
3110+
3111+
function SchrodingersError() {}
3112+
SchrodingersError.prototype = new Error("Schrödinger's cat was here");
3113+
var error = new SchrodingersError();
3114+
this.sinon.stub(Raven, 'isSetup').returns(true);
3115+
this.sinon.stub(Raven, '_handleStackInfo');
3116+
this.sinon.spy(Raven, '_getCaptureExceptionOptionsFromPlainObject');
3117+
Raven.captureException(error, {foo: 'bar'});
3118+
assert.isTrue(Raven._handleStackInfo.calledOnce);
3119+
assert.isFalse(Raven._getCaptureExceptionOptionsFromPlainObject.called);
3120+
});
3121+
30823122
it('should call handleStackInfo', function() {
30833123
var error = new Error('pickleRick');
30843124
this.sinon.stub(Raven, 'isSetup').returns(true);

0 commit comments

Comments
 (0)