From cc9195530269e031e3cf03e014dc4d2c5baf570f Mon Sep 17 00:00:00 2001 From: Josh Eversmann Date: Fri, 28 Oct 2016 16:04:19 -0500 Subject: [PATCH 1/2] fix circular objects in json reporter. Closes #2433 --- lib/reporters/json.js | 13 ++++++++++++- mocha.js | 13 ++++++++++++- test/reporters/json.spec.js | 27 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/reporters/json.js b/lib/reporters/json.js index 259a782121..eb2044e5b7 100644 --- a/lib/reporters/json.js +++ b/lib/reporters/json.js @@ -54,7 +54,18 @@ function JSONReporter (runner) { runner.testResults = obj; - process.stdout.write(JSON.stringify(obj, null, 2)); + var cache = []; + process.stdout.write(JSON.stringify(obj, function (key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + }, 2)); }); } diff --git a/mocha.js b/mocha.js index 16d5619e27..4febc4ed96 100644 --- a/mocha.js +++ b/mocha.js @@ -3061,7 +3061,18 @@ function JSONReporter (runner) { runner.testResults = obj; - process.stdout.write(JSON.stringify(obj, null, 2)); + var cache = []; + process.stdout.write(JSON.stringify(obj, function (key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + }, 2)); }); } diff --git a/test/reporters/json.spec.js b/test/reporters/json.spec.js index 74151fdc8b..ff36269765 100644 --- a/test/reporters/json.spec.js +++ b/test/reporters/json.spec.js @@ -60,4 +60,31 @@ describe('json reporter', function () { done(); }); }); + + it('should handle circular objects in errors', function (done) { + var testTitle = 'json test 1'; + function CircleError () { + this.message = 'oh shit'; + this.circular = this; + } + var error = new CircleError(); + + suite.addTest(new Test(testTitle, function (done) { + throw error; + })); + + runner.run(function (failureCount) { + failureCount.should.be.exactly(1); + runner.should.have.property('testResults'); + runner.testResults.should.have.property('failures'); + runner.testResults.failures.should.be.an.instanceOf(Array); + runner.testResults.failures.should.have.a.lengthOf(1); + + var failure = runner.testResults.failures[0]; + failure.should.have.property('title', testTitle); + failure.should.have.properties('err'); + + done(); + }); + }); }); From c446ac5f73d283450520d1a1f54c0e2a4a17a7a7 Mon Sep 17 00:00:00 2001 From: Josh Eversmann Date: Thu, 3 Nov 2016 09:43:33 -0500 Subject: [PATCH 2/2] move circular object logic into clean --- lib/reporters/json.js | 43 +++++++++++++++++++++++++++++-------------- mocha.js | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/lib/reporters/json.js b/lib/reporters/json.js index eb2044e5b7..ed8fc70c1f 100644 --- a/lib/reporters/json.js +++ b/lib/reporters/json.js @@ -54,18 +54,7 @@ function JSONReporter (runner) { runner.testResults = obj; - var cache = []; - process.stdout.write(JSON.stringify(obj, function (key, value) { - if (typeof value === 'object' && value !== null) { - if (cache.indexOf(value) !== -1) { - // Instead of going in a circle, we'll print [object Object] - return '' + value; - } - cache.push(value); - } - - return value; - }, 2)); + process.stdout.write(JSON.stringify(obj, null, 2)); }); } @@ -78,17 +67,43 @@ function JSONReporter (runner) { * @return {Object} */ function clean (test) { + var err = test.err || {}; + if (err instanceof Error) { + err = errorJSON(err); + } + return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, currentRetry: test.currentRetry(), - err: errorJSON(test.err || {}) + err: cleanCycles(err) }; } +/** + * Replaces any circular references inside `obj` with '[object Object]' + * + * @api private + * @param {Object} obj + * @return {Object} + */ +function cleanCycles (obj) { + var cache = []; + return JSON.parse(JSON.stringify(obj, function (key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + })); +} /** - * Transform `error` into a JSON object. + * Transform an Error object into a JSON object. * * @api private * @param {Error} err diff --git a/mocha.js b/mocha.js index 4febc4ed96..176ed9d413 100644 --- a/mocha.js +++ b/mocha.js @@ -3061,18 +3061,7 @@ function JSONReporter (runner) { runner.testResults = obj; - var cache = []; - process.stdout.write(JSON.stringify(obj, function (key, value) { - if (typeof value === 'object' && value !== null) { - if (cache.indexOf(value) !== -1) { - // Instead of going in a circle, we'll print [object Object] - return '' + value; - } - cache.push(value); - } - - return value; - }, 2)); + process.stdout.write(JSON.stringify(obj, null, 2)); }); } @@ -3085,17 +3074,43 @@ function JSONReporter (runner) { * @return {Object} */ function clean (test) { + var err = test.err || {}; + if (err instanceof Error) { + err = errorJSON(err); + } + return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, currentRetry: test.currentRetry(), - err: errorJSON(test.err || {}) + err: cleanCycles(err) }; } +/** + * Replaces any circular references inside `obj` with '[object Object]' + * + * @api private + * @param {Object} obj + * @return {Object} + */ +function cleanCycles (obj) { + var cache = []; + return JSON.parse(JSON.stringify(obj, function (key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + })); +} /** - * Transform `error` into a JSON object. + * Transform an Error object into a JSON object. * * @api private * @param {Error} err