Comparing version 0.4.4 to 0.4.5
{ | ||
"name": "tracekit", | ||
"main": "./tracekit.js", | ||
"version": "0.4.4", | ||
"version": "0.4.5", | ||
"homepage": "https://github.com/csnover/TraceKit", | ||
@@ -6,0 +6,0 @@ "description": "Cross browser stack traces", |
{ | ||
"name": "tracekit", | ||
"main": "./tracekit.js", | ||
"version": "0.4.4", | ||
"version": "0.4.5", | ||
"homepage": "https://github.com/csnover/TraceKit", | ||
@@ -23,11 +23,11 @@ "description": "Cross browser stack traces", | ||
"grunt-cli": "1.2.0", | ||
"grunt-contrib-jasmine": "1.0.3", | ||
"grunt-contrib-jshint": "1.0.0", | ||
"grunt-contrib-jasmine": "1.1.0", | ||
"grunt-contrib-jshint": "1.1.0", | ||
"grunt-jsdoc": "2.1.0", | ||
"jasmine": "2.5.2", | ||
"jasmine-core": "2.5.2", | ||
"karma": "1.3.0", | ||
"karma-jasmine": "1.0.2", | ||
"karma-phantomjs-launcher": "1.0.2", | ||
"phantomjs-prebuilt": "2.1.13" | ||
"jasmine": "2.6.0", | ||
"jasmine-core": "2.6.4", | ||
"karma": "1.7.0", | ||
"karma-jasmine": "1.1.0", | ||
"karma-phantomjs-launcher": "1.0.4", | ||
"phantomjs-prebuilt": "2.1.14" | ||
}, | ||
@@ -34,0 +34,0 @@ "scripts": { |
@@ -177,2 +177,13 @@ /* exported CapturedExceptions */ | ||
// can be generated when Webpack is built with { devtool: eval } | ||
CapturedExceptions.CHROME_XX_WEBPACK = { | ||
message: "Cannot read property 'error' of undefined", | ||
name: "TypeError", | ||
stack: "TypeError: Cannot read property 'error' of undefined\n" + | ||
" at TESTTESTTEST.eval(webpack:///./src/components/test/test.jsx?:295:108)\n" + | ||
" at TESTTESTTEST.render(webpack:///./src/components/test/test.jsx?:272:32)\n" + | ||
" at TESTTESTTEST.tryRender(webpack:///./~/react-transform-catch-errors/lib/index.js?:34:31)\n" + | ||
" at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)" | ||
}; | ||
CapturedExceptions.FIREFOX_3 = { | ||
@@ -228,2 +239,14 @@ fileName: "http://127.0.0.1:8000/js/stacktrace.js", | ||
CapturedExceptions.FIREFOX_43_EVAL = { | ||
columnNumber: 30, | ||
fileName: 'http://localhost:8080/file.js line 25 > eval line 2 > eval', | ||
lineNumber: 1, | ||
message: 'message string', | ||
stack: 'baz@http://localhost:8080/file.js line 26 > eval line 2 > eval:1:30\n' + | ||
'foo@http://localhost:8080/file.js line 26 > eval:2:96\n' + | ||
'@http://localhost:8080/file.js line 26 > eval:4:18\n' + | ||
'speak@http://localhost:8080/file.js:26:17\n' + | ||
'@http://localhost:8080/file.js:33:9' | ||
}; | ||
// Internal errors sometimes thrown by Firefox | ||
@@ -247,2 +270,13 @@ // More here: https://developer.mozilla.org/en-US/docs/Mozilla/Errors | ||
CapturedExceptions.FIREFOX_50_RESOURCE_URL = { | ||
stack: 'render@resource://path/data/content/bundle.js:5529:16\n' + | ||
'dispatchEvent@resource://path/data/content/vendor.bundle.js:18:23028\n' + | ||
'wrapped@resource://path/data/content/bundle.js:7270:25', | ||
fileName: 'resource://path/data/content/bundle.js', | ||
lineNumber: 5529, | ||
columnNumber: 16, | ||
message: 'this.props.raw[this.state.dataSource].rows is undefined', | ||
name: 'TypeError' | ||
}; | ||
CapturedExceptions.SAFARI_6 = { | ||
@@ -339,1 +373,75 @@ message: "'null' is not an object (evaluating 'x.undef')", | ||
}; | ||
CapturedExceptions.CHROME_48_EVAL = { | ||
message: 'message string', | ||
name: 'Error', | ||
stack: 'Error: message string\n' + | ||
'at baz (eval at foo (eval at speak (http://localhost:8080/file.js:21:17)), <anonymous>:1:30)\n' + | ||
'at foo (eval at speak (http://localhost:8080/file.js:21:17), <anonymous>:2:96)\n' + | ||
'at eval (eval at speak (http://localhost:8080/file.js:21:17), <anonymous>:4:18)\n' + | ||
'at Object.speak (http://localhost:8080/file.js:21:17)\n' + | ||
'at http://localhost:8080/file.js:31:13\n' | ||
}; | ||
CapturedExceptions.PHANTOMJS_1_19 = { | ||
stack: "Error: foo\n" + | ||
" at file:///path/to/file.js:878\n" + | ||
" at foo (http://path/to/file.js:4283)\n" + | ||
" at http://path/to/file.js:4287" | ||
}; | ||
CapturedExceptions.ANDROID_REACT_NATIVE = { | ||
message: 'Error: test', | ||
name: 'Error', | ||
stack: 'Error: test\n' + | ||
'at render(/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js:78:24)\n' + | ||
'at _renderValidatedComponentWithoutOwnerOrContext(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1050:29)\n' + | ||
'at _renderValidatedComponent(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1075:15)\n' + | ||
'at renderedElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:484:29)\n' + | ||
'at _currentElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:346:40)\n' + | ||
'at child(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js:68:25)\n' + | ||
'at children(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js:264:10)\n' + | ||
'at this(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js:74:41)\n' | ||
}; | ||
CapturedExceptions.ANDROID_REACT_NATIVE_PROD = { | ||
message: 'Error: test', | ||
name: 'Error', | ||
stack: 'value@index.android.bundle:12:1917\n' + | ||
'onPress@index.android.bundle:12:2336\n' + | ||
'touchableHandlePress@index.android.bundle:258:1497\n' + | ||
'[native code]\n' + | ||
'_performSideEffectsForTransition@index.android.bundle:252:8508\n' + | ||
'[native code]\n' + | ||
'_receiveSignal@index.android.bundle:252:7291\n' + | ||
'[native code]\n' + | ||
'touchableHandleResponderRelease@index.android.bundle:252:4735\n' + | ||
'[native code]\n' + | ||
'u@index.android.bundle:79:142\n' + | ||
'invokeGuardedCallback@index.android.bundle:79:459\n' + | ||
'invokeGuardedCallbackAndCatchFirstError@index.android.bundle:79:580\n' + | ||
'c@index.android.bundle:95:365\n' + | ||
'a@index.android.bundle:95:567\n' + | ||
'v@index.android.bundle:146:501\n' + | ||
'g@index.android.bundle:146:604\n' + | ||
'forEach@[native code]\n' + | ||
'i@index.android.bundle:149:80\n' + | ||
'processEventQueue@index.android.bundle:146:1432\n' + | ||
's@index.android.bundle:157:88\n' + | ||
'handleTopLevel@index.android.bundle:157:174\n' + | ||
'index.android.bundle:156:572\n' + | ||
'a@index.android.bundle:93:276\n' + | ||
'c@index.android.bundle:93:60\n' + | ||
'perform@index.android.bundle:177:596\n' + | ||
'batchedUpdates@index.android.bundle:188:464\n' + | ||
'i@index.android.bundle:176:358\n' + | ||
'i@index.android.bundle:93:90\n' + | ||
'u@index.android.bundle:93:150\n' + | ||
'_receiveRootNodeIDEvent@index.android.bundle:156:544\n' + | ||
'receiveTouches@index.android.bundle:156:918\n' + | ||
'value@index.android.bundle:29:3016\n' + | ||
'index.android.bundle:29:955\n' + | ||
'value@index.android.bundle:29:2417\n' + | ||
'value@index.android.bundle:29:927\n' + | ||
'[native code]' | ||
}; |
@@ -23,24 +23,3 @@ (function() { | ||
}); | ||
describe('can parse stack', function () { | ||
function createException() { | ||
function throwError() { | ||
throw new ReferenceError('This is a test'); | ||
} | ||
try { | ||
throwError(); | ||
} | ||
catch (e) { | ||
var t = TraceKit.computeStackTrace(e, 25); | ||
console.log("tttttt"); | ||
console.log(JSON.stringify(t)); | ||
return e; | ||
} | ||
} | ||
it('should rhave stacktrace', function() { | ||
expect(createException()).toBe(null); | ||
}); | ||
}); | ||
}); | ||
})(); |
@@ -25,2 +25,29 @@ (function() { | ||
it('should get extra arguments (isWindowError and exception)', function (done){ | ||
var handler = jasmine.createSpy('handler'); | ||
var exception = new Error('Boom!'); | ||
function throwException() { | ||
throw exception; | ||
} | ||
TraceKit.report.subscribe(handler); | ||
expect(function () { TraceKit.wrap(throwException)(); }).toThrow(); | ||
setTimeout(function () { | ||
TraceKit.report.unsubscribe(handler); | ||
expect(handler.calls.count()).toEqual(1); | ||
var isWindowError = handler.calls.mostRecent().args[1]; | ||
expect(isWindowError).toEqual(false); | ||
var e = handler.calls.mostRecent().args[2]; | ||
expect(e).toEqual(exception); | ||
done(); | ||
}, 1000); | ||
}, 2000); | ||
// NOTE: This will not pass currently because errors are rethrown. | ||
@@ -27,0 +54,0 @@ /* it('it should call report handler once', function (done){ |
@@ -1,5 +0,5 @@ | ||
(function() { | ||
(function () { | ||
'use strict'; | ||
describe('Parser', function() { | ||
describe('Parser', function () { | ||
function foo() { | ||
@@ -17,6 +17,6 @@ return bar(); | ||
it('should get the order of functions called right', function() { | ||
it('should get the order of functions called right', function () { | ||
var trace = foo(); | ||
var expected = ['baz', 'bar', 'foo']; | ||
for(var i = 1; i <= 3; i++) { | ||
for (var i = 1; i <= 3; i++) { | ||
expect(trace.stack[i].func).toBe(expected[i - 1]); | ||
@@ -33,3 +33,3 @@ } | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'onclick', args: [], line: 82, column: null, context: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: '[native code]', func: '?', args: [], line: null, column: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: '[native code]', func: '?', args: [], line: null, column: null, context: null }); | ||
}); | ||
@@ -60,3 +60,3 @@ | ||
expect(stackFrames.stack.length).toBe(3); | ||
expect(stackFrames.stack[0]).toEqual({ url: '[native code]', func: 'eval', args: [], line: null, column: null }); | ||
expect(stackFrames.stack[0]).toEqual({ url: '[native code]', func: 'eval', args: [], line: null, column: null, context: null }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 58, column: 21, context: null }); | ||
@@ -121,5 +121,5 @@ expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 109, column: 91, context: null }); | ||
it('should parse Chrome error with no location', function () { | ||
var stackFrames = TraceKit.computeStackTrace({stack: "error\n at Array.forEach (native)"}); | ||
var stackFrames = TraceKit.computeStackTrace({ stack: "error\n at Array.forEach (native)" }); | ||
expect(stackFrames.stack.length).toBe(1); | ||
expect(stackFrames.stack[0]).toEqual({ url: null, func: 'Array.forEach', args: ['native'], line: null, column: null }); | ||
expect(stackFrames.stack[0]).toEqual({ url: null, func: 'Array.forEach', args: ['native'], line: null, column: null, context: null }); | ||
}); | ||
@@ -146,9 +146,29 @@ | ||
it('should parse Chrome error with webpack URLs', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.CHROME_XX_WEBPACK); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(4); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.eval', args: [], line: 295, column: 108, context: null }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.render', args: [], line: 272, column: 32, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'webpack:///./~/react-transform-catch-errors/lib/index.js?', func: 'TESTTESTTEST.tryRender', args: [], line: 34, column: 31, context: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'webpack:///./~/react-proxy/modules/createPrototypeProxy.js?', func: 'TESTTESTTEST.proxiedMethod', args: [], line: 44, column: 30, context: null }); | ||
}); | ||
it('should parse nested eval() from Chrome', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.CHROME_48_EVAL); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(5); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://localhost:8080/file.js', func: 'baz', args: [], line: 21, column: 17, context: null }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://localhost:8080/file.js', func: 'foo', args: [], line: 21, column: 17, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://localhost:8080/file.js', func: 'eval', args: [], line: 21, column: 17, context: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://localhost:8080/file.js', func: 'Object.speak', args: [], line: 21, column: 17, context: null }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://localhost:8080/file.js', func: '?', args: [], line: 31, column: 13, context: null }); | ||
}); | ||
it('should parse Chrome error with blob URLs', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.CHROME_48_BLOB); | ||
expect(stackFrames).toBeTruthy(); | ||
console.log(stackFrames); | ||
expect(stackFrames.stack.length).toBe(7); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', func: 's', args: [], line: 31, column: 29146, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', func: 'Object.d [as add]', args: [ ], line: 31, column: 30039, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', func: 'Object.d [as add]', args: [], line: 31, column: 30039, context: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a', func: '?', args: [], line: 15, column: 10978, context: null }); | ||
@@ -160,3 +180,3 @@ expect(stackFrames.stack[4]).toEqual({ url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', func: '?', args: [], line: 1, column: 6911, context: null }); | ||
it('should parse empty IE 9 error', function() { | ||
it('should parse empty IE 9 error', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.IE_9); | ||
@@ -201,9 +221,9 @@ expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(7); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 44, column: null, context: [ ' this.undef();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [ ' ex = ex || this.createException();' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [ ' var p = new printStackTrace.implementation(), result = p.run(ex);' ] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 4, column: null, context: [ ' printTrace(printStackTrace());' ] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 7, column: null, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 11, column: null, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 44, column: null, context: [' this.undef();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [' ex = ex || this.createException();'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [' var p = new printStackTrace.implementation(), result = p.run(ex);'] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 4, column: null, context: [' printTrace(printStackTrace());'] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 7, column: null, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 11, column: null, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [' foo();'] }); | ||
}); | ||
@@ -215,9 +235,9 @@ | ||
expect(stackFrames.stack.length).toBe(7); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 44, column: null, context: [ ' this.undef();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [ ' ex = ex || this.createException();' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [ ' var p = new printStackTrace.implementation(), result = p.run(ex);' ] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 4, column: null, context: [ ' printTrace(printStackTrace());' ] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 7, column: null, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 11, column: null, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 44, column: null, context: [' this.undef();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [' ex = ex || this.createException();'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [' var p = new printStackTrace.implementation(), result = p.run(ex);'] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 4, column: null, context: [' printTrace(printStackTrace());'] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 7, column: null, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 11, column: null, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [' foo();'] }); | ||
}); | ||
@@ -229,5 +249,5 @@ | ||
expect(stackFrames.stack.length).toBe(3); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 43, column: null, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 43, column: null, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 31, column: null, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 18, column: null, context: [' foo();'] }); | ||
}); | ||
@@ -239,8 +259,8 @@ | ||
expect(stackFrames.stack.length).toBe(6); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 27, column: null, context: [ ' ex = ex || this.createException();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: [], line: 18, column: null, context: [ ' var p = new printStackTrace.implementation(), result = p.run(ex);' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 4, column: null, context: [ ' printTrace(printStackTrace());' ] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 7, column: null, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: null, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 27, column: null, context: [' ex = ex || this.createException();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: [], line: 18, column: null, context: [' var p = new printStackTrace.implementation(), result = p.run(ex);'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 4, column: null, context: [' printTrace(printStackTrace());'] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 7, column: null, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: null, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [' foo();'] }); | ||
}); | ||
@@ -252,9 +272,9 @@ | ||
expect(stackFrames.stack.length).toBe(7); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 42, column: null, context: [ ' this.undef();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 27, column: null, context: [ ' ex = ex || this.createException();' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: [], line: 18, column: null, context: [ ' var p = new printStackTrace.implementation(), result = p.run(ex);' ] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 4, column: null, context: [ ' printTrace(printStackTrace());' ] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 7, column: null, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: null, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 42, column: null, context: [' this.undef();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 27, column: null, context: [' ex = ex || this.createException();'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: [], line: 18, column: null, context: [' var p = new printStackTrace.implementation(), result = p.run(ex);'] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 4, column: null, context: [' printTrace(printStackTrace());'] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: [], line: 7, column: null, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: null, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: null, context: [' foo();'] }); | ||
}); | ||
@@ -266,9 +286,9 @@ | ||
expect(stackFrames.stack.length).toBe(7); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: 'createException', args: [], line: 42, column: 12, context: [ ' this.undef();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'run', args: ['ex'], line: 27, column: 8, context: [ ' ex = ex || this.createException();' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: ['options'], line: 18, column: 4, context: [ ' var p = new printStackTrace.implementation(), result = p.run(ex);' ] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: ['n'], line: 4, column: 5, context: [ ' printTrace(printStackTrace());' ] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: ['n'], line: 7, column: 4, context: [ ' bar(n - 1);' ] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: 4, context: [ ' bar(2);' ] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: 3, context: [ ' foo();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://path/to/file.js', func: 'createException', args: [], line: 42, column: 12, context: [' this.undef();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'run', args: ['ex'], line: 27, column: 8, context: [' ex = ex || this.createException();'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: 'printStackTrace', args: ['options'], line: 18, column: 4, context: [' var p = new printStackTrace.implementation(), result = p.run(ex);'] }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: ['n'], line: 4, column: 5, context: [' printTrace(printStackTrace());'] }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://path/to/file.js', func: 'bar', args: ['n'], line: 7, column: 4, context: [' bar(n - 1);'] }); | ||
expect(stackFrames.stack[5]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 11, column: 4, context: [' bar(2);'] }); | ||
expect(stackFrames.stack[6]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 15, column: 3, context: [' foo();'] }); | ||
}); | ||
@@ -281,5 +301,5 @@ | ||
expect(stackFrames.stack.length).toBe(3); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: '<anonymous function>', args: ['x'], line: 48, column: 12, context: [ ' x.undef();' ] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: 'dumpException3', args: [], line: 46, column: 8, context: [ ' dumpException((function(x) {' ] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: '<anonymous function>', args: ['event'], line: 1, column: 0, context: [ ' dumpException3();' ] }); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: '<anonymous function>', args: ['x'], line: 48, column: 12, context: [' x.undef();'] }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: 'dumpException3', args: [], line: 46, column: 8, context: [' dumpException((function(x) {'] }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://localhost:8000/ExceptionLab.html', func: '<anonymous function>', args: ['event'], line: 1, column: 0, context: [' dumpException3();'] }); | ||
}); | ||
@@ -295,3 +315,47 @@ | ||
}); | ||
it('should parse PhantomJS 1.19 error', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.PHANTOMJS_1_19); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(3); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'file:///path/to/file.js', func: '?', args: [], line: 878, column: null, context: null }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://path/to/file.js', func: 'foo', args: [], line: 4283, column: null, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://path/to/file.js', func: '?', args: [], line: 4287, column: null, context: null }); | ||
}); | ||
it('should parse Firefox errors with resource: URLs', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.FIREFOX_50_RESOURCE_URL); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(3); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'resource://path/data/content/bundle.js', func: 'render', args: [], line: 5529, column: 16, context: null }); | ||
}); | ||
it('should parse Firefox errors with eval URLs', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.FIREFOX_43_EVAL); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(5); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'http://localhost:8080/file.js', func: 'baz', args: [], line: 26, column: null, context: null }); | ||
expect(stackFrames.stack[1]).toEqual({ url: 'http://localhost:8080/file.js', func: 'foo', args: [], line: 26, column: null, context: null }); | ||
expect(stackFrames.stack[2]).toEqual({ url: 'http://localhost:8080/file.js', func: '?', args: [], line: 26, column: null, context: null }); | ||
expect(stackFrames.stack[3]).toEqual({ url: 'http://localhost:8080/file.js', func: 'speak', args: [], line: 26, column: 17, context: null }); | ||
expect(stackFrames.stack[4]).toEqual({ url: 'http://localhost:8080/file.js', func: '?', args: [], line: 33, column: 9, context: null }); | ||
}); | ||
it('should parse React Native errors on Android', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.ANDROID_REACT_NATIVE); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(8); | ||
expect(stackFrames.stack[0]).toEqual({ url: '/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js', func: 'render', args: [], line: 78, column: 24, context: null }); | ||
expect(stackFrames.stack[7]).toEqual({ url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js', func: 'this', args: [], line: 74, column: 41, context: null }); | ||
}); | ||
it('should parse React Native errors on Android Production', function () { | ||
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.ANDROID_REACT_NATIVE_PROD); | ||
expect(stackFrames).toBeTruthy(); | ||
expect(stackFrames.stack.length).toBe(37); | ||
expect(stackFrames.stack[0]).toEqual({ url: 'index.android.bundle', func: 'value', args: [], line: 12, column: 1917, context: null }); | ||
expect(stackFrames.stack[35]).toEqual({ url: 'index.android.bundle', func: 'value', args: [], line: 29, column: 927, context: null }); | ||
expect(stackFrames.stack[36]).toEqual({ url: '[native code]', func: '?', args: [], line: null, column: null, context: null }); | ||
}); | ||
}); | ||
})(); | ||
})(); |
@@ -79,2 +79,6 @@ export interface StackFrame { | ||
interface ReportSubscriber { | ||
(stackTrace: StackTrace, isWindowError: boolean, error: any): void | ||
} | ||
interface Report { | ||
@@ -91,3 +95,3 @@ /** | ||
*/ | ||
subscribe(handler:(stackTrace:StackTrace, options?:any) => void): void; | ||
subscribe(handler: ReportSubscriber): void; | ||
@@ -98,3 +102,3 @@ /** | ||
*/ | ||
unsubscribe(handler:() => void): void; | ||
unsubscribe(handler: ReportSubscriber): void; | ||
} | ||
@@ -101,0 +105,0 @@ |
113
tracekit.js
@@ -18,2 +18,5 @@ /** | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types | ||
var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/; | ||
/** | ||
@@ -119,3 +122,2 @@ * A better form of hasOwnProperty<br/> | ||
var handlers = [], | ||
lastArgs = null, | ||
lastException = null, | ||
@@ -145,2 +147,7 @@ lastExceptionStack = null; | ||
} | ||
if (handlers.length === 0) { | ||
window.onerror = _oldOnerrorHandler; | ||
_onErrorHandlerInstalled = false; | ||
} | ||
} | ||
@@ -152,6 +159,7 @@ | ||
* @param {boolean} isWindowError Is this a top-level window error? | ||
* @param {Error=} error The error that's being handled (if available, null otherwise) | ||
* @memberof TraceKit.report | ||
* @throws An exception if an error occurs while calling an handler. | ||
*/ | ||
function notifyHandlers(stack, isWindowError) { | ||
function notifyHandlers(stack, isWindowError, error) { | ||
var exception = null; | ||
@@ -164,3 +172,3 @@ if (isWindowError && !TraceKit.collectWindowErrors) { | ||
try { | ||
handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2))); | ||
handlers[i](stack, isWindowError, error); | ||
} catch (inner) { | ||
@@ -195,5 +203,5 @@ exception = inner; | ||
processLastException(); | ||
} else if (errorObj) { | ||
} else if (errorObj) { | ||
stack = TraceKit.computeStackTrace(errorObj); | ||
notifyHandlers(stack, true); | ||
notifyHandlers(stack, true, errorObj); | ||
} else { | ||
@@ -205,11 +213,23 @@ var location = { | ||
}; | ||
var name; | ||
var msg = message; // must be new var or will modify original `arguments` | ||
if ({}.toString.call(message) === '[object String]') { | ||
var groups = message.match(ERROR_TYPES_RE); | ||
if (groups) { | ||
name = groups[1]; | ||
msg = groups[2]; | ||
} | ||
} | ||
location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line); | ||
location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line); | ||
stack = { | ||
'mode': 'onerror', | ||
'message': message, | ||
'stack': [location] | ||
'name': name, | ||
'message': msg, | ||
'mode': 'onerror', | ||
'stack': [location] | ||
}; | ||
notifyHandlers(stack, true); | ||
notifyHandlers(stack, true, null); | ||
} | ||
@@ -228,6 +248,7 @@ | ||
*/ | ||
function installGlobalHandler () { | ||
function installGlobalHandler() { | ||
if (_onErrorHandlerInstalled === true) { | ||
return; | ||
} | ||
_oldOnerrorHandler = window.onerror; | ||
@@ -244,7 +265,6 @@ window.onerror = traceKitWindowOnError; | ||
var _lastExceptionStack = lastExceptionStack, | ||
_lastArgs = lastArgs; | ||
lastArgs = null; | ||
_lastException = lastException; | ||
lastExceptionStack = null; | ||
lastException = null; | ||
notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs)); | ||
notifyHandlers(_lastExceptionStack, false, _lastException); | ||
} | ||
@@ -270,3 +290,2 @@ | ||
lastException = ex; | ||
lastArgs = _slice.call(arguments, 1); | ||
@@ -277,3 +296,3 @@ // If the stack trace is incomplete, wait for 2 seconds for | ||
// stack trace | ||
window.setTimeout(function () { | ||
setTimeout(function () { | ||
if (lastException === ex) { | ||
@@ -487,4 +506,3 @@ processLastException(); | ||
* @param {string} url URL of source code. | ||
* @param {(string|number)} line Line number in source code to centre | ||
* around for context. | ||
* @param {(string|number)} line Line number in source code to center around for context. | ||
* @return {?Array.<string>} Lines of source code. | ||
@@ -555,7 +573,5 @@ * @memberof TraceKit.computeStackTrace | ||
for (var i = 0, j = urls.length; i < j; ++i) { | ||
// console.log('searching', urls[i]); | ||
if ((source = getSource(urls[i])).length) { | ||
source = source.join('\n'); | ||
if ((m = re.exec(source))) { | ||
// console.log('Found function in ' + urls[i]); | ||
@@ -571,4 +587,2 @@ return { | ||
// console.log('no match'); | ||
return null; | ||
@@ -721,7 +735,14 @@ } | ||
var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|webpack|eval).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i, | ||
gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i, | ||
winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i, | ||
var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i, | ||
gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i, | ||
winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i, | ||
// Used to additionally parse URL/line/column from eval frames | ||
isEval, | ||
geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i, | ||
chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/, | ||
lines = ex.stack.split('\n'), | ||
stack = [], | ||
submatch, | ||
parts, | ||
@@ -733,3 +754,10 @@ element, | ||
if ((parts = chrome.exec(lines[i]))) { | ||
var isNative = parts[2] && parts[2].indexOf('native') !== -1; | ||
var isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line | ||
isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line | ||
if (isEval && (submatch = chromeEval.exec(parts[2]))) { | ||
// throw out eval line/column and use top-most line/column number | ||
parts[2] = submatch[1]; // url | ||
parts[3] = submatch[2]; // line | ||
parts[4] = submatch[3]; // column | ||
} | ||
element = { | ||
@@ -751,2 +779,15 @@ 'url': !isNative ? parts[2] : null, | ||
} else if ((parts = gecko.exec(lines[i]))) { | ||
isEval = parts[3] && parts[3].indexOf(' > eval') > -1; | ||
if (isEval && (submatch = geckoEval.exec(parts[3]))) { | ||
// throw out eval line/column and use top-most line number | ||
parts[3] = submatch[1]; | ||
parts[4] = submatch[2]; | ||
parts[5] = null; // no column when eval | ||
} else if (i === 0 && !parts[5] && !_isUndefined(ex.columnNumber)) { | ||
// FireFox uses this awesome columnNumber property for its top frame | ||
// Also note, Firefox's column number is 0-based and everything else expects 1-based, | ||
// so adding 1 | ||
// NOTE: this hack doesn't work if top-most frame is eval | ||
stack[0].column = ex.columnNumber + 1; | ||
} | ||
element = { | ||
@@ -767,6 +808,3 @@ 'url': parts[3], | ||
if (element.line) { | ||
element.context = gatherContext(element.url, element.line); | ||
} | ||
element.context = element.line ? gatherContext(element.url, element.line) : null; | ||
stack.push(element); | ||
@@ -781,7 +819,2 @@ } | ||
stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line); | ||
} else if (!stack[0].column && !_isUndefined(ex.columnNumber)) { | ||
// FireFox uses this awesome columnNumber property for its top frame | ||
// Also note, Firefox's column number is 0-based and everything else expects 1-based, | ||
// so adding 1 | ||
stack[0].column = ex.columnNumber + 1; | ||
} | ||
@@ -1063,3 +1096,2 @@ | ||
if (curr === computeStackTrace || curr === TraceKit.report) { | ||
// console.log('skipping internal function'); | ||
continue; | ||
@@ -1112,4 +1144,2 @@ } | ||
if (depth) { | ||
// console.log('depth is ' + depth); | ||
// console.log('stack is ' + stack.length); | ||
stack.splice(0, depth); | ||
@@ -1186,2 +1216,4 @@ } | ||
return { | ||
'name': ex.name, | ||
'message': ex.message, | ||
'mode': 'failed' | ||
@@ -1207,2 +1239,3 @@ }; | ||
computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement; | ||
computeStackTrace.computeStackTraceFromStackProp = computeStackTraceFromStackProp; | ||
computeStackTrace.guessFunctionName = guessFunctionName; | ||
@@ -1259,6 +1292,6 @@ computeStackTrace.gatherContext = gatherContext; | ||
// UMD export | ||
if (typeof module !== 'undefined' && module.exports && window.module !== module) { | ||
if (typeof define === 'function' && define.amd) { | ||
define('TraceKit', [], TraceKit); | ||
} else if (typeof module !== 'undefined' && module.exports && window.module !== module) { | ||
module.exports = TraceKit; | ||
} else if (typeof define === 'function' && define.amd) { | ||
define('TraceKit', [], TraceKit); | ||
} else { | ||
@@ -1265,0 +1298,0 @@ window.TraceKit = TraceKit; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2542
130243