Skip to content

Commit

Permalink
Merge a16d815 into f1fe632
Browse files Browse the repository at this point in the history
  • Loading branch information
plroebuck committed Apr 13, 2019
2 parents f1fe632 + a16d815 commit 5720413
Show file tree
Hide file tree
Showing 8 changed files with 765 additions and 253 deletions.
1 change: 1 addition & 0 deletions lib/reporters/base.js
Expand Up @@ -278,6 +278,7 @@ function Base(runner, options) {
this.options = options || {};
this.runner = runner;
this.stats = runner.stats; // assigned so Reporters keep a closer reference
this.preferConsole = !!(this.options.reporterOptions || {}).preferConsole;

runner.on(EVENT_TEST_PASS, function(test) {
if (test.duration > test.slow()) {
Expand Down
73 changes: 73 additions & 0 deletions lib/reporters/writers/console.js
@@ -0,0 +1,73 @@
'use strict';

/**
* Save timer references (mochajs/mocha#237).
*/
var setTimeout = global.setTimeout;

/**
* Provides methods used for output by console-oriented reporters.
*
* @description
* Not meant to be used directly.
*
* @package
* @mixin ConsoleWriter
*/
var ConsoleWriter = function() {
var buffer = '';

/**
* Writes string to reporter output.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.write = function(str) {
if (str) {
buffer += str; // Store until `console.log` invoked
}
return this;
};

/**
* Writes newline-terminated string to reporter output.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.writeln = function(str) {
this.write(str);
console.log(buffer);
buffer = ''; // Reset
return this;
};

/**
* Invokes provided completion function.
*
* @description
* Writes any buffered output.
*
* @package
* @param {Function} cb - Callback invoked when cleanup done
*/
this._done = function(cb) {
if (buffer) {
var delay = 1000; // One second

this.writeln();
setTimeout(cb, delay);
} else {
cb();
}
};

return this;
};

module.exports = ConsoleWriter;
97 changes: 97 additions & 0 deletions lib/reporters/writers/file.js
@@ -0,0 +1,97 @@
'use strict';

/**
* Module dependencies.
*/
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var errors = require('../../errors');

var createUnsupportedError = errors.createUnsupportedError;

/**
* Provides methods used for output by file-oriented reporters.
*
* @description
* Not meant to be used directly.
*
* @package
* @mixin FileWriter
*/
var FileWriter = function() {
/**
* Writes string to reporter output.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.write = function(str) {
this._fileStream.write(str);
return this;
};

/**
* Writes newline-terminated string to reporter output.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.writeln = function(str) {
return this.write(str + '\n');
};

/**
* Invokes provided completion function.
*
* @description
* Closes the filesystem output stream.
*
* @package
* @param {Function} cb - Callback invoked when cleanup done
*/
this._done = function(cb) {
var self = this;
this._fileStream.end(function() {
self._fileStream = null;
cb();
});
};

return this;
};

/**
* Creates filesystem output stream, if possible.
*
* @static
* @package
* @param {Object} reporter - Instance of reporter
* @param {string} pathname - Pathname of desired output file
* @throws Various errors are possible
*/
FileWriter.createWriteStream = function(reporter, pathname) {
if (!fs.createWriteStream) {
throw createUnsupportedError('file output not supported in browser');
}

mkdirp.sync(path.dirname(pathname));
reporter._fileStream = fs.createWriteStream(pathname);
};

/**
* Determines if writer should write output to filesystem.
*
* @public
* @static
* @returns {boolean} whether writer should use `FileWriter` methods
*/
FileWriter.isFileWriter = function(reporter) {
return reporter.hasOwnProperty('_fileStream') && !!reporter._fileStream;
};

module.exports = FileWriter;
3 changes: 3 additions & 0 deletions lib/reporters/writers/index.js
@@ -0,0 +1,3 @@
'use strict';

exports.ReportWriter = require('./report');
181 changes: 181 additions & 0 deletions lib/reporters/writers/report.js
@@ -0,0 +1,181 @@
'use strict';

/**
* Module dependencies.
*/
var sprintf = require('util').format;
var ConsoleWriter = require('./console');
var FileWriter = require('./file');
var StreamWriter = require('./stream');

/**
* Provides methods used for output by reporters.
*
* @description
* Not meant to be used directly. Runtime-adaptive.
* Once _any_ functional mixin method is iinvoked, specializations will occur
* which may augment/replace existing methods/properties.
*
* @public
* @mixin ReportWriter
* @example
* var ReportWriter = require('./writers/report');
* var MyReporter = function(runner, options) {
* runner.on(EVENT_TEST_PASS, function(test) {
* this.println(test);
* });
* };
* ReportWriter.call(MyReporter.prototype);
*/
var ReportWriter = function() {
/**
* Adapts prototype methods to specific output destination.
*
* @param {Object} reporter - Reporter instance
* @returns {reporter}
* @chainable
*/
function adapt(reporter) {
var preferConsole = !!reporter.preferConsole;

// :DEBUG: console.log('reporter:', reporter);
if (ReportWriter.isFileWriter(reporter)) {
// :DEBUG: console.log('### specialized as FileWriter');
FileWriter.call(reporter);
} else if (!preferConsole && ReportWriter.stdoutExists()) {
// :DEBUG: console.log('### specialized as StreamWriter');
StreamWriter.call(reporter);
} else {
// :DEBUG: console.log('### specialized as ConsoleWriter');
ConsoleWriter.call(reporter);
}

return reporter;
}

/**
* Writes string to reporter output.
*
* @description
* Overrides this class method by creating same-named instance method.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.write = function(str) {
return adapt(this).write(str);
};

/**
* Writes newline-terminated string to reporter output.
*
* @description
* Overrides this class method by creating same-named instance method.
*
* @package
* @param {string} str - String to write to the reporter output.
* @returns {this}
* @chainable
*/
this.writeln = function(str) {
return adapt(this).writeln(str);
};

/**
* Writes formatted string to reporter output.
* @see {@link https://nodejs.org/api/util.html#util_util_format_format_args}
*
* @package
* @param {string} format - `printf`-like format string
* @param {...*} [varArgs] - Format string arguments
* @returns {this}
* @chainable
*/
this.print = function(format, varArgs) {
var vargs = Array.prototype.slice.call(arguments);
var str = sprintf.apply(null, vargs);
return this.write(str);
};

/**
* Writes newline-terminated formatted string to reporter output.
*
* @package
* @param {string} format - `printf`-like format string
* @param {...*} [varArgs] - Format string arguments
* @returns {this}
* @chainable
*/
this.println = function(format, varArgs) {
var vargs = Array.prototype.slice.call(arguments);
vargs[0] += '\n';
return this.print(this, vargs);
};

/**
* Invokes provided completion function.
*
* @package
* @param {number} nfailures - Count of failed tests (integer)
* @param {DoneCB} fn - Callback invoked when test execution completes
*/
this.done = function(nfailures, fn) {
if (this._done) {
this._done(function() {
fn(nfailures);
});
} else {
fn(nfailures);
}
};

return this;
};

/**
* Attempts creation of filesystem output stream, if
* <code>reporter.options.output</code> given.
*
* @public
* @static
* @param {Object} reporter - Instance of reporter
* @throws Various errors are possible if file creation attempted
*/
ReportWriter.maybeCreateFileOutput = function(reporter) {
var reporterOptions = (reporter.options || {}).reporterOptions || {};
var pathname = reporterOptions.output;

if (pathname) {
FileWriter.createWriteStream(reporter, pathname);
}
};

/**
* Determines if writer can write output to filesystem.
*
* @private
* @static
* @param {Object} reporter - Instance of reporter
* @returns {boolean} whether writer should use `FileWriter` methods
*/
ReportWriter.isFileWriter = function(reporter) {
return FileWriter.isFileWriter(reporter);
};

/**
* Determines if `process.stdout` exists in current execution environment.
*
* @description
* On PhantomJS, `process.stdout` doesn't exist...
*
* @public
* @static
* @returns {boolean} whether `process.stdout` can be used
*/
ReportWriter.stdoutExists = function() {
return typeof process === 'object' && !!process.stdout;
};

module.exports = ReportWriter;

0 comments on commit 5720413

Please sign in to comment.