mocha-unfunk-reporter
Version:
Mocha reporter without console funkyness
607 lines (538 loc) • 22.5 kB
JavaScript
var unfunk;
(function (unfunk) {
(function (error) {
var splitLine = /[\r\n]+/g;
error.moduleFilters = ['mocha', 'chai', 'proclaim', 'assert', 'expect', 'should', 'chai-as-promised', 'q', 'mocha-as-promised'];
error.nodeFilters = ['node.js'];
error.webFilters = ['mocha.js', 'chai.js', 'assert.js', 'proclaim.js'];
var assertType = /^AssertionError/;
var anyLinExp = /^ *(.*) *$/gm;
var stackLineExp = /^ at (.+)$/;
var anyLinExp = /^ *(.*) *$/gm;
var StackElement = (function () {
function StackElement(text, lineRef) {
this.text = text;
this.lineRef = lineRef;
}
return StackElement;
})();
error.StackElement = StackElement;
var ParsedError = (function () {
function ParsedError(error) {
this.name = '';
this.message = '<no message>';
this.stack = [];
this.isAssertion = false;
this.error = error;
}
ParsedError.prototype.getStandard = function (prepend, indent) {
if (typeof prepend === "undefined") { prepend = ''; }
if (typeof indent === "undefined") { indent = ''; }
var ret = this.getHeader(prepend);
ret += '\n' + this.getHeadlessStack(prepend, indent);
return ret;
};
ParsedError.prototype.getHeader = function (prepend) {
if (typeof prepend === "undefined") { prepend = ''; }
if (this.isAssertion) {
return prepend + this.message;
}
return prepend + (this.name ? this.name + ': ' : '') + this.message;
};
ParsedError.prototype.getHeaderSingle = function (prepend) {
if (typeof prepend === "undefined") { prepend = ''; }
if (this.isAssertion) {
return prepend + (this.message.match(/^.*$/m)[0]);
}
return prepend + (this.name ? this.name + ': ' : '') + (this.message.match(/^.*$/m)[0]);
};
ParsedError.prototype.getHeadlessStack = function (prepend, indent) {
if (typeof prepend === "undefined") { prepend = ''; }
if (typeof indent === "undefined") { indent = ''; }
return this.stack.reduce(function (lines, element) {
if (element.lineRef) {
lines.push(prepend + indent + 'at ' + element.text);
} else {
lines.push(prepend + element.text);
}
return lines;
}, []).join('\n');
};
ParsedError.prototype.hasStack = function () {
return this.stack.length > 0;
};
ParsedError.prototype.toString = function () {
if (this.isAssertion) {
return this.message;
}
return (this.name ? this.name + ': ' : '<no name>') + this.message;
};
return ParsedError;
})();
error.ParsedError = ParsedError;
var StackFilter = (function () {
function StackFilter(style) {
this.style = style;
this.filters = [];
}
StackFilter.prototype.parse = function (error, stackFilter) {
var parsed = new ParsedError(error);
if (!error) {
parsed.name = '<undefined error>';
return parsed;
}
parsed.name = error.name;
parsed.isAssertion = assertType.test(parsed.name);
if (error.message) {
parsed.message = error.message;
} else if (error.operator) {
parsed.message = unfunk.toDebug(error.actual, 50) + ' ' + this.style.accent(error.operator) + ' ' + unfunk.toDebug(error.expected, 50) + '';
}
if (error.stack) {
var stack = error.stack;
var seenAt = false;
var lineMatch;
var stackLineMatch;
anyLinExp.lastIndex = 0;
while ((lineMatch = anyLinExp.exec(stack))) {
anyLinExp.lastIndex = lineMatch.index + (lineMatch[0].length || 1);
if (!lineMatch[1]) {
continue;
}
stackLineExp.lastIndex = 0;
stackLineMatch = stackLineExp.exec(lineMatch[0]);
if (stackLineMatch) {
parsed.stack.push(new StackElement(stackLineMatch[1], true));
seenAt = true;
continue;
} else if (seenAt) {
parsed.stack.push(new StackElement(lineMatch[1], false));
}
}
if (stackFilter) {
parsed.stack = this.filter(parsed.stack);
}
} else {
parsed.stack.push(new StackElement('<no error.stack>', false));
}
return parsed;
};
StackFilter.prototype.addModuleFilters = function (filters) {
var _this = this;
filters.forEach(function (filter) {
filter = '/node_modules/' + filter + '/';
var exp = new RegExp(filter.replace(/\\|\//g, '(\\\\|\\/)'));
_this.filters.push(exp);
}, this);
};
StackFilter.prototype.addFilters = function (filters) {
var _this = this;
filters.forEach(function (filter) {
var exp = new RegExp(filter.replace(/\\|\//g, '(\\\\|\\/)'));
_this.filters.push(exp);
}, this);
};
StackFilter.prototype.filter = function (lines) {
if (lines.length === 0) {
return [new StackElement('<no lines in stack>', false)];
}
if (this.filters.length === 0) {
return lines;
}
var cut = -1;
var i, line;
for (i = lines.length - 1; i >= 0; i--) {
line = lines[i];
if (this.filters.some(function (filter) {
return filter.test(line.text);
})) {
cut = i;
} else if (cut > -1) {
break;
}
}
if (cut > 0) {
lines = lines.splice(0, cut);
}
if (lines.length === 0) {
return [new StackElement('<no unfiltered calls in stack>', false)];
}
return lines;
};
return StackFilter;
})();
error.StackFilter = StackFilter;
})(unfunk.error || (unfunk.error = {}));
var error = unfunk.error;
})(unfunk || (unfunk = {}));
var unfunk;
(function (unfunk) {
var jsesc = require('jsesc');
var ministyle = require('ministyle');
var miniwrite = require('miniwrite');
var DiffFormatter = require('unfunk-diff').DiffFormatter;
var Stats = (function () {
function Stats() {
this.suites = 0;
this.tests = 0;
this.passes = 0;
this.pending = 0;
this.failures = 0;
this.duration = 0;
this.start = 0;
this.end = 0;
}
return Stats;
})();
unfunk.Stats = Stats;
var expose;
var options = {
writer: 'log',
style: 'ansi',
stream: null,
stackFilter: true,
reportPending: false,
width: 0
};
var tty = require('tty');
var isatty = (tty.isatty('1') && tty.isatty('2'));
function getViewWidth() {
if (options.width > 0) {
return options.width;
}
if (isatty) {
return Math.min(options.width, process.stdout['getWindowSize'] ? process.stdout['getWindowSize'](1)[0] : tty.getWindowSize()[1]);
}
return 80;
}
function option(nameOrHash, value) {
if (arguments.length === 1) {
if (typeof nameOrHash === 'object') {
for (var name in nameOrHash) {
if (nameOrHash.hasOwnProperty(name)) {
options[name] = nameOrHash[name];
}
}
}
} else if (arguments.length === 2) {
if (typeof value !== 'undefined' && typeof nameOrHash === 'string') {
var propLower = nameOrHash.toLowerCase();
for (var name in options) {
if (options.hasOwnProperty(name)) {
var nameLower = name.toLowerCase();
if (nameLower === propLower) {
options[name] = value;
}
}
}
}
}
return expose;
}
function importEnv() {
var pattern = /^mocha[_-]unfunk[_-]([\w]+(?:[\w_-][\w]+)*)$/i;
var obj;
if (typeof process !== 'undefined' && process.env) {
obj = process.env;
}
if (obj) {
for (var name in obj) {
if (Object.prototype.hasOwnProperty.call(obj, name)) {
pattern.lastIndex = 0;
var match = pattern.exec(name);
if (match && match.length > 1) {
var prop = match[1].toLowerCase();
option(prop, obj[name]);
}
}
}
}
}
var escapableExp = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
var meta = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
'\\': '\\\\'
};
var jsonNW = {
json: true,
wrap: false,
quotes: 'double'
};
function escape(str) {
escapableExp.lastIndex = 0;
if (escapableExp.test(str)) {
return str.replace(escapableExp, function (a) {
var c = meta[a];
if (typeof c === 'string') {
return c;
}
return jsesc(a, jsonNW);
});
}
return str;
}
unfunk.escape = escape;
function stringTrueish(str) {
str = ('' + str).toLowerCase();
return str != '' && str != 'false' && str != '0' && str != 'null' && str != 'undefined';
}
unfunk.stringTrueish = stringTrueish;
function toDebug(value, cutoff) {
if (typeof cutoff === "undefined") { cutoff = 20; }
var t = typeof value;
if (t === 'function') {
t = '' + t;
}
if (t === 'object') {
var str = '';
var match = Object.prototype.toString.call(value).match(/^\[object ([\S]*)]$/);
if (match && match.length > 1 && match[1] !== 'Object') {
str = match[1];
}
value = str + JSON.stringify(value);
if (value.length > cutoff) {
value = value.substr(0, cutoff) + '...';
}
return value;
}
if (t === 'string') {
if (value.length > cutoff) {
return '"' + escape(value.substr(0, cutoff)) + '"' + '...';
}
return '"' + escape(value) + '"';
}
return '' + value;
}
unfunk.toDebug = toDebug;
function padLeft(str, len, char) {
str = String(str);
char = String(char).charAt(0);
while (str.length < len) {
str = char + str;
}
return str;
}
unfunk.padLeft = padLeft;
function padRight(str, len, char) {
str = String(str);
char = String(char).charAt(0);
while (str.length < len) {
str += char;
}
return str;
}
unfunk.padRight = padRight;
function getStyler() {
switch (options.style) {
case 'no':
case 'none':
case 'plain':
return ministyle.plain();
case 'dev':
return ministyle.dev();
case 'html':
return ministyle.html();
case 'css':
return ministyle.css();
case 'ansi':
default:
return ministyle.ansi();
}
}
function getWriter() {
if (options.stream) {
return miniwrite.chars(miniwrite.stream(options.stream));
}
switch (options.writer) {
case 'stdout':
return miniwrite.chars(miniwrite.stream(process.stdout));
case 'null':
return miniwrite.chars(miniwrite.base());
case 'log':
default:
return miniwrite.chars(miniwrite.log());
}
}
function pluralize(word, amount, plurl) {
if (typeof plurl === "undefined") { plurl = 's'; }
return amount + ' ' + (1 == amount ? word : word + plurl);
}
unfunk.pluralize = pluralize;
var Unfunk = (function () {
function Unfunk(runner) {
this.init(runner);
}
Unfunk.prototype.init = function (runner) {
importEnv();
var stats = this.stats = new Stats();
var out = getWriter();
var style = getStyler();
var diffFormat = new DiffFormatter(style, getViewWidth());
var stackFilter = new unfunk.error.StackFilter(style);
if (options.stackFilter) {
stackFilter.addFilters(unfunk.error.nodeFilters);
stackFilter.addFilters(unfunk.error.webFilters);
stackFilter.addModuleFilters(unfunk.error.moduleFilters);
}
runner.stats = stats;
var indents = 0;
var indenter = ' ';
var failures = this.failures = [];
var pending = this.pending = [];
var suiteStack = [];
var currentSuite;
var indent = function (add) {
if (typeof add === "undefined") { add = 0; }
return Array(indents + add + 1).join(indenter);
};
var indentLen = function (amount) {
if (typeof amount === "undefined") { amount = 1; }
return amount * indenter.length;
};
var start;
runner.on('start', function () {
stats.start = new Date().getTime();
out.writeln(style.plain(''));
});
runner.on('suite', function (suite) {
if (indents === 0) {
if (suite.suites) {
out.writeln(style.accent('->') + ' running ' + style.accent(pluralize('suite', suite.suites.length)));
} else {
out.writeln(style.accent('->') + ' running suites');
}
out.writeln('');
}
suite.parent = currentSuite;
suiteStack.push(suite);
currentSuite = suite;
stats.suites++;
if (!suite.root && suite.title) {
out.writeln(indent() + style.accent(suite.title));
}
indents++;
});
runner.on('suite end', function (suite) {
indents--;
suiteStack.pop();
if (suiteStack.length > 0) {
currentSuite = suiteStack[suiteStack.length - 1];
} else {
currentSuite = null;
}
if (1 == indents && !suite.root) {
out.writeln('');
}
});
runner.on('test', function (test) {
stats.tests++;
out.write(indent(0) + style.plain(test.title + '.. '));
});
runner.on('pending', function (test) {
stats.pending++;
out.writeln(indent(0) + style.plain(test.title + '.. ') + style.warning('pending'));
pending.push(test);
});
runner.on('pass', function (test) {
stats.passes++;
var medium = test.slow() / 2;
test.speed = test.duration > test.slow() ? 'slow' : (test.duration > medium ? 'medium' : 'fast');
if (test.speed === 'slow') {
out.writeln(style.success(test.speed) + style.error(' (' + test.duration + 'ms)'));
} else if (test.speed === 'medium') {
out.writeln(style.success(test.speed) + style.warning(' (' + test.duration + 'ms)'));
} else {
out.writeln(style.success('ok'));
}
});
runner.on('fail', function (test, err) {
stats.failures++;
out.writeln(style.error('fail'));
test.err = err;
test.parsed = stackFilter.parse(err, options.stackFilter);
out.writeln(style.error(padRight(stats.failures + ': ', indentLen(indents + 1), ' ')) + style.warning(test.parsed.getHeaderSingle()));
failures.push(test);
});
runner.on('end', function () {
var test;
var sum = '';
var fail;
indents = 0;
stats.end = new Date().getTime();
stats.duration = stats.end - stats.start;
if (stats.tests > 0) {
if (stats.failures > 0) {
fail = style.error('failed ' + stats.failures);
sum += fail + ' and ';
}
if (stats.passes == stats.tests) {
sum += style.success('passed ' + stats.passes);
} else if (stats.passes === 0) {
sum += style.error('passed ' + stats.passes);
} else {
sum += style.warning('passed ' + stats.passes);
}
sum += ' of ';
sum += style.accent(pluralize('test', stats.tests));
} else {
sum += style.warning(pluralize('test', stats.tests));
}
if (pending.length > 0) {
sum += ', left ' + style.warning(stats.pending + ' pending');
}
if (options.reportPending && pending.length > 0) {
out.writeln(style.accent('->') + ' reporting ' + style.warning(pluralize('pending spec', pending.length)));
out.writeln('');
pending.forEach(function (test, num) {
var tmp = test.fullTitle();
var ind = tmp.lastIndexOf(test.title);
var title = style.accent(tmp.substring(0, ind)) + style.plain(tmp.substring(ind));
out.writeln(style.warning(padRight((num + 1) + ': ', indentLen(2), ' ')) + title);
});
out.writeln('');
}
if (failures.length > 0) {
out.writeln(style.accent('->') + ' reporting ' + style.error(pluralize('failure', failures.length)));
out.writeln('');
failures.forEach(function (test, num) {
var tmp = test.fullTitle();
var ind = tmp.lastIndexOf(test.title);
var title = style.accent(tmp.substring(0, ind)) + style.plain(tmp.substring(ind));
var err = test.err;
var parsed = test.parsed;
var msg = parsed.getHeader();
out.writeln(style.error(padRight((num + 1) + ': ', indentLen(2), ' ')) + title);
out.writeln('');
out.writeln(indent(2) + style.warning(msg));
if (parsed.hasStack()) {
out.writeln(parsed.getHeadlessStack(indent(2), indenter));
out.writeln('');
} else {
out.writeln('');
}
if (err.showDiff || diffFormat.forcedDiff(err.actual, err.expected)) {
var diff = diffFormat.getStyledDiff(err.actual, err.expected, indent(2));
if (diff) {
out.writeln(diff);
out.writeln('');
}
}
});
}
out.writeln(style.plain('-> ') + sum + ' (' + (stats.duration) + 'ms)');
out.writeln('');
});
};
return Unfunk;
})();
unfunk.Unfunk = Unfunk;
expose = Unfunk;
expose.option = option;
(module).exports = expose;
})(unfunk || (unfunk = {}));
//# sourceMappingURL=unfunk.js.map