function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
function Context() {}
n/a
function Dot(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var n = -1; runner.on('start', function () { process.stdout.write('\n'); }); runner.on('pending', function () { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('pending', Base.symbols.comma)); }); runner.on('pass', function (test) { if (++n % width === 0) { process.stdout.write('\n '); } if (test.speed === 'slow') { process.stdout.write(color('bright yellow', Base.symbols.dot)); } else { process.stdout.write(color(test.speed, Base.symbols.dot)); } }); runner.on('fail', function () { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('fail', Base.symbols.bang)); }); runner.on('end', function () { console.log(); self.epilogue(); }); }
n/a
function Hook(title, fn) { Runnable.call(this, title, fn); this.type = 'hook'; }
...
self.suite = suite;
if (!suite) {
self.suite = orig;
return fn();
}
self.hook(name, function (err) {
if (err) {
var errSuite = self.suite;
self.suite = orig;
return fn(err, errSuite);
}
next(suites.pop());
...
function HTML(runner) { Base.call(this, runner); var self = this; var stats = this.stats; var stat = fragment(statsTemplate); var items = stat.getElementsByTagName('li'); var passes = items[1].getElementsByTagName('em')[0]; var passesLink = items[1].getElementsByTagName('a')[0]; var failures = items[2].getElementsByTagName('em')[0]; var failuresLink = items[2].getElementsByTagName('a')[0]; var duration = items[3].getElementsByTagName('em')[0]; var canvas = stat.getElementsByTagName('canvas')[0]; var report = fragment('<ul id="mocha-report"></ul>'); var stack = [report]; var progress; var ctx; var root = document.getElementById('mocha'); if (canvas.getContext) { var ratio = window.devicePixelRatio || 1; canvas.style.width = canvas.width; canvas.style.height = canvas.height; canvas.width *= ratio; canvas.height *= ratio; ctx = canvas.getContext('2d'); ctx.scale(ratio, ratio); progress = new Progress(); } if (!root) { return error('#mocha div missing, add it to your document'); } // pass toggle on(passesLink, 'click', function (evt) { evt.preventDefault(); unhide(); var name = (/pass/).test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test pass'); } }); // failure toggle on(failuresLink, 'click', function (evt) { evt.preventDefault(); unhide(); var name = (/fail/).test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test fail'); } }); root.appendChild(stat); root.appendChild(report); if (progress) { progress.size(40); } runner.on('suite', function (suite) { if (suite.root) { return; } // suite var url = self.suiteURL(suite); var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title)); // container stack[0].appendChild(el); stack.unshift(document.createElement('ul')); el.appendChild(stack[0]); }); runner.on('suite end', function (suite) { if (suite.root) { updateStats(); return; } stack.shift(); }); runner.on('pass', function (test) { var url = self.testURL(test); var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> ' + '<a href="%s" class="replay">' + playIcon + '</a></h2></li>'; var el = fragment(markup, test.speed, test.title, test.duration, url); self.addCodeToggle(el, test.body); appendToStack(el); updateStats(); }); runner.on('fail', function (test) { var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">' + playIcon + '</a></h2></li>', test.title, self.testURL(test)); var stackString; // Note: Includes leading newline var message = test.err.toString(); // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we // check for the result of the stringifying. if (message === '[object Error]') { message = test.err.message; } if (test.err.stack) { var indexOfMessage = test.err.stack.indexOf(test.err.message); if (indexOfMessage === -1) { stackString = test.err.stack; } else { stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; } stackString = stackString || ''; if (test.err.htmlMessage && stackString) { el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>', test.err.htmlMessage, stackString)); } else if (test.err.htmlMessage) { el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage)); } else { el.app ...
n/a
function Landing(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var total = runner.total; var stream = process.stdout; var plane = color('plane', '✈'); var crashed = -1; var n = 0; function runway () { var buf = Array(width).join('-'); return ' ' + color('runway', buf); } runner.on('start', function () { stream.write('\n\n\n '); cursor.hide(); }); runner.on('test end', function (test) { // check if the plane crashed var col = crashed === -1 ? width * ++n / total | 0 : crashed; // show the crash if (test.state === 'failed') { plane = color('plane crash', '✈'); crashed = col; } // render landing strip stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); stream.write(runway()); stream.write('\n '); stream.write(color('runway', Array(col).join('⋅'))); stream.write(plane); stream.write(color('runway', Array(width - col).join('⋅') + '\n')); stream.write(runway()); stream.write('\u001b[0m'); }); runner.on('end', function () { cursor.show(); console.log(); self.epilogue(); }); }
n/a
function List(runner) { Base.call(this, runner); var self = this; var n = 0; runner.on('start', function () { console.log(); }); runner.on('test', function (test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); runner.on('pending', function (test) { var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); runner.on('pass', function (test) { var fmt = color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s: ') + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); runner.on('fail', function (test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); runner.on('end', self.epilogue.bind(self)); }
...
// failures
if (stats.failures) {
fmt = color('fail', ' %d failing');
console.log(fmt, stats.failures);
Base.list(this.failures);
console.log();
}
console.log();
};
/**
...
function NyanCat(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var nyanCatWidth = this.nyanCatWidth = 11; this.colorIndex = 0; this.numberOfLines = 4; this.rainbowColors = self.generateColors(); this.scoreboardWidth = 5; this.tick = 0; this.trajectories = [[], [], [], []]; this.trajectoryWidthMax = (width - nyanCatWidth); runner.on('start', function () { Base.cursor.hide(); self.draw(); }); runner.on('pending', function () { self.draw(); }); runner.on('pass', function () { self.draw(); }); runner.on('fail', function () { self.draw(); }); runner.on('end', function () { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); } self.epilogue(); }); }
n/a
function Progress() { this.percent = 0; this.size(0); this.fontSize(11); this.font('helvetica, arial, sans-serif'); }
n/a
function Runnable(title, fn) { this.title = title; this.fn = fn; this.body = (fn || '').toString(); this.async = fn && fn.length; this.sync = !this.async; this._timeout = 2000; this._slow = 75; this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; }
...
*
* @api private
* @param {number} ms
* @return {Context} self
*/
Context.prototype.timeout = function (ms) {
if (!arguments.length) {
return this.runnable().timeout();
}
this.runnable().timeout(ms);
return this;
};
/**
* Set test timeout `enabled`.
...
function Runner(suite, delay) { var self = this; this._globals = []; this._abort = false; this._delay = delay; this.suite = suite; this.started = false; this.total = suite.total(); this.failures = 0; this.on('test end', function (test) { self.checkGlobals(test); }); this.on('hook end', function (hook) { self.checkGlobals(hook); }); this._defaultGrep = /.*/; this.grep(this._defaultGrep); this.globals(this.globalProps().concat(extraGlobals())); }
n/a
function Suite(title, parentContext) { if (!utils.isString(title)) { throw new Error('Suite `title` should be a "string" but "' + typeof title + '" was given instead.'); } this.title = title; function Context () {} Context.prototype = parentContext; this.ctx = new Context(); this.suites = []; this.tests = []; this.pending = false; this._beforeEach = []; this._beforeAll = []; this._afterEach = []; this._afterAll = []; this.root = !title; this._timeout = 2000; this._enableTimeouts = true; this._slow = 75; this._bail = false; this._retries = -1; this._onlyTests = []; this._onlySuites = []; this.delayed = false; }
n/a
function XUnit(runner, options) { Base.call(this, runner); var stats = this.stats; var tests = []; var self = this; if (options && options.reporterOptions && options.reporterOptions.output) { if (!fs.createWriteStream) { throw new Error('file output not supported in browser'); } mkdirp.sync(path.dirname(options.reporterOptions.output)); self.fileStream = fs.createWriteStream(options.reporterOptions.output); } runner.on('pending', function (test) { tests.push(test); }); runner.on('pass', function (test) { tests.push(test); }); runner.on('fail', function (test) { tests.push(test); }); runner.on('end', function () { self.write(tag('testsuite', { name: 'Mocha Tests', tests: stats.tests, failures: stats.failures, errors: stats.failures, skipped: stats.tests - stats.failures - stats.passes, timestamp: (new Date()).toUTCString(), time: (stats.duration / 1000) || 0 }, false)); tests.forEach(function (t) { self.test(t); }); self.write('</testsuite>'); }); }
n/a
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
color = function (type, str) { if (!exports.useColors) { return String(str); } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; }
...
*/
NyanCat.prototype.drawScoreboard = function () {
var stats = this.stats;
function draw (type, n) {
write(' ');
write(Base.color(type, n));
write('\n');
}
draw('green', stats.passes);
draw('fail', stats.failures);
draw('pending', stats.pending);
write('\n');
...
list = function (failures) { console.log(); failures.forEach(function (test, i) { // format var fmt = color('error title', ' %s) %s:\n') + color('error message', ' %s') + color('error stack', '\n%s\n'); // msg var msg; var err = test.err; var message; if (err.message && typeof err.message.toString === 'function') { message = err.message + ''; } else if (typeof err.inspect === 'function') { message = err.inspect() + ''; } else { message = ''; } var stack = err.stack || message; var index = message ? stack.indexOf(message) : -1; var actual = err.actual; var expected = err.expected; var escape = true; if (index === -1) { msg = message; } else { index += message.length; msg = stack.slice(0, index); // remove msg from stack stack = stack.slice(index + 1); } // uncaught if (err.uncaught) { msg = 'Uncaught ' + msg; } // explicitly show diff if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { escape = false; if (!(utils.isString(actual) && utils.isString(expected))) { err.actual = actual = utils.stringify(actual); err.expected = expected = utils.stringify(expected); } fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); var match = message.match(/^([^:]+): expected/); msg = '\n ' + color('error message', match ? match[1] : msg); if (exports.inlineDiffs) { msg += inlineDiff(err, escape); } else { msg += unifiedDiff(err, escape); } } // indent stack trace stack = stack.replace(/^/gm, ' '); console.log(fmt, (i + 1), test.fullTitle(), msg, stack); }); }
...
// failures
if (stats.failures) {
fmt = color('fail', ' %d failing');
console.log(fmt, stats.failures);
Base.list(this.failures);
console.log();
}
console.log();
};
/**
...
epilogue = function () { var stats = this.stats; var fmt; console.log(); // passes fmt = color('bright pass', ' ') + color('green', ' %d passing') + color('light', ' (%s)'); console.log(fmt, stats.passes || 0, ms(stats.duration)); // pending if (stats.pending) { fmt = color('pending', ' ') + color('pending', ' %d pending'); console.log(fmt, stats.pending); } // failures if (stats.failures) { fmt = color('fail', ' %d failing'); console.log(fmt, stats.failures); Base.list(this.failures); console.log(); } console.log(); }
...
process.stdout.write('\n ');
}
process.stdout.write(color('fail', Base.symbols.bang));
});
runner.on('end', function () {
console.log();
self.epilogue();
});
}
/**
* Inherit from `Base.prototype`.
*/
inherits(Dot, Base);
...
function Context() {}
n/a
enableTimeouts = function (enabled) { this.runnable().enableTimeouts(enabled); return this; }
...
* Set test timeout `enabled`.
*
* @api private
* @param {boolean} enabled
* @return {Context} self
*/
Context.prototype.enableTimeouts = function (enabled) {
this.runnable().enableTimeouts(enabled);
return this;
};
/**
* Set test slowness threshold `ms`.
*
* @api private
...
inspect = function () { return JSON.stringify(this, function (key, val) { return key === 'runnable' || key === 'test' ? undefined : val; }, 2); }
...
// msg
var msg;
var err = test.err;
var message;
if (err.message && typeof err.message.toString === 'function') {
message = err.message + '';
} else if (typeof err.inspect === 'function') {
message = err.inspect() + '';
} else {
message = '';
}
var stack = err.stack || message;
var index = message ? stack.indexOf(message) : -1;
var actual = err.actual;
var expected = err.expected;
...
retries = function (n) { if (!arguments.length) { return this.runnable().retries(); } this.runnable().retries(n); return this; }
...
*
* @api private
* @param {number} n
* @return {Context} self
*/
Context.prototype.retries = function (n) {
if (!arguments.length) {
return this.runnable().retries();
}
this.runnable().retries(n);
return this;
};
/**
* Inspect the context void of `._runnable`.
...
runnable = function (runnable) { if (!arguments.length) { return this._runnable; } this.test = this._runnable = runnable; return this; }
...
*
* @api private
* @param {number} ms
* @return {Context} self
*/
Context.prototype.timeout = function (ms) {
if (!arguments.length) {
return this.runnable().timeout();
}
this.runnable().timeout(ms);
return this;
};
/**
* Set test timeout `enabled`.
...
skip = function () { this.runnable().skip(); return this; }
...
- [#2357]: Support `--inspect` on command-line ([@simov])
- [#2194]: Human-friendly error if no files are matched on command-line ([@Munter])
- [#1744]: Human-friendly error if a Suite has no callback (BDD/TDD only) ([@anton])
## :bug: Bug Fix
- [#2488]: Fix case in which *variables beginning with lowercase "D"* may not have been reported properly as global leaks
([@JustATrick]) :laughing:
- [#2465]: Always halt execution in async function when `this.skip()` is called ([@boneskull
])
- [#2445]: Exits with expected code 130 when `SIGINT` encountered; exit code can no longer rollover at 256 ([@Munter])
- [#2315]: Fix uncaught TypeError thrown from callback stack ([@1999])
- Fix broken `only()`/`skip()` in IE7/IE8 ([@boneskull])
- [#2502]: Fix broken stack trace filter on Node.js under Windows ([@boneskull])
- [#2496]: Fix diff output for objects instantiated with `String` constructor ([more](https://youtrack.jetbrains.com/issue/WEB-23383
)) ([@boneskull])
[#2496]: https://github.com/mochajs/mocha/issues/2496
...
slow = function (ms) { this.runnable().slow(ms); return this; }
...
- [#2259]: Restore ES3 compatibility. Specifically, support an environment lacking `Date.prototype.toISOString()`, `JSON`, or has
a non-standard implementation of `JSON`. ([@ndhoule], [@boneskull])
- [#2286]: Fix `after()` failing to execute if test skipped using `this.skip()` in `beforeEach()`; no longer marks the entire suite
as "pending". ([@dasilvacontin], [@boneskull])
- [#2208]: Fix function name display in `markdown` and `html` (browser) reporters. ([@ScottFreeCode])
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any
previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very large values ([@callumacrae], [@boneskull
])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
...
timeout = function (ms) { if (!arguments.length) { return this.runnable().timeout(); } this.runnable().timeout(ms); return this; }
...
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very
large values ([@callumacrae], [@boneskull])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
## :nut_and_bolt: Other
- Upgrade production dependencies to address security advisories (and because now we can): `glob`, `commander`, `escape-string-regexp
`,
...
function Dot(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var n = -1; runner.on('start', function () { process.stdout.write('\n'); }); runner.on('pending', function () { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('pending', Base.symbols.comma)); }); runner.on('pass', function (test) { if (++n % width === 0) { process.stdout.write('\n '); } if (test.speed === 'slow') { process.stdout.write(color('bright yellow', Base.symbols.dot)); } else { process.stdout.write(color(test.speed, Base.symbols.dot)); } }); runner.on('fail', function () { if (++n % width === 0) { process.stdout.write('\n '); } process.stdout.write(color('fail', Base.symbols.bang)); }); runner.on('end', function () { console.log(); self.epilogue(); }); }
n/a
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
function EventEmitter() {}
n/a
function Hook(title, fn) { Runnable.call(this, title, fn); this.type = 'hook'; }
...
self.suite = suite;
if (!suite) {
self.suite = orig;
return fn();
}
self.hook(name, function (err) {
if (err) {
var errSuite = self.suite;
self.suite = orig;
return fn(err, errSuite);
}
next(suites.pop());
...
function Runnable(title, fn) { this.title = title; this.fn = fn; this.body = (fn || '').toString(); this.async = fn && fn.length; this.sync = !this.async; this._timeout = 2000; this._slow = 75; this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; }
n/a
error = function (err) { if (!arguments.length) { err = this._error; this._error = null; return err; } this._error = err; }
...
==================
* Added 0.8.0 support
1.2.1 / 2012-06-25
==================
* Added `this.test.error(err)` support to after each hooks. Closes #287
* Added: export top-level suite on global mocha object (mocha.suite). Closes #448
* Fixed `js` code block format error in markdown reporter
* Fixed deprecation warning when using `path.existsSync`
* Fixed --globals with wildcard
* Fixed chars in nyan when his head moves back
* Remove `--growl` from test/mocha.opts. Closes #289
...
function HTML(runner) { Base.call(this, runner); var self = this; var stats = this.stats; var stat = fragment(statsTemplate); var items = stat.getElementsByTagName('li'); var passes = items[1].getElementsByTagName('em')[0]; var passesLink = items[1].getElementsByTagName('a')[0]; var failures = items[2].getElementsByTagName('em')[0]; var failuresLink = items[2].getElementsByTagName('a')[0]; var duration = items[3].getElementsByTagName('em')[0]; var canvas = stat.getElementsByTagName('canvas')[0]; var report = fragment('<ul id="mocha-report"></ul>'); var stack = [report]; var progress; var ctx; var root = document.getElementById('mocha'); if (canvas.getContext) { var ratio = window.devicePixelRatio || 1; canvas.style.width = canvas.width; canvas.style.height = canvas.height; canvas.width *= ratio; canvas.height *= ratio; ctx = canvas.getContext('2d'); ctx.scale(ratio, ratio); progress = new Progress(); } if (!root) { return error('#mocha div missing, add it to your document'); } // pass toggle on(passesLink, 'click', function (evt) { evt.preventDefault(); unhide(); var name = (/pass/).test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test pass'); } }); // failure toggle on(failuresLink, 'click', function (evt) { evt.preventDefault(); unhide(); var name = (/fail/).test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test fail'); } }); root.appendChild(stat); root.appendChild(report); if (progress) { progress.size(40); } runner.on('suite', function (suite) { if (suite.root) { return; } // suite var url = self.suiteURL(suite); var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title)); // container stack[0].appendChild(el); stack.unshift(document.createElement('ul')); el.appendChild(stack[0]); }); runner.on('suite end', function (suite) { if (suite.root) { updateStats(); return; } stack.shift(); }); runner.on('pass', function (test) { var url = self.testURL(test); var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> ' + '<a href="%s" class="replay">' + playIcon + '</a></h2></li>'; var el = fragment(markup, test.speed, test.title, test.duration, url); self.addCodeToggle(el, test.body); appendToStack(el); updateStats(); }); runner.on('fail', function (test) { var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">' + playIcon + '</a></h2></li>', test.title, self.testURL(test)); var stackString; // Note: Includes leading newline var message = test.err.toString(); // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we // check for the result of the stringifying. if (message === '[object Error]') { message = test.err.message; } if (test.err.stack) { var indexOfMessage = test.err.stack.indexOf(test.err.message); if (indexOfMessage === -1) { stackString = test.err.stack; } else { stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; } stackString = stackString || ''; if (test.err.htmlMessage && stackString) { el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>', test.err.htmlMessage, stackString)); } else if (test.err.htmlMessage) { el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage)); } else { el.app ...
n/a
addCodeToggle = function (el, contents) { var h2 = el.getElementsByTagName('h2')[0]; on(h2, 'click', function () { pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; }); var pre = fragment('<pre><code>%e</code></pre>', utils.clean(contents)); el.appendChild(pre); pre.style.display = 'none'; }
...
});
runner.on('pass', function (test) {
var url = self.testURL(test);
var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems
</span> ' +
'<a href="%s" class="replay">‣</a></h2></li>'
;;
var el = fragment(markup, test.speed, test.title, test.duration, url);
self.addCodeToggle(el, test.body);
appendToStack(el);
updateStats();
});
runner.on('fail', function (test) {
var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay
">‣</a></h2></li>',
test.title, self.testURL(test));
...
suiteURL = function (suite) { return makeUrl(suite.fullTitle()); }
...
runner.on('suite', function (suite) {
if (suite.root) {
return;
}
// suite
var url = self.suiteURL(suite);
var el = fragment('<li class="suite"><h1><a href="%s">%s</a>
x3c;/h1></li>', url, escape(suite.title));
// container
stack[0].appendChild(el);
stack.unshift(document.createElement('ul'));
el.appendChild(stack[0]);
});
...
testURL = function (test) { return makeUrl(test.fullTitle()); }
...
updateStats();
return;
}
stack.shift();
});
runner.on('pass', function (test) {
var url = self.testURL(test);
var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems
</span> ' +
'<a href="%s" class="replay">‣</a></h2></li>'
;;
var el = fragment(markup, test.speed, test.title, test.duration, url);
self.addCodeToggle(el, test.body);
appendToStack(el);
updateStats();
});
...
bdd = function (suite) {
var suites = [suite];
suite.on('pre-require', function (context, file, mocha) {
var common = require('./common')(suites, context, mocha);
context.before = common.before;
context.after = common.after;
context.beforeEach = common.beforeEach;
context.afterEach = common.afterEach;
context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.describe = context.context = function (title, fn) {
return common.suite.create({
title: title,
file: file,
fn: fn
});
};
/**
* Pending describe.
*/
context.xdescribe = context.xcontext = context.describe.skip = function (title, fn) {
return common.suite.skip({
title: title,
file: file,
fn: fn
});
};
/**
* Exclusive suite.
*/
context.describe.only = function (title, fn) {
return common.suite.only({
title: title,
file: file,
fn: fn
});
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = context.specify = function (title, fn) {
var suite = suites[0];
if (suite.isPending()) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.it.only = function (title, fn) {
return common.test.only(mocha, context.it(title, fn));
};
/**
* Pending test case.
*/
context.xit = context.xspecify = context.it.skip = function (title) {
context.it(title);
};
/**
* Number of attempts to retry.
*/
context.it.retries = function (n) {
context.retries(n);
};
});
}
n/a
exports = function (suite) { var suites = [suite]; suite.on('require', visit); function visit (obj, file) { var suite; for (var key in obj) { if (typeof obj[key] === 'function') { var fn = obj[key]; switch (key) { case 'before': suites[0].beforeAll(fn); break; case 'after': suites[0].afterAll(fn); break; case 'beforeEach': suites[0].beforeEach(fn); break; case 'afterEach': suites[0].afterEach(fn); break; default: var test = new Test(key, fn); test.file = file; suites[0].addTest(test); } } else { suite = Suite.create(suites[0], key); suites.unshift(suite); visit(obj[key], file); suites.shift(); } } } }
n/a
qunit = function (suite) {
var suites = [suite];
suite.on('pre-require', function (context, file, mocha) {
var common = require('./common')(suites, context, mocha);
context.before = common.before;
context.after = common.after;
context.beforeEach = common.beforeEach;
context.afterEach = common.afterEach;
context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title`.
*/
context.suite = function (title) {
if (suites.length > 1) {
suites.shift();
}
return common.suite.create({
title: title,
file: file,
fn: false
});
};
/**
* Exclusive Suite.
*/
context.suite.only = function (title) {
if (suites.length > 1) {
suites.shift();
}
return common.suite.only({
title: title,
file: file,
fn: false
});
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.test = function (title, fn) {
var test = new Test(title, fn);
test.file = file;
suites[0].addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.test.only = function (title, fn) {
return common.test.only(mocha, context.test(title, fn));
};
context.test.skip = common.test.skip;
context.test.retries = common.test.retries;
});
}
n/a
tdd = function (suite) {
var suites = [suite];
suite.on('pre-require', function (context, file, mocha) {
var common = require('./common')(suites, context, mocha);
context.setup = common.beforeEach;
context.teardown = common.afterEach;
context.suiteSetup = common.before;
context.suiteTeardown = common.after;
context.run = mocha.options.delay && common.runWithSuite(suite);
/**
* Describe a "suite" with the given `title` and callback `fn` containing
* nested suites and/or tests.
*/
context.suite = function (title, fn) {
return common.suite.create({
title: title,
file: file,
fn: fn
});
};
/**
* Pending suite.
*/
context.suite.skip = function (title, fn) {
return common.suite.skip({
title: title,
file: file,
fn: fn
});
};
/**
* Exclusive test-case.
*/
context.suite.only = function (title, fn) {
return common.suite.only({
title: title,
file: file,
fn: fn
});
};
/**
* Describe a specification or test-case with the given `title` and
* callback `fn` acting as a thunk.
*/
context.test = function (title, fn) {
var suite = suites[0];
if (suite.isPending()) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.test.only = function (title, fn) {
return common.test.only(mocha, context.test(title, fn));
};
context.test.skip = common.test.skip;
context.test.retries = common.test.retries;
});
}
n/a
function Landing(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var total = runner.total; var stream = process.stdout; var plane = color('plane', '✈'); var crashed = -1; var n = 0; function runway () { var buf = Array(width).join('-'); return ' ' + color('runway', buf); } runner.on('start', function () { stream.write('\n\n\n '); cursor.hide(); }); runner.on('test end', function (test) { // check if the plane crashed var col = crashed === -1 ? width * ++n / total | 0 : crashed; // show the crash if (test.state === 'failed') { plane = color('plane crash', '✈'); crashed = col; } // render landing strip stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); stream.write(runway()); stream.write('\n '); stream.write(color('runway', Array(col).join('⋅'))); stream.write(plane); stream.write(color('runway', Array(width - col).join('⋅') + '\n')); stream.write(runway()); stream.write('\u001b[0m'); }); runner.on('end', function () { cursor.show(); console.log(); self.epilogue(); }); }
n/a
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
function List(runner) { Base.call(this, runner); var self = this; var n = 0; runner.on('start', function () { console.log(); }); runner.on('test', function (test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); runner.on('pending', function (test) { var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); runner.on('pass', function (test) { var fmt = color('checkmark', ' ' + Base.symbols.ok) + color('pass', ' %s: ') + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); runner.on('fail', function (test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); runner.on('end', self.epilogue.bind(self)); }
...
// failures
if (stats.failures) {
fmt = color('fail', ' %d failing');
console.log(fmt, stats.failures);
Base.list(this.failures);
console.log();
}
console.log();
};
/**
...
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
function NyanCat(runner) { Base.call(this, runner); var self = this; var width = Base.window.width * 0.75 | 0; var nyanCatWidth = this.nyanCatWidth = 11; this.colorIndex = 0; this.numberOfLines = 4; this.rainbowColors = self.generateColors(); this.scoreboardWidth = 5; this.tick = 0; this.trajectories = [[], [], [], []]; this.trajectoryWidthMax = (width - nyanCatWidth); runner.on('start', function () { Base.cursor.hide(); self.draw(); }); runner.on('pending', function () { self.draw(); }); runner.on('pass', function () { self.draw(); }); runner.on('fail', function () { self.draw(); }); runner.on('end', function () { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); } self.epilogue(); }); }
n/a
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
appendRainbow = function () { var segment = this.tick ? '_' : '-'; var rainbowified = this.rainbowify(segment); for (var index = 0; index < this.numberOfLines; index++) { var trajectory = this.trajectories[index]; if (trajectory.length >= this.trajectoryWidthMax) { trajectory.shift(); } trajectory.push(rainbowified); } }
...
/**
* Draw the nyan cat
*
* @api private
*/
NyanCat.prototype.draw = function () {
this.appendRainbow();
this.drawScoreboard();
this.drawRainbow();
this.drawNyanCat();
this.tick = !this.tick;
};
/**
...
cursorDown = function (n) { write('\u001b[' + n + 'B'); }
n/a
cursorUp = function (n) { write('\u001b[' + n + 'A'); }
...
}
draw('green', stats.passes);
draw('fail', stats.failures);
draw('pending', stats.pending);
write('\n');
this.cursorUp(this.numberOfLines);
};
/**
* Append the rainbow.
*
* @api private
*/
...
draw = function () { this.appendRainbow(); this.drawScoreboard(); this.drawRainbow(); this.drawNyanCat(); this.tick = !this.tick; }
...
}
}
function updateStats () {
// TODO: add to stats
var percent = stats.tests / runner.total * 100 | 0;
if (progress) {
progress.update(percent).draw(ctx);
}
// update stats
var ms = new Date() - stats.start;
text(passes, stats.passes);
text(failures, stats.failures);
text(duration, (ms / 1000).toFixed(2));
...
drawNyanCat = function () { var self = this; var startWidth = this.scoreboardWidth + this.trajectories[0].length; var dist = '\u001b[' + startWidth + 'C'; var padding = ''; write(dist); write('_,------,'); write('\n'); write(dist); padding = self.tick ? ' ' : ' '; write('_|' + padding + '/\\_/\\ '); write('\n'); write(dist); padding = self.tick ? '_' : '__'; var tail = self.tick ? '~' : '^'; write(tail + '|' + padding + this.face() + ' '); write('\n'); write(dist); padding = self.tick ? ' ' : ' '; write(padding + '"" "" '); write('\n'); this.cursorUp(this.numberOfLines); }
...
* @api private
*/
NyanCat.prototype.draw = function () {
this.appendRainbow();
this.drawScoreboard();
this.drawRainbow();
this.drawNyanCat();
this.tick = !this.tick;
};
/**
* Draw the "scoreboard" showing the number
* of passes, failures and pending tests.
*
...
drawRainbow = function () { var self = this; this.trajectories.forEach(function (line) { write('\u001b[' + self.scoreboardWidth + 'C'); write(line.join('')); write('\n'); }); this.cursorUp(this.numberOfLines); }
...
*
* @api private
*/
NyanCat.prototype.draw = function () {
this.appendRainbow();
this.drawScoreboard();
this.drawRainbow();
this.drawNyanCat();
this.tick = !this.tick;
};
/**
* Draw the "scoreboard" showing the number
* of passes, failures and pending tests.
...
drawScoreboard = function () { var stats = this.stats; function draw (type, n) { write(' '); write(Base.color(type, n)); write('\n'); } draw('green', stats.passes); draw('fail', stats.failures); draw('pending', stats.pending); write('\n'); this.cursorUp(this.numberOfLines); }
...
* Draw the nyan cat
*
* @api private
*/
NyanCat.prototype.draw = function () {
this.appendRainbow();
this.drawScoreboard();
this.drawRainbow();
this.drawNyanCat();
this.tick = !this.tick;
};
/**
* Draw the "scoreboard" showing the number
...
face = function () { var stats = this.stats; if (stats.failures) { return '( x .x)'; } else if (stats.pending) { return '( o .o)'; } else if (stats.passes) { return '( ^ .^)'; } return '( - .-)'; }
...
padding = self.tick ? ' ' : ' ';
write('_|' + padding + '/\\_/\\ ');
write('\n');
write(dist);
padding = self.tick ? '_' : '__';
var tail = self.tick ? '~' : '^';
write(tail + '|' + padding + this.face() + ' ');
write('\n');
write(dist);
padding = self.tick ? ' ' : ' ';
write(padding + '"" "" ');
write('\n');
...
generateColors = function () { var colors = []; for (var i = 0; i < (6 * 7); i++) { var pi3 = Math.floor(Math.PI / 3); var n = (i * (1.0 / 6)); var r = Math.floor(3 * Math.sin(n) + 3); var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); colors.push(36 * r + 6 * g + b + 16); } return colors; }
...
var self = this;
var width = Base.window.width * 0.75 | 0;
var nyanCatWidth = this.nyanCatWidth = 11;
this.colorIndex = 0;
this.numberOfLines = 4;
this.rainbowColors = self.generateColors();
this.scoreboardWidth = 5;
this.tick = 0;
this.trajectories = [[], [], [], []];
this.trajectoryWidthMax = (width - nyanCatWidth);
runner.on('start', function () {
Base.cursor.hide();
...
rainbowify = function (str) { if (!Base.useColors) { return str; } var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; this.colorIndex += 1; return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; }
...
* Append the rainbow.
*
* @api private
*/
NyanCat.prototype.appendRainbow = function () {
var segment = this.tick ? '_' : '-';
var rainbowified = this.rainbowify(segment);
for (var index = 0; index < this.numberOfLines; index++) {
var trajectory = this.trajectories[index];
if (trajectory.length >= this.trajectoryWidthMax) {
trajectory.shift();
}
trajectory.push(rainbowified);
...
function Progress() { this.percent = 0; this.size(0); this.fontSize(11); this.font('helvetica, arial, sans-serif'); }
n/a
draw = function (ctx) { try { var percent = Math.min(this.percent, 100); var size = this._size; var half = size / 2; var x = half; var y = half; var rad = half - 1; var fontSize = this._fontSize; ctx.font = fontSize + 'px ' + this._font; var angle = Math.PI * 2 * (percent / 100); ctx.clearRect(0, 0, size, size); // outer circle ctx.strokeStyle = '#9f9f9f'; ctx.beginPath(); ctx.arc(x, y, rad, 0, angle, false); ctx.stroke(); // inner circle ctx.strokeStyle = '#eee'; ctx.beginPath(); ctx.arc(x, y, rad - 1, 0, angle, true); ctx.stroke(); // text var text = this._text || (percent | 0) + '%'; var w = ctx.measureText(text).width; ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); } catch (err) { // don't fail if we can't render progress } return this; }
...
}
}
function updateStats () {
// TODO: add to stats
var percent = stats.tests / runner.total * 100 | 0;
if (progress) {
progress.update(percent).draw(ctx);
}
// update stats
var ms = new Date() - stats.start;
text(passes, stats.passes);
text(failures, stats.failures);
text(duration, (ms / 1000).toFixed(2));
...
font = function (family) { this._font = family; return this; }
...
/**
* Initialize a new `Progress` indicator.
*/
function Progress () {
this.percent = 0;
this.size(0);
this.fontSize(11);
this.font('helvetica, arial, sans-serif');
}
/**
* Set progress size to `size`.
*
* @api public
* @param {number} size
...
fontSize = function (size) { this._fontSize = size; return this; }
...
/**
* Initialize a new `Progress` indicator.
*/
function Progress () {
this.percent = 0;
this.size(0);
this.fontSize(11);
this.font('helvetica, arial, sans-serif');
}
/**
* Set progress size to `size`.
*
* @api public
...
size = function (size) { this._size = size; return this; }
...
module.exports = Progress;
/**
* Initialize a new `Progress` indicator.
*/
function Progress () {
this.percent = 0;
this.size(0);
this.fontSize(11);
this.font('helvetica, arial, sans-serif');
}
/**
* Set progress size to `size`.
*
...
text = function (text) { this._text = text; return this; }
n/a
update = function (n) { this.percent = n; return this; }
...
}
}
function updateStats () {
// TODO: add to stats
var percent = stats.tests / runner.total * 100 | 0;
if (progress) {
progress.update(percent).draw(ctx);
}
// update stats
var ms = new Date() - stats.start;
text(passes, stats.passes);
text(failures, stats.failures);
text(duration, (ms / 1000).toFixed(2));
...
function Runnable(title, fn) { this.title = title; this.fn = fn; this.body = (fn || '').toString(); this.async = fn && fn.length; this.sync = !this.async; this._timeout = 2000; this._slow = 75; this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; }
...
*
* @api private
* @param {number} ms
* @return {Context} self
*/
Context.prototype.timeout = function (ms) {
if (!arguments.length) {
return this.runnable().timeout();
}
this.runnable().timeout(ms);
return this;
};
/**
* Set test timeout `enabled`.
...
clearTimeout = function () { clearTimeout(this.timer); }
...
Runnable.prototype.resetTimeout = function () {
var self = this;
var ms = this.timeout() || 1e9;
if (!this._enableTimeouts) {
return;
}
this.clearTimeout();
this.timer = setTimeout(function () {
if (!self._enableTimeouts) {
return;
}
self.callback(new Error('Timeout of ' + ms +
'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves
.'));
self.timedOut = true;
...
function Runnable(title, fn) { this.title = title; this.fn = fn; this.body = (fn || '').toString(); this.async = fn && fn.length; this.sync = !this.async; this._timeout = 2000; this._slow = 75; this._enableTimeouts = true; this.timedOut = false; this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; }
n/a
currentRetry = function (n) { if (!arguments.length) { return this._currentRetry; } this._currentRetry = n; }
...
* @return {Object}
*/
function clean (test) {
return {
title: test.title,
fullTitle: test.fullTitle(),
duration: test.duration,
currentRetry: test.currentRetry()
};
}
}).call(this,require('_process'))
},{"./base":17,"_process":67,"json3":54}],23:[function(require,module,exports){
(function (process){
'use strict';
...
enableTimeouts = function (enabled) { if (!arguments.length) { return this._enableTimeouts; } debug('enableTimeouts %s', enabled); this._enableTimeouts = enabled; return this; }
...
* Set test timeout `enabled`.
*
* @api private
* @param {boolean} enabled
* @return {Context} self
*/
Context.prototype.enableTimeouts = function (enabled) {
this.runnable().enableTimeouts(enabled);
return this;
};
/**
* Set test slowness threshold `ms`.
*
* @api private
...
fullTitle = function () { return this.parent.fullTitle() + ' ' + this.title; }
...
suite.parent._onlySuites = suite.parent._onlySuites.concat(suite);
mocha.options.hasOnly = true;
}
if (typeof opts.fn === 'function') {
opts.fn.call(suite);
suites.shift();
} else if (typeof opts.fn === 'undefined' && !suite.pending) {
throw new Error('Suite "' + suite.fullTitle() + '" was
defined but no callback was supplied. Supply a callback or explicitly skip the suite.');
}
return suite;
}
},
test: {
...
globals = function (globals) { if (!arguments.length) { return this._allowedGlobals; } this._allowedGlobals = globals; }
...
/**
* Run mocha, returning the Runner.
*/
mocha.run = function (fn) {
var options = mocha.options;
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
if (query.grep) {
mocha.grep(query.grep);
}
if (query.fgrep) {
mocha.fgrep(query.fgrep);
...
inspect = function () { return JSON.stringify(this, function (key, val) { if (key[0] === '_') { return; } if (key === 'parent') { return '#<Suite>'; } if (key === 'ctx') { return '#<Context>'; } return val; }, 2); }
...
// msg
var msg;
var err = test.err;
var message;
if (err.message && typeof err.message.toString === 'function') {
message = err.message + '';
} else if (typeof err.inspect === 'function') {
message = err.inspect() + '';
} else {
message = '';
}
var stack = err.stack || message;
var index = message ? stack.indexOf(message) : -1;
var actual = err.actual;
var expected = err.expected;
...
isPending = function () { return this.pending || (this.parent && this.parent.isPending()); }
...
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = context.specify = function (title, fn) {
var suite = suites[0];
if (suite.isPending()) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
...
resetTimeout = function () { var self = this; var ms = this.timeout() || 1e9; if (!this._enableTimeouts) { return; } this.clearTimeout(); this.timer = setTimeout(function () { if (!self._enableTimeouts) { return; } self.callback(new Error('Timeout of ' + ms + 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.')); self.timedOut = true; }, ms); }
...
}
if (typeof ms === 'string') {
ms = milliseconds(ms);
}
debug('timeout %d', ms);
this._timeout = ms;
if (this.timer) {
this.resetTimeout();
}
return this;
};
/**
* Set & get slow `ms`.
*
...
retries = function (n) { if (!arguments.length) { return this._retries; } this._retries = n; }
...
*
* @api private
* @param {number} n
* @return {Context} self
*/
Context.prototype.retries = function (n) {
if (!arguments.length) {
return this.runnable().retries();
}
this.runnable().retries(n);
return this;
};
/**
* Inspect the context void of `._runnable`.
...
run = function (fn) { var self = this; var start = new Date(); var ctx = this.ctx; var finished; var emitted; // Sometimes the ctx exists, but it is not runnable if (ctx && ctx.runnable) { ctx.runnable(this); } // called multiple times function multiple (err) { if (emitted) { return; } emitted = true; self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); } // finished function done (err) { var ms = self.timeout(); if (self.timedOut) { return; } if (finished) { return multiple(err || self._trace); } self.clearTimeout(); self.duration = new Date() - start; finished = true; if (!err && self.duration > ms && self._enableTimeouts) { err = new Error('Timeout of ' + ms + 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.'); } fn(err); } // for .resetTimeout() this.callback = done; // explicit async with `done` argument if (this.async) { this.resetTimeout(); // allows skip() to be used in an explicit async context this.skip = function asyncSkip () { done(new Pending('async skip call')); // halt execution. the Runnable will be marked pending // by the previous call, and the uncaught handler will ignore // the failure. throw new Pending('async skip; aborting execution'); }; if (this.allowUncaught) { return callFnAsync(this.fn); } try { callFnAsync(this.fn); } catch (err) { emitted = true; done(utils.getError(err)); } return; } if (this.allowUncaught) { callFn(this.fn); done(); return; } // sync or promise-returning try { if (this.isPending()) { done(); } else { callFn(this.fn); } } catch (err) { emitted = true; done(utils.getError(err)); } function callFn (fn) { var result = fn.call(ctx); if (result && typeof result.then === 'function') { self.resetTimeout(); result .then(function () { done(); // Return null so libraries like bluebird do not warn about // subsequently constructed Promises. return null; }, function (reason) { done(reason || new Error('Promise rejected with no or falsy reason')); }); } else { if (self.asyncOnly) { return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); } done(); } } function callFnAsync (fn) { var result = fn.call(ctx, function (err) { if (err instanceof Error || toString.call(err) === '[object Error]') { return done(err); } if (err) { if (Object.prototype.toString.call(err) === '[object Object]') { return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err))); } return done(new Error('done() invoked with non-Error: ' + err)); } if (result && utils.isPromise(result)) { return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.')); } done(); }); } }
...
* small fix: commander option for --expose-gc
* Ignore asynchronous errors after global failure
* Improve error output when a test fails with a non-error
* updated travis badge, uses svg instead of img
* Allow skip from test context for #332
* [JSHINT] Unnecessary semicolon fixed in bin/_mocha
* Added a reminder about the done() callback to test timeout error messages
* fixes #1496, in Mocha.run(fn), check if fn exists before executing it, added tests
too
* Add Harmony Proxy flag for iojs
* test(utils|ms|*): test existing units
* add support for some iojs flags
* fix(utils.stringify): issue #1229, diff viewer
* Remove slack link
* Prevent multiple 'grep=' querystring params in html reporter
* Use grep as regexp (close #1381)
...
skip = function () { throw new Pending('sync skip'); }
...
- [#2357]: Support `--inspect` on command-line ([@simov])
- [#2194]: Human-friendly error if no files are matched on command-line ([@Munter])
- [#1744]: Human-friendly error if a Suite has no callback (BDD/TDD only) ([@anton])
## :bug: Bug Fix
- [#2488]: Fix case in which *variables beginning with lowercase "D"* may not have been reported properly as global leaks
([@JustATrick]) :laughing:
- [#2465]: Always halt execution in async function when `this.skip()` is called ([@boneskull
])
- [#2445]: Exits with expected code 130 when `SIGINT` encountered; exit code can no longer rollover at 256 ([@Munter])
- [#2315]: Fix uncaught TypeError thrown from callback stack ([@1999])
- Fix broken `only()`/`skip()` in IE7/IE8 ([@boneskull])
- [#2502]: Fix broken stack trace filter on Node.js under Windows ([@boneskull])
- [#2496]: Fix diff output for objects instantiated with `String` constructor ([more](https://youtrack.jetbrains.com/issue/WEB-23383
)) ([@boneskull])
[#2496]: https://github.com/mochajs/mocha/issues/2496
...
slow = function (ms) { if (typeof ms === 'undefined') { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._slow = ms; return this; }
...
- [#2259]: Restore ES3 compatibility. Specifically, support an environment lacking `Date.prototype.toISOString()`, `JSON`, or has
a non-standard implementation of `JSON`. ([@ndhoule], [@boneskull])
- [#2286]: Fix `after()` failing to execute if test skipped using `this.skip()` in `beforeEach()`; no longer marks the entire suite
as "pending". ([@dasilvacontin], [@boneskull])
- [#2208]: Fix function name display in `markdown` and `html` (browser) reporters. ([@ScottFreeCode])
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any
previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very large values ([@callumacrae], [@boneskull
])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
...
timeout = function (ms) { if (!arguments.length) { return this._timeout; } // see #1652 for reasoning if (ms === 0 || ms > Math.pow(2, 31)) { this._enableTimeouts = false; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._timeout = ms; if (this.timer) { this.resetTimeout(); } return this; }
...
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very
large values ([@callumacrae], [@boneskull])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
## :nut_and_bolt: Other
- Upgrade production dependencies to address security advisories (and because now we can): `glob`, `commander`, `escape-string-regexp
`,
...
function Runner(suite, delay) { var self = this; this._globals = []; this._abort = false; this._delay = delay; this.suite = suite; this.started = false; this.total = suite.total(); this.failures = 0; this.on('test end', function (test) { self.checkGlobals(test); }); this.on('hook end', function (hook) { self.checkGlobals(hook); }); this._defaultGrep = /.*/; this.grep(this._defaultGrep); this.globals(this.globalProps().concat(extraGlobals())); }
n/a
immediately = function () {
/*
* this function will do nothing
*/
return;
}
...
}
self.emit('hook end', hook);
delete hook.ctx.currentTest;
next(++i);
});
}
Runner.immediately(function () {
next(0);
});
};
/**
* Run hook `name` for the given array of `suites`
* in order, and callback `fn(err, errSuite)`.
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
abort = function () { debug('aborting'); this._abort = true; return this; }
...
process.exit(code);
}
});
});
// terminate children.
process.on('SIGINT', function () {
proc.kill('SIGINT'); // calls runner.abort()
proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die.
});
...
checkGlobals = function (test) { if (this.ignoreLeaks) { return; } var ok = this._globals; var globals = this.globalProps(); var leaks; if (test) { ok = ok.concat(test._allowedGlobals || []); } if (this.prevGlobalsLength === globals.length) { return; } this.prevGlobalsLength = globals.length; leaks = filterLeaks(ok, globals); this._globals = this._globals.concat(leaks); if (leaks.length > 1) { this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); } else if (leaks.length) { this.fail(test, new Error('global leak detected: ' + leaks[0])); } }
...
1.5.0 / 2012-09-21
==================
* add `ms()` to `.slow()` and `.timeout()`
* add `Mocha#checkLeaks()` to re-enable global leak checks
* add `this.slow()` option [aheckmann]
* add tab, CR, LF to error diffs for now
* add faster `.checkGlobals()` solution [guille]
* remove `fn.call()` from reduce util
* remove `fn.call()` from filter util
* fix forEach. Closes #582
* fix relaying of signals [TooTallNate]
* fix TAP reporter grep number
1.4.2 / 2012-09-01
...
fail = function (test, err) { if (test.isPending()) { return; } ++this.failures; test.state = 'failed'; if (!(err instanceof Error || err && typeof err.message === 'string')) { err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); } try { err.stack = (this.fullStackTrace || !err.stack) ? err.stack : stackFilter(err.stack); } catch (ignored) { // some environments do not take kindly to monkeying with the stack } this.emit('fail', test, err); }
...
}
this.prevGlobalsLength = globals.length;
leaks = filterLeaks(ok, globals);
this._globals = this._globals.concat(leaks);
if (leaks.length > 1) {
this.fail(test, new Error('global leaks detected: ' + leaks.join(',
x27;) + ''));
} else if (leaks.length) {
this.fail(test, new Error('global leak detected: ' + leaks[0]));
}
};
/**
* Fail the given `test`.
...
failHook = function (hook, err) { if (hook.ctx && hook.ctx.currentTest) { hook.originalTitle = hook.originalTitle || hook.title; hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; } this.fail(hook, err); if (this.suite.bail()) { this.emit('end'); } }
...
hook.ctx.currentTest = self.test;
self.emit('hook', hook);
if (!hook.listeners('error').length) {
hook.on('error', function (err) {
self.failHook(hook, err);
});
}
hook.run(function (err) {
var testError = hook.error();
if (testError) {
self.fail(self.test, testError);
...
globalProps = function () { var props = keys(global); // non-enumerables for (var i = 0; i < globals.length; ++i) { if (~indexOf(props, globals[i])) { continue; } props.push(globals[i]); } return props; }
...
self.checkGlobals(test);
});
this.on('hook end', function (hook) {
self.checkGlobals(hook);
});
this._defaultGrep = /.*/;
this.grep(this._defaultGrep);
this.globals(this.globalProps().concat(extraGlobals()));
}
/**
* Wrapper for setImmediate, process.nextTick, or browser polyfill.
*
* @param {Function} fn
* @api private
...
globals = function (arr) { if (!arguments.length) { return this._globals; } debug('globals %j', arr); this._globals = this._globals.concat(arr); return this; }
...
/**
* Run mocha, returning the Runner.
*/
mocha.run = function (fn) {
var options = mocha.options;
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
if (query.grep) {
mocha.grep(query.grep);
}
if (query.fgrep) {
mocha.fgrep(query.fgrep);
...
grep = function (re, invert) { debug('grep %s', re); this._grep = re; this._invert = invert; this.total = this.grepTotal(this.suite); return this; }
...
mocha.run = function (fn) {
var options = mocha.options;
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
if (query.grep) {
mocha.grep(query.grep);
}
if (query.fgrep) {
mocha.fgrep(query.fgrep);
}
if (query.invert) {
mocha.invert();
}
...
grepTotal = function (suite) { var self = this; var total = 0; suite.eachTest(function (test) { var match = self._grep.test(test.fullTitle()); if (self._invert) { match = !match; } if (match) { total++; } }); return total; }
...
Base.call(this, runner);
var n = 1;
var passes = 0;
var failures = 0;
runner.on('start', function () {
var total = runner.grepTotal(runner.suite);
console.log('%d..%d', 1, total);
});
runner.on('test end', function () {
++n;
});
...
hook = function (name, fn) { var suite = this.suite; var hooks = suite['_' + name]; var self = this; function next (i) { var hook = hooks[i]; if (!hook) { return fn(); } self.currentRunnable = hook; hook.ctx.currentTest = self.test; self.emit('hook', hook); if (!hook.listeners('error').length) { hook.on('error', function (err) { self.failHook(hook, err); }); } hook.run(function (err) { var testError = hook.error(); if (testError) { self.fail(self.test, testError); } if (err) { if (err instanceof Pending) { if (name === 'beforeEach' || name === 'afterEach') { self.test.pending = true; } else { utils.forEach(suite.tests, function (test) { test.pending = true; }); // a pending hook won't be executed twice. hook.pending = true; } } else { self.failHook(hook, err); // stop executing hooks, notify callee of hook err return fn(err); } } self.emit('hook end', hook); delete hook.ctx.currentTest; next(++i); }); } Runner.immediately(function () { next(0); }); }
...
self.suite = suite;
if (!suite) {
self.suite = orig;
return fn();
}
self.hook(name, function (err) {
if (err) {
var errSuite = self.suite;
self.suite = orig;
return fn(err, errSuite);
}
next(suites.pop());
...
hookDown = function (name, fn) { var suites = [this.suite].concat(this.parents()); this.hooks(name, suites, fn); }
...
self.emit('pending', test);
self.emit('test end', test);
return next();
}
// execute test and hook(s)
self.emit('test', self.test = test);
self.hookDown('beforeEach', function (err, errSuite) {
if (test.isPending()) {
self.emit('pending', test);
self.emit('test end', test);
return next();
}
if (err) {
return hookErr(err, errSuite, false);
...
hookUp = function (name, fn) { var suites = [this.suite].concat(this.parents()).reverse(); this.hooks(name, suites, fn); }
...
// for failed 'after each' hook start from errSuite parent,
// otherwise start from errSuite itself
self.suite = after ? errSuite.parent : errSuite;
if (self.suite) {
// call hookUp afterEach
self.hookUp('afterEach', function (err2, errSuite2) {
self.suite = orig;
// some hooks may fail even now
if (err2) {
return hookErr(err2, errSuite2, true);
}
// report error suite
fn(errSuite);
...
hooks = function (name, suites, fn) { var self = this; var orig = this.suite; function next (suite) { self.suite = suite; if (!suite) { self.suite = orig; return fn(); } self.hook(name, function (err) { if (err) { var errSuite = self.suite; self.suite = orig; return fn(err, errSuite); } next(suites.pop()); }); } next(suites.pop()); }
...
*
* @param {String} name
* @param {Function} fn
* @api private
*/
Runner.prototype.hookUp = function (name, fn) {
var suites = [this.suite].concat(this.parents()).reverse();
this.hooks(name, suites, fn);
};
/**
* Run hooks from the bottom up.
*
* @param {String} name
* @param {Function} fn
...
parents = function () { var suite = this.suite; var suites = []; while (suite.parent) { suite = suite.parent; suites.push(suite); } return suites; }
...
* Run hooks from the top level down.
*
* @param {String} name
* @param {Function} fn
* @api private
*/
Runner.prototype.hookUp = function (name, fn) {
var suites = [this.suite].concat(this.parents()).reverse();
this.hooks(name, suites, fn);
};
/**
* Run hooks from the bottom up.
*
* @param {String} name
...
run = function (fn) { var self = this; var rootSuite = this.suite; // If there is an `only` filter if (this.hasOnly) { filterOnly(rootSuite); } fn = fn || function () {}; function uncaught (err) { self.uncaught(err); } function start () { self.started = true; self.emit('start'); self.runSuite(rootSuite, function () { debug('finished running'); self.emit('end'); }); } debug('start'); // references cleanup to avoid memory leaks this.on('suite end', cleanSuiteReferences); // callback this.on('end', function () { debug('end'); process.removeListener('uncaughtException', uncaught); fn(self.failures); }); // uncaught exception process.on('uncaughtException', uncaught); if (this._delay) { // for reporters, I guess. // might be nice to debounce some dots while we wait. this.emit('waiting', rootSuite); rootSuite.once('run', start); } else { start(); } return this; }
...
* small fix: commander option for --expose-gc
* Ignore asynchronous errors after global failure
* Improve error output when a test fails with a non-error
* updated travis badge, uses svg instead of img
* Allow skip from test context for #332
* [JSHINT] Unnecessary semicolon fixed in bin/_mocha
* Added a reminder about the done() callback to test timeout error messages
* fixes #1496, in Mocha.run(fn), check if fn exists before executing it, added tests
too
* Add Harmony Proxy flag for iojs
* test(utils|ms|*): test existing units
* add support for some iojs flags
* fix(utils.stringify): issue #1229, diff viewer
* Remove slack link
* Prevent multiple 'grep=' querystring params in html reporter
* Use grep as regexp (close #1381)
...
runSuite = function (suite, fn) { var i = 0; var self = this; var total = this.grepTotal(suite); var afterAllHookCalled = false; debug('run suite %s', suite.fullTitle()); if (!total || (self.failures && suite._bail)) { return fn(); } this.emit('suite', this.suite = suite); function next (errSuite) { if (errSuite) { // current suite failed on a hook from errSuite if (errSuite === suite) { // if errSuite is current suite // continue to the next sibling suite return done(); } // errSuite is among the parents of current suite // stop execution of errSuite and all sub-suites return done(errSuite); } if (self._abort) { return done(); } var curr = suite.suites[i++]; if (!curr) { return done(); } // Avoid grep neglecting large number of tests causing a // huge recursive loop and thus a maximum call stack error. // See comment in `this.runTests()` for more information. if (self._grep !== self._defaultGrep) { Runner.immediately(function () { self.runSuite(curr, next); }); } else { self.runSuite(curr, next); } } function done (errSuite) { self.suite = suite; self.nextSuite = next; if (afterAllHookCalled) { fn(errSuite); } else { // mark that the afterAll block has been called once // and so can be skipped if there is an error in it. afterAllHookCalled = true; // remove reference to test delete self.test; self.hook('afterAll', function () { self.emit('suite end', suite); fn(errSuite); }); } } this.nextSuite = next; this.hook('beforeAll', function (err) { if (err) { return done(); } self.runTests(suite, next); }); }
...
}
// Avoid grep neglecting large number of tests causing a
// huge recursive loop and thus a maximum call stack error.
// See comment in `this.runTests()` for more information.
if (self._grep !== self._defaultGrep) {
Runner.immediately(function () {
self.runSuite(curr, next);
});
} else {
self.runSuite(curr, next);
}
}
function done (errSuite) {
...
runTest = function (fn) { var self = this; var test = this.test; if (!test) { return; } if (this.asyncOnly) { test.asyncOnly = true; } if (this.allowUncaught) { test.allowUncaught = true; return test.run(fn); } try { test.on('error', function (err) { self.fail(test, err); }); test.run(fn); } catch (err) { fn(err); } }
...
self.emit('test end', test);
return next();
}
if (err) {
return hookErr(err, errSuite, false);
}
self.currentRunnable = self.test;
self.runTest(function (err) {
test = self.test;
if (err) {
var retry = test.currentRetry();
if (err instanceof Pending) {
test.pending = true;
self.emit('pending', test);
} else if (retry < test.retries()) {
...
runTests = function (suite, fn) { var self = this; var tests = suite.tests.slice(); var test; function hookErr (_, errSuite, after) { // before/after Each hook for errSuite failed: var orig = self.suite; // for failed 'after each' hook start from errSuite parent, // otherwise start from errSuite itself self.suite = after ? errSuite.parent : errSuite; if (self.suite) { // call hookUp afterEach self.hookUp('afterEach', function (err2, errSuite2) { self.suite = orig; // some hooks may fail even now if (err2) { return hookErr(err2, errSuite2, true); } // report error suite fn(errSuite); }); } else { // there is no need calling other 'after each' hooks self.suite = orig; fn(errSuite); } } function next (err, errSuite) { // if we bail after first err if (self.failures && suite._bail) { return fn(); } if (self._abort) { return fn(); } if (err) { return hookErr(err, errSuite, true); } // next test test = tests.shift(); // all done if (!test) { return fn(); } // grep var match = self._grep.test(test.fullTitle()); if (self._invert) { match = !match; } if (!match) { // Run immediately only if we have defined a grep. When we // define a grep — It can cause maximum callstack error if // the grep is doing a large recursive loop by neglecting // all tests. The run immediately function also comes with // a performance cost. So we don't want to run immediately // if we run the whole test suite, because running the whole // test suite don't do any immediate recursive loops. Thus, // allowing a JS runtime to breathe. if (self._grep !== self._defaultGrep) { Runner.immediately(next); } else { next(); } return; } if (test.isPending()) { self.emit('pending', test); self.emit('test end', test); return next(); } // execute test and hook(s) self.emit('test', self.test = test); self.hookDown('beforeEach', function (err, errSuite) { if (test.isPending()) { self.emit('pending', test); self.emit('test end', test); return next(); } if (err) { return hookErr(err, errSuite, false); } self.currentRunnable = self.test; self.runTest(function (err) { test = self.test; if (err) { var retry = test.currentRetry(); if (err instanceof Pending) { test.pending = true; self.emit('pending', test); } else if (retry < test.retries()) { var clonedTest = test.clone(); clonedTest.currentRetry(retry + 1); tests.unshift(clonedTest); // Early return + hook trigger so that it doesn't // increment the count wrong return self.hookUp('afterEach', next); } else { self.fail(test, err); } self.emit('test end', test); if (err instanceof Pending) { return next(); } return self.hookUp('afterEach', next); } test.state = 'passed'; self.emit('pass', test); self.emit('test end', test); self.hookUp('afterEach', next); }); }); } this.next = next; this.hookErr = hookErr; next(); }
...
var curr = suite.suites[i++];
if (!curr) {
return done();
}
// Avoid grep neglecting large number of tests causing a
// huge recursive loop and thus a maximum call stack error.
// See comment in `this.runTests()` for more information.
if (self._grep !== self._defaultGrep) {
Runner.immediately(function () {
self.runSuite(curr, next);
});
} else {
self.runSuite(curr, next);
}
...
uncaught = function (err) { if (err) { debug('uncaught exception %s', err === (function () { return this; }.call(err)) ? (err.message || err) : err); } else { debug('uncaught undefined exception'); err = undefinedError(); } err.uncaught = true; var runnable = this.currentRunnable; if (!runnable) { runnable = new Runnable('Uncaught error outside test suite'); runnable.parent = this.suite; if (this.started) { this.fail(runnable, err); } else { // Can't recover from this failure this.emit('start'); this.fail(runnable, err); this.emit('end'); } return; } runnable.clearTimeout(); // Ignore errors if complete or pending if (runnable.state || runnable.isPending()) { return; } this.fail(runnable, err); // recover from test if (runnable.type === 'test') { this.emit('test end', runnable); this.hookUp('afterEach', this.next); return; } // recover from hooks if (runnable.type === 'hook') { var errSuite = this.suite; // if hook failure is in afterEach block if (runnable.fullTitle().indexOf('after each') > -1) { return this.hookErr(err, errSuite, true); } // if hook failure is in beforeEach block if (runnable.fullTitle().indexOf('before each') > -1) { return this.hookErr(err, errSuite, false); } // if hook failure is in after or before blocks return this.nextSuite(errSuite); } // bail this.emit('end'); }
...
if (this.hasOnly) {
filterOnly(rootSuite);
}
fn = fn || function () {};
function uncaught (err) {
self.uncaught(err);
}
function start () {
self.started = true;
self.emit('start');
self.runSuite(rootSuite, function () {
debug('finished running');
...
function Suite(title, parentContext) { if (!utils.isString(title)) { throw new Error('Suite `title` should be a "string" but "' + typeof title + '" was given instead.'); } this.title = title; function Context () {} Context.prototype = parentContext; this.ctx = new Context(); this.suites = []; this.tests = []; this.pending = false; this._beforeEach = []; this._beforeAll = []; this._afterEach = []; this._afterAll = []; this.root = !title; this._timeout = 2000; this._enableTimeouts = true; this._slow = 75; this._bail = false; this._retries = -1; this._onlyTests = []; this._onlySuites = []; this.delayed = false; }
n/a
create = function (parent, title) { var suite = new Suite(title, parent.ctx); suite.parent = parent; title = suite.fullTitle(); parent.addSuite(suite); return suite; }
...
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.describe = context.context = function (title, fn) {
return common.suite.create({
title: title,
file: file,
fn: fn
});
};
/**
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
addSuite = function (suite) { suite.parent = this; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); this.suites.push(suite); this.emit('suite', suite); return this; }
...
* @param {string} title
* @return {Suite}
*/
exports.create = function (parent, title) {
var suite = new Suite(title, parent.ctx);
suite.parent = parent;
title = suite.fullTitle();
parent.addSuite(suite);
return suite;
};
/**
* Initialize a new `Suite` with the given `title` and `ctx`.
*
* @api private
...
addTest = function (test) { test.parent = this; test.timeout(this.timeout()); test.retries(this.retries()); test.enableTimeouts(this.enableTimeouts()); test.slow(this.slow()); test.ctx = this.ctx; this.tests.push(test); this.emit('test', test); return this; }
...
context.it = context.specify = function (title, fn) {
var suite = suites[0];
if (suite.isPending()) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
...
afterAll = function (title, fn) { if (this.isPending()) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"after all" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._afterAll.push(hook); this.emit('afterAll', hook); return this; }
...
/**
* Execute after running tests.
*
* @param {string} name
* @param {Function} fn
*/
after: function (name, fn) {
suites[0].afterAll(name, fn);
},
/**
* Execute before each test case.
*
* @param {string} name
* @param {Function} fn
...
afterEach = function (title, fn) { if (this.isPending()) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"after each" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._afterEach.push(hook); this.emit('afterEach', hook); return this; }
...
/**
* Execute after each test case.
*
* @param {string} name
* @param {Function} fn
*/
afterEach: function (name, fn) {
suites[0].afterEach(name, fn);
},
suite: {
/**
* Create an exclusive Suite; convenience function
* See docstring for create() below.
*
...
bail = function (bail) { if (!arguments.length) { return this._bail; } debug('bail %s', bail); this._bail = bail; return this; }
...
* add `setImmediate` support for 0.10.x
* fix mocha -w spinner on windows
1.8.1 / 2013-01-09
==================
* fix .bail() arity check causing it to default to true
1.8.0 / 2013-01-08
==================
* add Mocha() options bail support
* add `Mocha#bail()` method
* add instanceof check back for inheriting from Error
...
beforeAll = function (title, fn) { if (this.isPending()) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"before all" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._beforeAll.push(hook); this.emit('beforeAll', hook); return this; }
...
/**
* Execute before running tests.
*
* @param {string} name
* @param {Function} fn
*/
before: function (name, fn) {
suites[0].beforeAll(name, fn);
},
/**
* Execute after running tests.
*
* @param {string} name
* @param {Function} fn
...
beforeEach = function (title, fn) { if (this.isPending()) { return this; } if (typeof title === 'function') { fn = title; title = fn.name; } title = '"before each" hook' + (title ? ': ' + title : ''); var hook = new Hook(title, fn); hook.parent = this; hook.timeout(this.timeout()); hook.retries(this.retries()); hook.enableTimeouts(this.enableTimeouts()); hook.slow(this.slow()); hook.ctx = this.ctx; this._beforeEach.push(hook); this.emit('beforeEach', hook); return this; }
...
/**
* Execute before each test case.
*
* @param {string} name
* @param {Function} fn
*/
beforeEach: function (name, fn) {
suites[0].beforeEach(name, fn);
},
/**
* Execute after each test case.
*
* @param {string} name
* @param {Function} fn
...
clone = function () { var suite = new Suite(this.title); debug('clone'); suite.ctx = this.ctx; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); return suite; }
...
test = self.test;
if (err) {
var retry = test.currentRetry();
if (err instanceof Pending) {
test.pending = true;
self.emit('pending', test);
} else if (retry < test.retries()) {
var clonedTest = test.clone();
clonedTest.currentRetry(retry + 1);
tests.unshift(clonedTest);
// Early return + hook trigger so that it doesn't
// increment the count wrong
return self.hookUp('afterEach', next);
} else {
...
eachTest = function (fn) { utils.forEach(this.tests, fn); utils.forEach(this.suites, function (suite) { suite.eachTest(fn); }); return this; }
...
* @param {Suite} suite
* @return {number}
*/
Runner.prototype.grepTotal = function (suite) {
var self = this;
var total = 0;
suite.eachTest(function (test) {
var match = self._grep.test(test.fullTitle());
if (self._invert) {
match = !match;
}
if (match) {
total++;
}
...
enableTimeouts = function (enabled) { if (!arguments.length) { return this._enableTimeouts; } debug('enableTimeouts %s', enabled); this._enableTimeouts = enabled; return this; }
...
* Set test timeout `enabled`.
*
* @api private
* @param {boolean} enabled
* @return {Context} self
*/
Context.prototype.enableTimeouts = function (enabled) {
this.runnable().enableTimeouts(enabled);
return this;
};
/**
* Set test slowness threshold `ms`.
*
* @api private
...
fullTitle = function () { if (this.parent) { var full = this.parent.fullTitle(); if (full) { return full + ' ' + this.title; } } return this.title; }
...
suite.parent._onlySuites = suite.parent._onlySuites.concat(suite);
mocha.options.hasOnly = true;
}
if (typeof opts.fn === 'function') {
opts.fn.call(suite);
suites.shift();
} else if (typeof opts.fn === 'undefined' && !suite.pending) {
throw new Error('Suite "' + suite.fullTitle() + '" was
defined but no callback was supplied. Supply a callback or explicitly skip the suite.');
}
return suite;
}
},
test: {
...
isPending = function () { return this.pending || (this.parent && this.parent.isPending()); }
...
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = context.specify = function (title, fn) {
var suite = suites[0];
if (suite.isPending()) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
...
retries = function (n) { if (!arguments.length) { return this._retries; } debug('retries %d', n); this._retries = parseInt(n, 10) || 0; return this; }
...
*
* @api private
* @param {number} n
* @return {Context} self
*/
Context.prototype.retries = function (n) {
if (!arguments.length) {
return this.runnable().retries();
}
this.runnable().retries(n);
return this;
};
/**
* Inspect the context void of `._runnable`.
...
function run() { if (this.root) { this.emit('run'); } }
...
* small fix: commander option for --expose-gc
* Ignore asynchronous errors after global failure
* Improve error output when a test fails with a non-error
* updated travis badge, uses svg instead of img
* Allow skip from test context for #332
* [JSHINT] Unnecessary semicolon fixed in bin/_mocha
* Added a reminder about the done() callback to test timeout error messages
* fixes #1496, in Mocha.run(fn), check if fn exists before executing it, added tests
too
* Add Harmony Proxy flag for iojs
* test(utils|ms|*): test existing units
* add support for some iojs flags
* fix(utils.stringify): issue #1229, diff viewer
* Remove slack link
* Prevent multiple 'grep=' querystring params in html reporter
* Use grep as regexp (close #1381)
...
slow = function (ms) { if (!arguments.length) { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('slow %d', ms); this._slow = ms; return this; }
...
- [#2259]: Restore ES3 compatibility. Specifically, support an environment lacking `Date.prototype.toISOString()`, `JSON`, or has
a non-standard implementation of `JSON`. ([@ndhoule], [@boneskull])
- [#2286]: Fix `after()` failing to execute if test skipped using `this.skip()` in `beforeEach()`; no longer marks the entire suite
as "pending". ([@dasilvacontin], [@boneskull])
- [#2208]: Fix function name display in `markdown` and `html` (browser) reporters. ([@ScottFreeCode])
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any
previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very large values ([@callumacrae], [@boneskull
])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
...
timeout = function (ms) { if (!arguments.length) { return this._timeout; } if (ms.toString() === '0') { this._enableTimeouts = false; } if (typeof ms === 'string') { ms = milliseconds(ms); } debug('timeout %d', ms); this._timeout = parseInt(ms, 10); return this; }
...
- [#2299]: Fix progress bar in `html` (browser) reporter. ([@AviVahl])
- [#2307]: Fix `doc` reporter crashing when test fails. ([@jleyba])
- [#2323]: Ensure browser entry point (`browser-entry.js`) is published to npm (for use with bundlers). ([@boneskull])
- [#2310]: Ensure custom reporter with an absolute path works in Windows. ([@silentcloud])
- [#2311]: Fix problem wherein calling `this.slow()` without a value would blast any previously set value. ([@boneskull])
- [#1813]: Ensure Mocha's own test suite will run in Windows. ([@tswaters], [@TimothyGu], [@boneskull])
- [#2317]: Ensure all interfaces are displayed in `--help` on CLI. ([@ScottFreeCode])
- [#1644]: Don't exhibit undefined behavior when calling `this.timeout()` with very
large values ([@callumacrae], [@boneskull])
- [#2361]: Don't truncate name of thrown anonymous exception. ([@boneskull])
- [#2367]: Fix invalid CSS. ([@bensontrent])
- [#2401]: Remove carriage return before each test line in spec reporter. ([@Munter])
## :nut_and_bolt: Other
- Upgrade production dependencies to address security advisories (and because now we can): `glob`, `commander`, `escape-string-regexp
`,
...
total = function () { return utils.reduce(this.suites, function (sum, suite) { return sum + suite.total(); }, 0) + this.tests.length; }
...
function Runner (suite, delay) {
var self = this;
this._globals = [];
this._abort = false;
this._delay = delay;
this.suite = suite;
this.started = false;
this.total = suite.total();
this.failures = 0;
this.on('test end', function (test) {
self.checkGlobals(test);
});
this.on('hook end', function (hook) {
self.checkGlobals(hook);
});
...
function getWindowSize() { if ('innerHeight' in global) { return [global.innerHeight, global.innerWidth]; } // In a Web Worker, the DOM Window is not available. return [640, 480]; }
...
exports.window = {
width: 75
};
if (isatty) {
exports.window.width = process.stdout.getWindowSize
? process.stdout.getWindowSize(1)[0]
: tty.getWindowSize()[1];
}
/**
* Expose some basic cursor interactions that are common among reporters.
*/
...
function isatty() { return true; }
...
var clearInterval = global.clearInterval;
/* eslint-enable no-unused-vars, no-native-reassign */
/**
* Check if both stdio streams are associated with a tty.
*/
var isatty = tty.isatty(1) && tty.isatty(2);
/**
* Enable coloring by default, except in the browser interface.
*/
exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined));
...
function canonicalize(value, stack, typeHint) {
var canonicalizedObj;
/* eslint-disable no-unused-vars */
var prop;
/* eslint-enable no-unused-vars */
typeHint = typeHint || type(value);
function withStack (value, fn) {
stack.push(value);
fn();
stack.pop();
}
stack = stack || [];
if (indexOf(stack, value) !== -1) {
return '[Circular]';
}
switch (typeHint) {
case 'undefined':
case 'buffer':
case 'null':
canonicalizedObj = value;
break;
case 'array':
withStack(value, function () {
canonicalizedObj = exports.map(value, function (item) {
return exports.canonicalize(item, stack);
});
});
break;
case 'function':
/* eslint-disable guard-for-in */
for (prop in value) {
canonicalizedObj = {};
break;
}
/* eslint-enable guard-for-in */
if (!canonicalizedObj) {
canonicalizedObj = emptyRepresentation(value, typeHint);
break;
}
/* falls through */
case 'object':
canonicalizedObj = canonicalizedObj || {};
withStack(value, function () {
exports.forEach(exports.keys(value).sort(), function (key) {
canonicalizedObj[key] = exports.canonicalize(value[key], stack);
});
});
break;
case 'date':
case 'number':
case 'regexp':
case 'boolean':
case 'symbol':
canonicalizedObj = value;
break;
default:
canonicalizedObj = value + '';
}
return canonicalizedObj;
}
...
} else {
return jsonStringify(value);
}
}
for (var prop in value) {
if (Object.prototype.hasOwnProperty.call(value, prop)) {
return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\n|$)/g, '$1');
}
}
return emptyRepresentation(value, typeHint);
};
/**
...
clean = function (str) { str = str .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content .replace(/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, '$ 1$2$3'); var spaces = str.match(/^\n?( *)/)[1].length; var tabs = str.match(/^\n?(\t*)/)[1].length; var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', 'gm'); str = str.replace(re, ''); return exports.trim(str); }
...
* remove: --watch's spinner (#806)
* fix: duplicate test output for multi-line specs in spec reporter (#1006)
* fix: gracefully exit on SIGINT (#1063)
* fix expose the specified ui only in the browser (#984)
* fix: ensure process exit code is preserved when using --no-exit (#1059)
* fix: return true from window.onerror handler (#868)
* fix: xunit reporter to use process.stdout.write (#1068)
* fix: utils.clean(str) indentation (#761)
* fix: xunit reporter returning test duration a NaN (#1039)
1.15.1 / 2013-12-03
==================
* fix: recompiled for missed changes from the last release
...
escape = function (html) { return String(html) .replace(/&/g, '&') .replace(/"/g, '"') .replace(/</g, '<') .replace(/>/g, '>'); }
...
runner.on('suite', function (suite) {
if (suite.root) {
return;
}
++indents;
console.log('%s<section class="suite">', indent());
++indents;
console.log('%s<h1>%s</h1>', indent(), utils.escape(suite
.title));
console.log('%s<dl>', indent());
});
runner.on('suite end', function (suite) {
if (suite.root) {
return;
}
...
files = function (dir, ext, ret) { ret = ret || []; ext = ext || ['js']; var re = new RegExp('\\.(' + ext.join('|') + ')$'); readdirSync(dir) .filter(ignored) .forEach(function (path) { path = join(dir, path); if (lstatSync(path).isDirectory()) { exports.files(path, ext, ret); } else if (path.match(re)) { ret.push(path); } }); return ret; }
...
var re = new RegExp('\\.(' + ext.join('|') + ')$');
readdirSync(dir)
.filter(ignored)
.forEach(function (path) {
path = join(dir, path);
if (lstatSync(path).isDirectory()) {
exports.files(path, ext, ret);
} else if (path.match(re)) {
ret.push(path);
}
});
return ret;
};
...
filter = function (arr, fn) { var ret = []; for (var i = 0, l = arr.length; i < l; i++) { var val = arr[i]; if (fn(val, i, arr)) { ret.push(val); } } return ret; }
...
}
var msg = diff.createPatch('string', err.actual, err.expected);
var lines = msg.split('\n').splice(4);
return '\n ' +
colorLines('diff added', '+ expected') + ' ' +
colorLines('diff removed', '- actual') +
'\n\n' +
lines.map(cleanUp).filter(notBlank).join('\n');
}
/**
* Return a character diff for `err`.
*
* @api private
* @param {Error} err
...
forEach = function (arr, fn, scope) { for (var i = 0, l = arr.length; i < l; i++) { fn.call(scope, arr[i], i); } }
...
/**
* Function to allow assertion libraries to throw errors directly into mocha.
* This is useful when running tests in a browser because window.onerror will
* only receive the 'message' attribute of the Error.
*/
mocha.throwError = function (err) {
Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) {
fn(err);
});
throw err;
};
/**
* Override ui to ensure that the ui functions are initialized.
...
getError = function (err) { return err || exports.undefinedError(); }
...
if (this.allowUncaught) {
return callFnAsync(this.fn);
}
try {
callFnAsync(this.fn);
} catch (err) {
emitted = true;
done(utils.getError(err));
}
return;
}
if (this.allowUncaught) {
callFn(this.fn);
done();
...
highlightTags = function (name) { var code = document.getElementById('mocha').getElementsByTagName(name); for (var i = 0, len = code.length; i < len; ++i) { code[i].innerHTML = highlight(code[i].innerHTML); } }
...
mocha.invert();
}
return Mocha.prototype.run.call(mocha, function (err) {
// The DOM Document is not available in Web Workers.
var document = global.document;
if (document && document.getElementById('mocha') && options.noHighlighting !== true) {
Mocha.utils.highlightTags('code');
}
if (fn) {
fn(err);
}
});
};
...
indexOf = function (arr, obj, start) { for (var i = start || 0, l = arr.length; i < l; i++) { if (arr[i] === obj) { return i; } } return -1; }
...
process.removeListener = function (e, fn) {
if (e === 'uncaughtException') {
if (originalOnerrorHandler) {
global.onerror = originalOnerrorHandler;
} else {
global.onerror = function () {};
}
var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn);
if (i !== -1) {
uncaughtExceptionHandlers.splice(i, 1);
}
}
};
/**
...
inherits = function (ctor, superCtor) { if (ctor === undefined || ctor === null) throw new TypeError('The constructor to "inherits" must not be ' + 'null or undefined'); if (superCtor === undefined || superCtor === null) throw new TypeError('The super constructor to "inherits" must not ' + 'be null or undefined'); if (superCtor.prototype === undefined) throw new TypeError('The super constructor to "inherits" must ' + 'have a prototype'); ctor.super_ = superCtor; Object.setPrototypeOf(ctor.prototype, superCtor.prototype); }
n/a
function isArray() { [native code] }
...
}
if (Buffer.isBuffer(value)) {
var out = new Buffer(value.length);
value.copy(out, 0, 0, value.length);
return out;
}
if (value) {
if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' &&
; value.buffer instanceof ArrayBuffer) || 'length' in value) {
return new Buffer(value);
}
if (value.type === 'Buffer' && Array.isArray(value.data)) {
return new Buffer(value.data);
}
}
...
isBuffer = function (value) { return typeof Buffer !== 'undefined' && Buffer.isBuffer(value); }
...
* type(new String('foo') // 'object'
*/
var type = exports.type = function type (value) {
if (value === undefined) {
return 'undefined';
} else if (value === null) {
return 'null';
} else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value
)) {
return 'buffer';
}
return Object.prototype.toString.call(value)
.replace(/^\[.+\s(.+?)\]$/, '$1')
.toLowerCase();
};
...
function isPromise(value) { return typeof value === 'object' && typeof value.then === 'function'; }
...
if (err) {
if (Object.prototype.toString.call(err) === '[object Object]') {
return done(new Error('done() invoked with non-Error: ' +
JSON.stringify(err)));
}
return done(new Error('done() invoked with non-Error: ' + err));
}
if (result && utils.isPromise(result)) {
return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'
;));
}
done();
});
}
};
...
isString = function (obj) { return typeof obj === 'string'; }
...
* @param {RegExp|String} re
* @return {Mocha}
* @api public
* @param {RegExp|string} re
* @return {Mocha}
*/
Mocha.prototype.grep = function (re) {
if (utils.isString(re)) {
// extract args if it's regex-like, i.e: [string, pattern, flag]
var arg = re.match(/^\/(.*)\/(g|i|)$|.*/);
this.options.grep = new RegExp(arg[1] || arg[0], arg[2]);
} else {
this.options.grep = re;
}
return this;
...
function keys() { [native code] }
...
return _stringify(object);
}
depth = depth || 1;
var space = spaces * depth;
var str = isArray(object) ? '[' : '{';
var end = isArray(object) ? ']' : '}';
var length = typeof object.length === 'number' ? object.length : exports.keys(object).length;
// `.repeat()` polyfill
function repeat (s, n) {
return new Array(n).join(s);
}
function _stringify (val) {
switch (type(val)) {
...
function lookupFiles(path, extensions, recursive) { var files = []; var re = new RegExp('\\.(' + extensions.join('|') + ')$'); if (!exists(path)) { if (exists(path + '.js')) { path += '.js'; } else { files = glob.sync(path); if (!files.length) { throw new Error("cannot resolve path (or pattern) '" + path + "'"); } return files; } } try { var stat = statSync(path); if (stat.isFile()) { return path; } } catch (err) { // ignore error return; } readdirSync(path).forEach(function (file) { file = join(path, file); try { var stat = statSync(file); if (stat.isDirectory()) { if (recursive) { files = files.concat(lookupFiles(file, extensions, recursive)); } return; } } catch (err) { // ignore error return; } if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { return; } files.push(file); }); return files; }
...
if (!args.length) {
args.push('test');
}
args.forEach(function (arg) {
var newFiles;
try {
newFiles = utils.lookupFiles(arg, extensions, program.recursive);
} catch (err) {
if (err.message.indexOf('cannot resolve path') === 0) {
console.error('Warning: Could not find any test files matching pattern: ' + arg);
return;
}
throw err;
...
map = function (arr, fn, scope) { var result = []; for (var i = 0, l = arr.length; i < l; i++) { result.push(fn.call(scope, arr[i], i, arr)); } return result; }
...
function inlineDiff (err, escape) {
var msg = errorDiff(err, 'WordsWithSpace', escape);
// linenos
var lines = msg.split('\n');
if (lines.length > 4) {
var width = String(lines.length).length;
msg = lines.map(function (str, i) {
return pad(++i, width) + ' |' + ' ' + str;
}).join('\n');
}
// legend
msg = '\n' +
color('diff removed', 'actual') +
...
noop = function () {}
n/a
parseQuery = function (qs) { return reduce(qs.replace('?', '').split('&'), function (obj, pair) { var i = pair.indexOf('='); var key = pair.slice(0, i); var val = pair.slice(++i); // Due to how the URLSearchParams API treats spaces obj[key] = decodeURIComponent(val.replace(/\+/g, '%20')); return obj; }, {}); }
...
* Run mocha, returning the Runner.
*/
mocha.run = function (fn) {
var options = mocha.options;
mocha.globals('location');
var query = Mocha.utils.parseQuery(global.location.search || '');
if (query.grep) {
mocha.grep(query.grep);
}
if (query.fgrep) {
mocha.fgrep(query.fgrep);
}
if (query.invert) {
...
reduce = function (arr, fn, val) { var rval = val; for (var i = 0, l = arr.length; i < l; i++) { rval = fn(rval, arr[i], i, arr); } return rval; }
...
*
* @return {Array}
* @api private
*/
function extraGlobals () {
if (typeof process === 'object' && typeof process.version === 'string') {
var parts = process.version.split('.');
var nodeVersion = utils.reduce(parts, function (a, v) {
return a << 8 | v;
});
// 'errno' was renamed to process._errno in v0.9.11.
if (nodeVersion < 0x00090B) {
return ['errno'];
...
slug = function (str) { return str .toLowerCase() .replace(/ +/g, '-') .replace(/[^-\w]/g, ''); }
...
var link;
for (var key in obj) {
if (key === 'suite') {
continue;
}
if (key !== SUITE_PREFIX) {
link = ' - [' + key.substring(1) + ']';
link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'
;;
buf += Array(level).join(' ') + link;
}
buf += stringifyTOC(obj[key], level);
}
return buf;
}
...
some = function (arr, fn) { for (var i = 0, l = arr.length; i < l; i++) { if (fn(arr[i])) { return true; } } return false; }
...
- [#2672]: Add coverage for node tests ([@c089], [@Munter])
- [#2680]: Increase tests coverage for base reporter ([@epallerols])
- [#2690]: Increase tests coverage for doc reporter ([@craigtaub])
- [#2701]: Increase tests coverage for landing, min, tap and list reporters ([@craigtaub])
- [#2691]: Increase tests coverage for spec + dot reporters ([@craigtaub])
- [#2698]: Increase tests coverage for xunit reporter ([@craigtaub])
- [#2699]: Increase tests coverage for json-stream, markdown and progress reporters ([@craigtaub])
- [#2703]: Cover .some() function in utils.js with tests ([@seppevs])
- [#2773]: Add tests for loading reporters w/ relative/absolute paths ([@sul4bh])
## :nut_and_bolt: Other
- Remove bin/.eslintrc; ensure execs are linted ([@boneskull])
- [#2542]: Expand CONTRIBUTING.md ([@boneskull])
- [#2660]: Double timeouts on integration tests ([@Munter])
...
stackTraceFilter = function () { // TODO: Replace with `process.browser` var is = typeof document === 'undefined' ? { node: true } : { browser: true }; var slash = path.sep; var cwd; if (is.node) { cwd = process.cwd() + slash; } else { cwd = (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^/]*$/, '/'); slash = '/'; } function isMochaInternal (line) { return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) || (~line.indexOf('node_modules' + slash + 'mocha.js')) || (~line.indexOf('bower_components' + slash + 'mocha.js')) || (~line.indexOf(slash + 'mocha.js')); } function isNodeInternal (line) { return (~line.indexOf('(timers.js:')) || (~line.indexOf('(events.js:')) || (~line.indexOf('(node.js:')) || (~line.indexOf('(module.js:')) || (~line.indexOf('GeneratorFunctionPrototype.next (native)')) || false; } return function (stack) { stack = stack.split('\n'); stack = reduce(stack, function (list, line) { if (isMochaInternal(line)) { return list; } if (is.node && isNodeInternal(line)) { return list; } // Clean up cwd(absolute) if (/\(?.+:\d+:\d+\)?$/.test(line)) { line = line.replace(cwd, ''); } list.push(line); return list; }, []); return stack.join('\n'); }; }
...
var inherits = utils.inherits;
var debug = require('debug')('mocha:runner');
var Runnable = require('./runnable');
var filter = utils.filter;
var indexOf = utils.indexOf;
var some = utils.some;
var keys = utils.keys;
var stackFilter = utils.stackTraceFilter();
var stringify = utils.stringify;
var type = utils.type;
var undefinedError = utils.undefinedError;
var isArray = utils.isArray;
/**
* Non-enumerable globals.
...
stringify = function (value) { var typeHint = type(value); if (!~indexOf(['object', 'array', 'function'], typeHint)) { if (typeHint === 'buffer') { var json = value.toJSON(); // Based on the toJSON result return jsonStringify(json.data && json.type ? json.data : json, 2) .replace(/,(\n|$)/g, '$1'); } // IE7/IE8 has a bizarre String constructor; needs to be coerced // into an array and back to obj. if (typeHint === 'string' && typeof value === 'object') { value = reduce(value.split(''), function (acc, char, idx) { acc[idx] = char; return acc; }, {}); typeHint = 'object'; } else { return jsonStringify(value); } } for (var prop in value) { if (Object.prototype.hasOwnProperty.call(value, prop)) { return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\n|$)/g, '$1'); } } return emptyRepresentation(value, typeHint); }
...
- [#880] - Make Mocha browserifyable ([@boneskull] via 524862b)
- [#2121] - Update [glob](https://npmjs.com/package/glob) to v3.2.11 ([@astorije] via 7920fc4)
- [#2126] - Fix dupe error messages in stack trace filter ([@Turbo87] via 4301caa)
- [#2109] - Fix certain diffs when objects cannot be coerced into primitives ([@joshlory] via 61fbb7f)
- [#1827] - Fix TWBS/`mocha.css` collisions ([@irnc] via 0543798)
- [#1760], [#1936] - Fix `this.skip()` in HTML reporter ([@mislav] via cb4248b)
- [#2115] - Fix exceptions thrown from hooks in HTML reporter ([@danielstjules] via e290bc0)
- [#2089] - Handle Symbol values in `util.stringify()` ([@ryym] via ea61d05)
- [#2097] - Fix diff for objects overriding `Object.prototype.hasOwnProperty` ([@mantoni] via b20fdfe)
- [#2101] - Properly handle non-string "messages" thrown from assertion libraries ([@jkimbo] via 9c41051)
- [#2124] - Update [growl](https://npmjs.com/package/growl) ([@benjamine] via 9ae6a85)
- [#2162], [#2205] - JSDoc fixes ([@OlegTsyba] via 8031f20, [@ScottFreeCode] via f83b1d9)
- [#2132] - Remove Growl-related cruft ([@julienw] via 00d6469)
- [#2172] - Add [OpenCollective](https://opencollective.com) badge, sponsors & backers ([@xdamman], [@boneskull] via caee94f
)
- [#1841] - Add new logo, banner assets ([@dasilvacontin] via 00fd0e1)
...
trim = function (str) { return str.replace(/^\s+|\s+$/g, ''); }
...
1.4.0 / 2012-08-22
==================
* add mkdir -p to `mocha init`. Closes #539
* add `.only()`. Closes #524
* add `.skip()`. Closes #524
* change str.trim() to use utils.trim(). Closes #533
* fix HTML progress indicator retina display
* fix url-encoding of click-to-grep HTML functionality
1.3.2 / 2012-08-01
==================
* fix exports double-execution regression. Closes #531
...
function type(value) { if (value === undefined) { return 'undefined'; } else if (value === null) { return 'null'; } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { return 'buffer'; } return Object.prototype.toString.call(value) .replace(/^\[.+\s(.+?)]$/, '$1') .toLowerCase(); }
...
for (var i = 0, len = paths.length; i < len; ++i) {
loc = path.join(paths[i], name);
if (exists(loc)) return loc;
}
}
switch(os.type()) {
case 'Darwin':
if (which('terminal-notifier')) {
cmd = {
type: "Darwin-NotificationCenter"
, pkg: "terminal-notifier"
, msg: '-message'
, title: '-title'
...
undefinedError = function () { return new Error('Caught undefined error, did you throw without specifying what?'); }
...
* Generate an undefined error if `err` is not defined.
*
* @param {Error} err
* @return {Error}
*/
exports.getError = function (err) {
return err || exports.undefinedError();
};
/**
* @summary
* This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
* @description
* When invoking this function you get a filter function that get the Error.stack as an input,
...
watch = function (files, fn) { var options = { interval: 100 }; files.forEach(function (file) { debug('file %s', file); watchFile(file, options, function (curr, prev) { if (prev.mtime < curr.mtime) { fn(file); } }); }); }
...
}
mocha.suite = mocha.suite.clone();
mocha.suite.ctx = new Mocha.Context();
mocha.ui(program.ui);
loadAndRun();
};
utils.watch(watchFiles, function () {
runAgain = true;
if (runner) {
runner.abort();
} else {
rerun();
}
});
...
function XUnit(runner, options) { Base.call(this, runner); var stats = this.stats; var tests = []; var self = this; if (options && options.reporterOptions && options.reporterOptions.output) { if (!fs.createWriteStream) { throw new Error('file output not supported in browser'); } mkdirp.sync(path.dirname(options.reporterOptions.output)); self.fileStream = fs.createWriteStream(options.reporterOptions.output); } runner.on('pending', function (test) { tests.push(test); }); runner.on('pass', function (test) { tests.push(test); }); runner.on('fail', function (test) { tests.push(test); }); runner.on('end', function () { self.write(tag('testsuite', { name: 'Mocha Tests', tests: stats.tests, failures: stats.failures, errors: stats.failures, skipped: stats.tests - stats.failures - stats.passes, timestamp: (new Date()).toUTCString(), time: (stats.duration / 1000) || 0 }, false)); tests.forEach(function (t) { self.test(t); }); self.write('</testsuite>'); }); }
n/a
function Base(runner) { var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; var failures = this.failures = []; if (!runner) { return; } 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) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function (test, err) { stats.failures = stats.failures || 0; stats.failures++; test.err = err; failures.push(test); }); runner.on('end', function () { stats.end = new Date(); stats.duration = new Date() - stats.start; }); runner.on('pending', function () { stats.pending++; }); }
n/a
done = function (failures, fn) { if (this.fileStream) { this.fileStream.end(function () { fn(failures); }); } else { fn(failures); } }
...
if (options.useColors !== undefined) {
exports.reporters.Base.useColors = options.useColors;
}
exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
function done (failures) {
if (reporter.done) {
reporter.done(failures, fn);
} else {
fn && fn(failures);
}
}
return runner.run(done);
};
...
test = function (test) { var attrs = { classname: test.parent.fullTitle(), name: test.title, time: (test.duration / 1000) || 0 }; if (test.state === 'failed') { var err = test.err; this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack)))); } else if (test.isPending()) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { this.write(tag('testcase', attrs, true)); } }
...
/**
* Pending test case.
*
* @param {string} title
*/
skip: function (title) {
context.test(title);
},
/**
* Number of retry attempts
*
* @param {number} n
*/
...
write = function (line) { if (this.fileStream) { this.fileStream.write(line + '\n'); } else if (typeof process === 'object' && process.stdout) { process.stdout.write(line + '\n'); } else { console.log(line); } }
...
/**
* Expose some basic cursor interactions that are common among reporters.
*/
exports.cursor = {
hide: function () {
isatty && process.stdout.write('\u001b[?25l');
},
show: function () {
isatty && process.stdout.write('\u001b[?25h');
},
deleteLine: function () {
...