diff --git a/api.js b/api.js index dc5f72d26..0702340c7 100644 --- a/api.js +++ b/api.js @@ -14,6 +14,7 @@ var resolveCwd = require('resolve-cwd'); var uniqueTempDir = require('unique-temp-dir'); var findCacheDir = require('find-cache-dir'); var slash = require('slash'); +var isObj = require('is-obj'); var AvaError = require('./lib/ava-error'); var fork = require('./lib/fork'); var formatter = require('./lib/enhance-assert').formatter(); @@ -81,10 +82,22 @@ Api.prototype._handleOutput = function (channel, data) { this.emit(channel, data); }; +function normalizeError(err) { + if (!isObj(err)) { + err = { + message: err, + stack: err + }; + } + + return err; +} + Api.prototype._handleRejections = function (data) { this.rejectionCount += data.rejections.length; data.rejections.forEach(function (err) { + err = normalizeError(err); err.type = 'rejection'; err.file = data.file; this.emit('error', err); @@ -94,7 +107,7 @@ Api.prototype._handleRejections = function (data) { Api.prototype._handleExceptions = function (data) { this.exceptionCount++; - var err = data.exception; + var err = normalizeError(data.exception); err.type = 'exception'; err.file = data.file; this.emit('error', err); diff --git a/index.js b/index.js index eaaa105b1..e73a0e87a 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ 'use strict'; var path = require('path'); var chalk = require('chalk'); -var serializeError = require('serialize-error'); -var beautifyStack = require('./lib/beautify-stack'); +var serializeError = require('./lib/serialize-error'); var globals = require('./lib/globals'); var Runner = require('./lib/runner'); var send = require('./lib/send'); @@ -49,9 +48,6 @@ function test(props) { if (hasError) { props.error = serializeError(props.error); - if (props.error.stack) { - props.error.stack = beautifyStack(props.error.stack); - } } else { props.error = null; } diff --git a/lib/serialize-error.js b/lib/serialize-error.js new file mode 100644 index 000000000..64cbea6d8 --- /dev/null +++ b/lib/serialize-error.js @@ -0,0 +1,20 @@ +'use strict'; +var cleanYamlObject = require('clean-yaml-object'); +var beautifyStack = require('./beautify-stack'); + +function filter(propertyName, isRoot, source, target) { + if (!isRoot) { + return true; + } + + if (propertyName === 'stack') { + target.stack = beautifyStack(source.stack); + return false; + } + + return true; +} + +module.exports = function (error) { + return cleanYamlObject(error, filter); +}; diff --git a/lib/test-worker.js b/lib/test-worker.js index d1f92e7c5..388943a41 100644 --- a/lib/test-worker.js +++ b/lib/test-worker.js @@ -60,8 +60,7 @@ sourceMapSupport.install({ }); var loudRejection = require('loud-rejection/api')(process); -var serializeError = require('serialize-error'); -var beautifyStack = require('./beautify-stack'); +var serializeError = require('./serialize-error'); var send = require('./send'); var installPrecompiler = require('require-precompiled'); var cacheDir = opts.cacheDir; @@ -94,11 +93,7 @@ Object.keys(require.extensions).forEach(function (ext) { require(testPath); process.on('uncaughtException', function (exception) { - var serialized = serializeError(exception); - if (serialized.stack) { - serialized.stack = beautifyStack(serialized.stack); - } - send('uncaughtException', {exception: serialized}); + send('uncaughtException', {exception: serializeError(exception)}); }); // if ava was not required, show an error @@ -140,11 +135,7 @@ process.on('ava-teardown', function () { } rejections = rejections.map(function (rejection) { - var error = serializeError(rejection.reason); - if (error.stack) { - error.stack = beautifyStack(error.stack); - } - return error; + return serializeError(rejection.reason); }); send('unhandledRejections', {rejections: rejections}); diff --git a/package.json b/package.json index 5f08342d9..c25626824 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "bluebird": "^3.0.0", "caching-transform": "^1.0.0", "chalk": "^1.0.0", + "clean-yaml-object": "^0.1.0", "cli-cursor": "^1.0.2", "cli-spinners": "^0.1.2", "cli-truncate": "^0.2.0", @@ -104,6 +105,7 @@ "ignore-by-default": "^1.0.0", "is-ci": "^1.0.7", "is-generator-fn": "^1.0.0", + "is-obj": "^1.0.0", "is-observable": "^0.1.0", "is-promise": "^2.1.0", "last-line-stream": "^1.0.0", @@ -124,7 +126,6 @@ "pretty-ms": "^2.0.0", "require-precompiled": "^0.1.0", "resolve-cwd": "^1.0.0", - "serialize-error": "^1.1.0", "set-immediate-shim": "^1.0.1", "slash": "^1.0.0", "source-map-support": "^0.4.0", diff --git a/test/cli.js b/test/cli.js index 799fe5aef..af72358ab 100644 --- a/test/cli.js +++ b/test/cli.js @@ -78,10 +78,10 @@ test('disallow invalid babel config shortcuts', function (t) { }); }); -test('throwing a named function will report the to the console', function (t) { +test('throwing a named function will report the function to the console', function (t) { execCli('fixture/throw-named-function.js', function (err, stdout, stderr) { t.ok(err); - t.match(stderr, /\[Function: fooFn]/); + t.match(stderr, /function fooFn\(\) \{\}/); // TODO(jamestalmage) // t.ok(/1 uncaught exception[^s]/.test(stdout)); t.end(); @@ -102,7 +102,7 @@ test('babel require hook only applies to the test file', function (t) { test('throwing a anonymous function will report the function to the console', function (t) { execCli('fixture/throw-anonymous-function.js', function (err, stdout, stderr) { t.ok(err); - t.match(stderr, /\[Function: anonymous]/); + t.match(stderr, /function \(\) \{\}/); // TODO(jamestalmage) // t.ok(/1 uncaught exception[^s]/.test(stdout)); t.end(); diff --git a/test/fixture/throw-anonymous-function.js b/test/fixture/throw-anonymous-function.js index a553e5ae3..365b6bb07 100644 --- a/test/fixture/throw-anonymous-function.js +++ b/test/fixture/throw-anonymous-function.js @@ -2,6 +2,6 @@ import test from '../../'; test('throw an uncaught exception', () => { setImmediate(() => { - throw () => {}; + throw function () {}; }); });