diff --git a/lib/reporters/base.js b/lib/reporters/base.js index e7b93b24b8..1a47481c96 100644 --- a/lib/reporters/base.js +++ b/lib/reporters/base.js @@ -270,9 +270,7 @@ exports.list = function(failures) { * Initialize a new `Base` reporter. * * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. + * inherit from this reporter. * * @memberof Mocha.reporters * @public @@ -281,39 +279,15 @@ exports.list = function(failures) { */ function Base(runner) { - var stats = (this.stats = { - suites: 0, - tests: 0, - passes: 0, - pending: 0, - failures: 0 - }); var failures = (this.failures = []); if (!runner) { - return; + throw new TypeError('Missing runner argument'); } + this.stats = runner.stats; // assigned so Reporters keep a closer reference this.runner = runner; - runner.stats = stats; - - runner.on('start', function() { - stats.start = new Date(); - }); - - runner.on('suite', function(suite) { - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function() { - stats.tests = stats.tests || 0; - stats.tests++; - }); - runner.on('pass', function(test) { - stats.passes = stats.passes || 0; - if (test.duration > test.slow()) { test.speed = 'slow'; } else if (test.duration > test.slow() / 2) { @@ -321,28 +295,15 @@ function Base(runner) { } else { test.speed = 'fast'; } - - stats.passes++; }); runner.on('fail', function(test, err) { - stats.failures = stats.failures || 0; - stats.failures++; if (showDiff(err)) { stringifyDiffObjs(err); } test.err = err; failures.push(test); }); - - runner.once('end', function() { - stats.end = new Date(); - stats.duration = stats.end - stats.start; - }); - - runner.on('pending', function() { - stats.pending++; - }); } /** diff --git a/lib/runner.js b/lib/runner.js index 15f5e40172..8e1bdf3958 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -12,6 +12,7 @@ var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:runner'); var Runnable = require('./runnable'); +var createStatsCollector = require('./stats-collector'); var stackFilter = utils.stackTraceFilter(); var stringify = utils.stringify; var type = utils.type; @@ -80,6 +81,7 @@ function Runner(suite, delay) { this._defaultGrep = /.*/; this.grep(this._defaultGrep); this.globals(this.globalProps().concat(extraGlobals())); + createStatsCollector(this); } /** diff --git a/lib/stats-collector.js b/lib/stats-collector.js new file mode 100644 index 0000000000..1c1491ca81 --- /dev/null +++ b/lib/stats-collector.js @@ -0,0 +1,70 @@ +'use strict'; + +/** + * Test statistics collector. + * + * @typedef {Object} StatsCollector + * @property {number} suites - integer count of suites run. + * @property {number} tests - integer count of tests run. + * @property {number} passes - integer count of passing tests. + * @property {number} pending - integer count of pending tests. + * @property {number} failures - integer count of failed tests. + * @property {Date} start - time when testing began. + * @property {Date} end - time when testing concluded. + * @property {number} duration - number of msecs that testing took. + */ + +/** + * Provides stats such as test duration, + * number of tests passed / failed etc. + * + * @public + * @memberof Mocha + * @param {Runner} runner + */ +function createStatsCollector(runner) { + var stats = { + suites: 0, + tests: 0, + passes: 0, + pending: 0, + failures: 0 + }; + + if (!runner) { + throw new TypeError('Missing runner argument'); + } + + runner.stats = stats; + + runner.once('start', function() { + stats.start = new Date(); + }); + + runner.on('suite', function(suite) { + suite.root || stats.suites++; + }); + + runner.on('pass', function() { + stats.passes++; + }); + + runner.on('fail', function() { + stats.failures++; + }); + + runner.on('pending', function() { + stats.pending++; + }); + + runner.on('test end', function() { + stats.tests++; + }); + + runner.once('end', function() { + stats.end = new Date(); + stats.duration = stats.end - stats.start; + }); +} + +module.exports = createStatsCollector; diff --git a/test/reporters/helpers.js b/test/reporters/helpers.js index 4da36fa600..bd49392a40 100644 --- a/test/reporters/helpers.js +++ b/test/reporters/helpers.js @@ -8,6 +8,8 @@ scope of this function for the tests to run properly. */ +var createStatsCollector = require('../../lib/stats-collector'); + function createMockRunner(runStr, ifStr1, ifStr2, ifStr3, arg1, arg2) { var runnerFunction = createRunnerFunction( runStr, @@ -17,10 +19,12 @@ function createMockRunner(runStr, ifStr1, ifStr2, ifStr3, arg1, arg2) { arg1, arg2 ); - return { + var mockRunner = { on: runnerFunction, once: runnerFunction }; + createStatsCollector(mockRunner); + return mockRunner; } function createRunnerFunction(runStr, ifStr1, ifStr2, ifStr3, arg1, arg2) { diff --git a/test/reporters/list.spec.js b/test/reporters/list.spec.js index 78895796c4..5abbe0bf69 100644 --- a/test/reporters/list.spec.js +++ b/test/reporters/list.spec.js @@ -21,6 +21,7 @@ describe('List reporter', function() { duration: expectedDuration, slow: function() {} }; + beforeEach(function() { useColors = Base.useColors; Base.useColors = false; @@ -126,7 +127,11 @@ describe('List reporter', function() { test = {}; runner = createMockRunner('fail', 'fail', null, null, test); runner.on = runner.once = function(event, callback) { - if (!checked && event === 'fail') { + if ( + !checked && + event === 'fail' && + callback.toString().includes('stringifyDiffObjs') // target correct fail event callback + ) { err = new Error('fake failure object with actual/expected'); err.actual = actual; err.expected = expected; diff --git a/test/reporters/xunit.spec.js b/test/reporters/xunit.spec.js index 42e9ca2c6e..4cbf76c646 100644 --- a/test/reporters/xunit.spec.js +++ b/test/reporters/xunit.spec.js @@ -4,12 +4,14 @@ var fs = require('fs'); var mkdirp = require('mkdirp'); var path = require('path'); var assert = require('assert'); +var createStatsCollector = require('../../lib/stats-collector'); var reporters = require('../../').reporters; var XUnit = reporters.XUnit; describe('XUnit reporter', function() { var stdout; var stdoutWrite; + // the runner parameter of the reporter var runner; var callbackArgument = null; @@ -26,6 +28,7 @@ describe('XUnit reporter', function() { beforeEach(function() { stdout = []; runner = {on: function() {}, once: function() {}}; + createStatsCollector(runner); }); describe('if reporter options output is given', function() { @@ -322,8 +325,6 @@ describe('XUnit reporter', function() { describe('custom suite name', function() { // capture the events that the reporter subscribes to var events; - // the runner parameter of the reporter - var runner; // capture output lines (will contain the resulting XML of the xunit reporter) var lines; // the file stream into which the xunit reporter will write into @@ -332,13 +333,10 @@ describe('XUnit reporter', function() { beforeEach(function() { events = {}; - runner = { - on: function(eventName, eventHandler) { - // capture the event handler - events[eventName] = eventHandler; - } + runner.on = runner.once = function(eventName, eventHandler) { + // capture the event handler + events[eventName] = eventHandler; }; - runner.once = runner.on; lines = []; fileStream = {