2014-10-23 11:17:19 -07:00

2449 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
// FIXME: This really could be trimmed down from all the generic and commonjs crap.
;(function(){
// CommonJS require()
function require(p){
var path = require.resolve(p)
, mod = require.modules[path];
if (!mod) throw new Error('failed to require "' + p + '"');
if (!mod.exports) {
mod.exports = {};
mod.call(mod.exports, mod, mod.exports, require.relative(path));
}
return mod.exports;
}
require.modules = {};
require.resolve = function (path){
var orig = path
, reg = path + '.js'
, index = path + '/index.js';
return require.modules[reg] && reg
|| require.modules[index] && index
|| orig;
};
require.register = function (path, fn){
require.modules[path] = fn;
};
require.relative = function (parent) {
return function(p){
if ('.' != p.charAt(0)) return require(p);
var path = parent.split('/')
, segs = p.split('/');
path.pop();
for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if ('..' == seg) path.pop();
else if ('.' != seg) path.push(seg);
}
return require(path.join('/'));
};
};
require.register("browser/debug.js", function(module, exports, require){
module.exports = function(type){
return function(){
}
};
}); // module: browser/debug.js
require.register("browser/events.js", function(module, exports, require){
/**
* Module exports.
*/
exports.EventEmitter = EventEmitter;
/**
* Check if `obj` is an array.
*/
function isArray(obj) {
return '[object Array]' == {}.toString.call(obj);
}
/**
* Event emitter constructor.
*
* @api public
*/
function EventEmitter(){};
/**
* Adds a listener.
*
* @api public
*/
EventEmitter.prototype.on = function (name, fn) {
if (!this.$events) {
this.$events = {};
}
if (!this.$events[name]) {
this.$events[name] = fn;
} else if (isArray(this.$events[name])) {
this.$events[name].push(fn);
} else {
this.$events[name] = [this.$events[name], fn];
}
return this;
};
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
/**
* Adds a volatile listener.
*
* @api public
*/
EventEmitter.prototype.once = function (name, fn) {
var self = this;
function on () {
self.removeListener(name, on);
fn.apply(this, arguments);
};
on.listener = fn;
this.on(name, on);
return this;
};
/**
* Removes a listener.
*
* @api public
*/
EventEmitter.prototype.removeListener = function (name, fn) {
if (this.$events && this.$events[name]) {
var list = this.$events[name];
if (isArray(list)) {
var pos = -1;
for (var i = 0, l = list.length; i < l; i++) {
if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
pos = i;
break;
}
}
if (pos < 0) {
return this;
}
list.splice(pos, 1);
if (!list.length) {
delete this.$events[name];
}
} else if (list === fn || (list.listener && list.listener === fn)) {
delete this.$events[name];
}
}
return this;
};
/**
* Removes all listeners for an event.
*
* @api public
*/
EventEmitter.prototype.removeAllListeners = function (name) {
if (name === undefined) {
this.$events = {};
return this;
}
if (this.$events && this.$events[name]) {
this.$events[name] = null;
}
return this;
};
/**
* Gets all listeners for a certain event.
*
* @api public
*/
EventEmitter.prototype.listeners = function (name) {
if (!this.$events) {
this.$events = {};
}
if (!this.$events[name]) {
this.$events[name] = [];
}
if (!isArray(this.$events[name])) {
this.$events[name] = [this.$events[name]];
}
return this.$events[name];
};
/**
* Emits an event.
*
* @api public
*/
EventEmitter.prototype.emit = function (name) {
if (!this.$events) {
return false;
}
var handler = this.$events[name];
if (!handler) {
return false;
}
var args = [].slice.call(arguments, 1);
if ('function' == typeof handler) {
handler.apply(this, args);
} else if (isArray(handler)) {
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
} else {
return false;
}
return true;
};
}); // module: browser/events.js
require.register("browser/path.js", function(module, exports, require){
}); // module: browser/path.js
require.register("context.js", function(module, exports, require){
/**
* Expose `Context`.
*/
module.exports = Context;
/**
* Initialize a new `Context`.
*
* @api private
*/
function Context(){}
/**
* Set or get the context `Runnable` to `runnable`.
*
* @param {Runnable} runnable
* @return {Context}
* @api private
*/
Context.prototype.runnable = function(runnable){
if (0 == arguments.length) return this._runnable;
this.test = this._runnable = runnable;
return this;
};
/**
* Set test timeout `ms`.
*
* @param {Number} ms
* @return {Context} self
* @api private
*/
Context.prototype.timeout = function(ms){
if (arguments.length === 0) return this.runnable().timeout();
this.runnable().timeout(ms);
return this;
};
/**
* Set test timeout `enabled`.
*
* @param {Boolean} enabled
* @return {Context} self
* @api private
*/
Context.prototype.enableTimeouts = function (enabled) {
this.runnable().enableTimeouts(enabled);
return this;
};
/**
* Set test slowness threshold `ms`.
*
* @param {Number} ms
* @return {Context} self
* @api private
*/
Context.prototype.slow = function(ms){
this.runnable().slow(ms);
return this;
};
/**
* Inspect the context void of `._runnable`.
*
* @return {String}
* @api private
*/
Context.prototype.inspect = function(){
return JSON.stringify(this, function(key, val){
if ('_runnable' == key) return;
if ('test' == key) return;
return val;
}, 2);
};
}); // module: context.js
require.register("hook.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Runnable = require('./runnable');
/**
* Expose `Hook`.
*/
module.exports = Hook;
/**
* Initialize a new `Hook` with the given `title` and callback `fn`.
*
* @param {String} title
* @param {Function} fn
* @api private
*/
function Hook(title, fn) {
Runnable.call(this, title, fn);
this.type = 'hook';
}
/**
* Inherit from `Runnable.prototype`.
*/
function F(){};
F.prototype = Runnable.prototype;
Hook.prototype = new F;
Hook.prototype.constructor = Hook;
/**
* Get or set the test `err`.
*
* @param {Error} err
* @return {Error}
* @api public
*/
Hook.prototype.error = function(err){
if (0 == arguments.length) {
var err = this._error;
this._error = null;
return err;
}
this._error = err;
};
}); // module: hook.js
require.register("interfaces/bdd.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Suite = require('../suite')
, Test = require('../test')
, utils = require('../utils');
/**
* BDD-style interface:
*
* describe('Array', function(){
* describe('#indexOf()', function(){
* it('should return -1 when not present', function(){
*
* });
*
* it('should return the index when present', function(){
*
* });
* });
* });
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('pre-require', function(context, file, mocha){
/**
* Execute before running tests.
*/
context.before = function(name, fn){
suites[0].beforeAll(name, fn);
};
/**
* Execute after running tests.
*/
context.after = function(name, fn){
suites[0].afterAll(name, fn);
};
/**
* Execute before each test case.
*/
context.beforeEach = function(name, fn){
suites[0].beforeEach(name, fn);
};
/**
* Execute after each test case.
*/
context.afterEach = function(name, fn){
suites[0].afterEach(name, fn);
};
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.describe = context.context = function(title, fn){
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
/**
* Pending describe.
*/
context.describe.skip = function(title, fn){
var suite = Suite.create(suites[0], title);
suite.pending = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
};
context.describe.only = function(title, fn){
var suite = context.describe(title, fn);
mocha.grep(suite.fullTitle());
return suite;
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = function(title, fn){
var suite = suites[0];
if (suite.pending) var fn = null;
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
context.it.only = function(title, fn){
var test = context.it(title, fn);
var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
mocha.grep(new RegExp(reString));
return test;
};
/**
* Pending test case.
*/
context.it.skip = function(title){
context.it(title);
};
});
};
}); // module: interfaces/bdd.js
require.register("interfaces/exports.js", function(module, exports, require){
/**
* Module dependencies.
SGMcan */
var Suite = require('../suite')
, Test = require('../test');
/**
* TDD-style interface:
*
* exports.Array = {
* '#indexOf()': {
* 'should return -1 when the value is not present': function(){
*
* },
*
* 'should return the correct index when the value is present': function(){
*
* }
* }
* };
*
*/
module.exports = function(suite){
var suites = [suite];
suite.on('require', visit);
function visit(obj, file) {
var suite;
for (var key in obj) {
if ('function' == typeof obj[key]) {
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 {
var suite = Suite.create(suites[0], key);
suites.unshift(suite);
visit(obj[key]);
suites.shift();
}
}
}
};
}); // module: interfaces/exports.js
require.register("interfaces/index.js", function(module, exports, require){
exports.bdd = require('./bdd');
exports.exports = require('./exports');
}); // module: interfaces/index.js
require.register("mocha.js", function(module, exports, require){
/*!
* mocha
* Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var path = require('browser/path')
, utils = require('./utils');
/**
* Expose `Mocha`.
*/
exports = module.exports = Mocha;
/**
* To require local UIs and reporters when running in node.
*/
if (typeof process !== 'undefined' && typeof process.cwd === 'function') {
var join = path.join
, cwd = process.cwd();
module.paths.push(cwd, join(cwd, 'node_modules'));
}
/**
* Expose internals.
*/
exports.utils = utils;
exports.interfaces = require('./interfaces');
exports.reporters = require('./reporters');
exports.Runnable = require('./runnable');
exports.Context = require('./context');
exports.Runner = require('./runner');
exports.Suite = require('./suite');
exports.Hook = require('./hook');
exports.Test = require('./test');
/**
* Setup mocha with `options`.
*
* Options:
*
* - `ui` name "bdd", "tdd", "exports" etc
* - `reporter` reporter instance, defaults to `mocha.reporters.spec`
* - `timeout` timeout in milliseconds
* - `bail` bail on the first test failure
* - `slow` milliseconds to wait before considering a test slow
*
* @param {Object} options
* @api public
*/
function Mocha(options) {
options = options || {};
this.files = [];
this.options = options;
this.grep(options.grep);
this.suite = new exports.Suite('', new exports.Context);
this.ui(options.ui);
this.bail(options.bail);
this.reporter();
if (null != options.timeout) this.timeout(options.timeout);
if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
if (options.slow) this.slow(options.slow);
this.suite.on('pre-require', function (context) {
exports.afterEach = context.afterEach;
exports.after = context.after;
exports.beforeEach = context.beforeEach;
exports.before = context.before;
exports.describe = context.describe;
exports.it = context.it;
});
}
/**
* Enable or disable bailing on the first failure.
*
* @param {Boolean} [bail]
* @api public
*/
Mocha.prototype.bail = function(bail){
if (0 == arguments.length) bail = true;
this.suite.bail(bail);
return this;
};
/**
* Set reporter to `reporter`, defaults to "spec".
*
* @param {String|Function} reporter name or constructor
* @api public
*/
Mocha.prototype.reporter = function(){
var _reporter = require('./reporters/tap');
this._reporter = _reporter;
};
/**
* Set test UI `name`, defaults to "bdd".
*
* @param {String} bdd
* @api public
*/
Mocha.prototype.ui = function(name){
name = name || 'bdd';
this._ui = exports.interfaces[name];
if (!this._ui) try { this._ui = require(name); } catch (err) {};
if (!this._ui) throw new Error('invalid interface "' + name + '"');
this._ui = this._ui(this.suite);
return this;
};
Mocha.prototype.grep = function(re){
this.options.grep = 'string' == typeof re
? new RegExp(utils.escapeRegexp(re))
: re;
return this;
};
/**
* Set the timeout in milliseconds.
*
* @param {Number} timeout
* @return {Mocha}
* @api public
*/
Mocha.prototype.timeout = function(timeout){
this.suite.timeout(timeout);
return this;
};
/**
* Set slowness threshold in milliseconds.
*
* @param {Number} slow
* @return {Mocha}
* @api public
*/
Mocha.prototype.slow = function(slow){
this.suite.slow(slow);
return this;
};
/**
* Enable timeouts.
*
* @param {Boolean} enabled
* @return {Mocha}
* @api public
*/
Mocha.prototype.enableTimeouts = function(enabled) {
this.suite.enableTimeouts(arguments.length && enabled !== undefined
? enabled
: true);
return this
};
/**
* Makes all tests async (accepting a callback)
*
* @return {Mocha}
* @api public
*/
Mocha.prototype.asyncOnly = function(){
this.options.asyncOnly = true;
return this;
};
/**
* Run tests and invoke `fn()` when complete.
*
* @param {Function} fn
* @return {Runner}
* @api public
*/
Mocha.prototype.run = function(fn){
var suite = this.suite;
var options = this.options;
options.files = this.files;
var runner = new exports.Runner(suite);
var reporter = new this._reporter(runner, options);
if (options.grep) runner.grep(options.grep);
return runner.run(fn);
};
}); // module: mocha.js
require.register("ms.js", function(module, exports, require){
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} options
* @return {String|Number}
* @api public
*/
module.exports = function(val, options){
options = options || {};
if ('string' == typeof val) return parse(val);
return options.long ? longFormat(val) : shortFormat(val);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
if (!match) return;
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'y':
return n * y;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 's':
return n * s;
case 'ms':
return n;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function shortFormat(ms) {
if (ms >= d) return Math.round(ms / d) + 'd';
if (ms >= h) return Math.round(ms / h) + 'h';
if (ms >= m) return Math.round(ms / m) + 'm';
if (ms >= s) return Math.round(ms / s) + 's';
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function longFormat(ms) {
return plural(ms, d, 'day')
|| plural(ms, h, 'hour')
|| plural(ms, m, 'minute')
|| plural(ms, s, 'second')
|| ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, n, name) {
if (ms < n) return;
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
return Math.ceil(ms / n) + ' ' + name + 's';
}
}); // module: ms.js
require.register("reporters/base.js", function(module, exports, require){
/**
* Module dependencies.
*/
var ms = require('../ms')
, utils = require('../utils');
/**
* Expose `Base`.
*/
exports = module.exports = Base;
/**
* Enable coloring by default.
*/
exports.useColors = false;
/**
* Inline diffs instead of +/-
*/
exports.inlineDiffs = false;
/**
* Default symbol map.
*/
exports.symbols = {
ok: '✓',
err: '✖',
dot: ''
};
/**
* Expose term window size, with some
* defaults for when stderr is not a tty.
*/
exports.window = {
width: 75
};
/**
* Outut the given `failures` as a list.
*
* @param {Array} failures
* @api public
*/
exports.list = function(failures){
};
/**
* Initialize a new `Base` reporter.
*
* All other reporters generally
* inherit from this reporter, providing
* stats such as test duration, number
* of tests passed / failed etc.
*
* @param {Runner} runner
* @api public
*/
function Base(runner) {
if (!runner) return;
this.runner = runner;
}
}); // module: reporters/base.js
require.register("reporters/index.js", function(module, exports, require){
exports.Base = require('./base');
exports.TAP = require('./tap');
}); // module: reporters/index.js
require.register("reporters/tap.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Base = require('./base')
, color = Base.color;
function Logger() {
this.items = [];
}
Logger.prototype.log = function(message) {
this.items.push(message);
}
Logger.prototype.flush = function() {
var body = document.documentElement;
body.textContent = '';
body.appendChild(document.createElement('style')).textContent = 'item { display: block; }';
this.items.forEach(function(item) {
body.appendChild(document.createElement('item')).textContent = item;
});
}
/**
* Expose `TAP`.
*/
exports = module.exports = TAP;
/**
* Initialize a new `TAP` reporter.
*
* @param {Runner} runner
* @api public
*/
function TAP(runner) {
Base.call(this, runner);
var logger = new Logger();
var self = this
, stats = this.stats
, n = 1
, passes = 0
, failures = 0;
runner.on('start', function(){
var total = runner.grepTotal(runner.suite);
logger.log('Running ' + total + ' tests');
});
runner.on('test end', function(){
++n;
});
runner.on('pending', function(test){
logger.log('ok ' + n + ' ' + title(test) + ' # SKIP -');
});
runner.on('pass', function(test){
passes++;
logger.log('ok ' + n + ' ' + title(test));
});
runner.on('fail', function(test, err){
failures++;
logger.log('not ok ' + n + ' ' + title(test));
if (err.stack) logger.log(err.stack.replace(/^/gm, ' '));
});
runner.on('end', function(){
logger.log((passes + failures) + ' tests');
logger.log(passes + ' pass');
logger.log(failures + ' fail');
logger.flush();
window.internals && window.internals.notifyTestComplete(internals.contentAsText());
});
}
/**
* Return a TAP-safe title of `test`
*
* @param {Object} test
* @return {String}
* @api private
*/
function title(test) {
return test.fullTitle().replace(/#/g, '');
}
}); // module: reporters/tap.js
require.register("runnable.js", function(module, exports, require){
/**
* Module dependencies.
*/
var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('mocha:runnable')
, milliseconds = require('./ms');
/**
* Object#toString().
*/
var toString = Object.prototype.toString;
/**
* Expose `Runnable`.
*/
module.exports = Runnable;
/**
* Initialize a new `Runnable` with the given `title` and callback `fn`.
*
* @param {String} title
* @param {Function} fn
* @api private
*/
function Runnable(title, fn) {
this.title = title;
this.fn = fn;
this.async = fn && fn.length;
this.sync = ! this.async;
this._timeout = 2000;
this._slow = 75;
this._enableTimeouts = true;
this.timedOut = false;
}
/**
* Inherit from `EventEmitter.prototype`.
*/
function F(){};
F.prototype = EventEmitter.prototype;
Runnable.prototype = new F;
Runnable.prototype.constructor = Runnable;
/**
* Set & get timeout `ms`.
*
* @param {Number|String} ms
* @return {Runnable|Number} ms or self
* @api private
*/
Runnable.prototype.timeout = function(ms){
if (0 == arguments.length) return this._timeout;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('timeout %d', ms);
this._timeout = ms;
if (this.timer) this.resetTimeout();
return this;
};
/**
* Set & get slow `ms`.
*
* @param {Number|String} ms
* @return {Runnable|Number} ms or self
* @api private
*/
Runnable.prototype.slow = function(ms){
if (0 === arguments.length) return this._slow;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('timeout %d', ms);
this._slow = ms;
return this;
};
/**
* Set and & get timeout `enabled`.
*
* @param {Boolean} enabled
* @return {Runnable|Boolean} enabled or self
* @api private
*/
Runnable.prototype.enableTimeouts = function(enabled){
if (arguments.length === 0) return this._enableTimeouts;
debug('enableTimeouts %s', enabled);
this._enableTimeouts = enabled;
return this;
};
/**
* Return the full title generated by recursively
* concatenating the parent's full title.
*
* @return {String}
* @api public
*/
Runnable.prototype.fullTitle = function(){
return this.parent.fullTitle() + ' ' + this.title;
};
/**
* Clear the timeout.
*
* @api private
*/
Runnable.prototype.clearTimeout = function(){
clearTimeout(this.timer);
};
/**
* Inspect the runnable void of private properties.
*
* @return {String}
* @api private
*/
Runnable.prototype.inspect = function(){
return JSON.stringify(this, function(key, val){
if ('_' == key[0]) return;
if ('parent' == key) return '#<Suite>';
if ('ctx' == key) return '#<Context>';
return val;
}, 2);
};
/**
* Reset the timeout.
*
* @api private
*/
Runnable.prototype.resetTimeout = function(){
var self = this;
var ms = this.timeout() || 1e9;
if (!this._enableTimeouts) return;
this.clearTimeout();
this.timer = setTimeout(function(){
self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
self.timedOut = true;
}, ms);
};
/**
* Run the test and invoke `fn(err)`.
*
* @param {Function} fn
* @api private
*/
Runnable.prototype.run = function(fn){
var self = this
, start = new Date
, ctx = this.ctx
, finished
, emitted;
// Some times 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'));
}
// finished
function done(err) {
var ms = self.timeout();
if (self.timedOut) return;
if (finished) return multiple(err);
self.clearTimeout();
self.duration = new Date - start;
finished = true;
if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded');
fn(err);
}
// for .resetTimeout()
this.callback = done;
// explicit async with `done` argument
if (this.async) {
this.resetTimeout();
try {
this.fn.call(ctx, function(err){
if (err instanceof Error || toString.call(err) === "[object Error]") return done(err);
if (null != err) {
if (Object.prototype.toString.call(err) === '[object Object]') {
return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err)));
} else {
return done(new Error('done() invoked with non-Error: ' + err));
}
}
done();
});
} catch (err) {
done(err);
}
return;
}
if (this.asyncOnly) {
return done(new Error('--async-only option in use without declaring `done()`'));
}
// sync or promise-returning
try {
if (this.pending) {
done();
} else {
callFn(this.fn);
}
} catch (err) {
done(err);
}
function callFn(fn) {
var result = fn.call(ctx);
if (result && typeof result.then === 'function') {
self.resetTimeout();
result
.then(function() {
done()
},
function(reason) {
done(reason || new Error('Promise rejected with no or falsy reason'))
});
} else {
done();
}
}
};
}); // module: runnable.js
require.register("runner.js", function(module, exports, require){
/**
* Module dependencies.
*/
var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('mocha:runner')
, Test = require('./test')
, utils = require('./utils')
, filter = utils.filter
, keys = utils.keys;
/**
* Expose `Runner`.
*/
module.exports = Runner;
/**
* Initialize a `Runner` for the given `suite`.
*
* Events:
*
* - `start` execution started
* - `end` execution complete
* - `suite` (suite) test suite execution started
* - `suite end` (suite) all tests (and sub-suites) have finished
* - `test` (test) test execution started
* - `test end` (test) test completed
* - `hook` (hook) hook execution started
* - `hook end` (hook) hook complete
* - `pass` (test) test passed
* - `fail` (test, err) test failed
* - `pending` (test) test pending
*
* @api public
*/
function Runner(suite) {
var self = this;
this._abort = false;
this.suite = suite;
this.total = suite.total();
this.failures = 0;
this.grep(/.*/);
}
/**
* Wrapper for setImmediate, process.nextTick, or browser polyfill.
*
* @param {Function} fn
* @api private
*/
Runner.immediately = process.nextTick;
/**
* Inherit from `EventEmitter.prototype`.
*/
function F(){};
F.prototype = EventEmitter.prototype;
Runner.prototype = new F;
Runner.prototype.constructor = Runner;
/**
* Run tests with full titles matching `re`. Updates runner.total
* with number of tests matched.
*
* @param {RegExp} re
* @param {Boolean} invert
* @return {Runner} for chaining
* @api public
*/
Runner.prototype.grep = function(re, invert){
debug('grep %s', re);
this._grep = re;
this._invert = invert;
this.total = this.grepTotal(this.suite);
return this;
};
/**
* Returns the number of tests matching the grep search for the
* given suite.
*
* @param {Suite} suite
* @return {Number}
* @api public
*/
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++;
});
return total;
};
/**
* Check for global variable leaks.
*
* @api private
*/
/**
* Fail the given `test`.
*
* @param {Test} test
* @param {Error} err
* @api private
*/
Runner.prototype.fail = function(test, err){
++this.failures;
test.state = 'failed';
if ('string' == typeof err) {
err = new Error('the string "' + err + '" was thrown, throw an Error :)');
}
this.emit('fail', test, err);
};
/**
* Fail the given `hook` with `err`.
*
* Hook failures work in the following pattern:
* - If bail, then exit
* - Failed `before` hook skips all tests in a suite and subsuites,
* but jumps to corresponding `after` hook
* - Failed `before each` hook skips remaining tests in a
* suite and jumps to corresponding `after each` hook,
* which is run only once
* - Failed `after` hook does not alter
* execution order
* - Failed `after each` hook skips remaining tests in a
* suite and subsuites, but executes other `after each`
* hooks
*
* @param {Hook} hook
* @param {Error} err
* @api private
*/
Runner.prototype.failHook = function(hook, err){
this.fail(hook, err);
if (this.suite.bail()) {
this.emit('end');
}
};
/**
* Run hook `name` callbacks and then invoke `fn()`.
*
* @param {String} name
* @param {Function} function
* @api private
*/
Runner.prototype.hook = function(name, fn){
var suite = this.suite
, hooks = suite['_' + name]
, self = this
, timer;
function next(i) {
var hook = hooks[i];
if (!hook) return fn();
if (self.failures && suite.bail()) return fn();
self.currentRunnable = hook;
hook.ctx.currentTest = self.test;
self.emit('hook', hook);
hook.on('error', function(err){
self.failHook(hook, err);
});
hook.run(function(err){
hook.removeAllListeners('error');
var testError = hook.error();
if (testError) self.fail(self.test, testError);
if (err) {
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);
});
};
/**
* Run hook `name` for the given array of `suites`
* in order, and callback `fn(err, errSuite)`.
*
* @param {String} name
* @param {Array} suites
* @param {Function} fn
* @api private
*/
Runner.prototype.hooks = function(name, suites, fn){
var self = this
, 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());
};
/**
* 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
* @param {Function} fn
* @api private
*/
Runner.prototype.hookDown = function(name, fn){
var suites = [this.suite].concat(this.parents());
this.hooks(name, suites, fn);
};
/**
* Return an array of parent Suites from
* closest to furthest.
*
* @return {Array}
* @api private
*/
Runner.prototype.parents = function(){
var suite = this.suite
, suites = [];
while (suite = suite.parent) suites.push(suite);
return suites;
};
/**
* Run the current test and callback `fn(err)`.
*
* @param {Function} fn
* @api private
*/
Runner.prototype.runTest = function(fn){
var test = this.test
, self = this;
if (this.asyncOnly) test.asyncOnly = true;
try {
test.on('error', function(err){
self.fail(test, err);
});
test.run(fn);
} catch (err) {
fn(err);
}
};
/**
* Run tests in the given `suite` and invoke
* the callback `fn()` when complete.
*
* @param {Suite} suite
* @param {Function} fn
* @api private
*/
Runner.prototype.runTests = function(suite, fn){
var self = this
, tests = suite.tests.slice()
, test;
function hookErr(err, 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) return next();
// pending
if (test.pending) {
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 (err) return hookErr(err, errSuite, false);
self.currentRunnable = self.test;
self.runTest(function(err){
test = self.test;
if (err) {
self.fail(test, err);
self.emit('test end', test);
return self.hookUp('afterEach', next);
}
test.state = 'passed';
self.emit('pass', test);
self.emit('test end', test);
self.hookUp('afterEach', next);
});
});
}
this.next = next;
next();
};
/**
* Run the given `suite` and invoke the
* callback `fn()` when complete.
*
* @param {Suite} suite
* @param {Function} fn
* @api private
*/
Runner.prototype.runSuite = function(suite, fn){
var total = this.grepTotal(suite)
, self = this
, i = 0;
debug('run suite %s', suite.fullTitle());
if (!total) 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();
} else {
// 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();
self.runSuite(curr, next);
}
function done(errSuite) {
self.suite = suite;
self.hook('afterAll', function(){
self.emit('suite end', suite);
fn(errSuite);
});
}
this.hook('beforeAll', function(err){
if (err) return done();
self.runTests(suite, next);
});
};
/**
* Handle uncaught exceptions.
*
* @param {Error} err
* @api private
*/
Runner.prototype.uncaught = function(err){
if (err) {
debug('uncaught exception %s', err.message);
} else {
debug('uncaught undefined exception');
err = new Error('Catched undefined error, did you throw without specifying what?');
}
var runnable = this.currentRunnable;
if (!runnable || 'failed' == runnable.state) return;
runnable.clearTimeout();
err.uncaught = true;
this.fail(runnable, err);
// recover from test
if ('test' == runnable.type) {
this.emit('test end', runnable);
this.hookUp('afterEach', this.next);
return;
}
// bail on hooks
this.emit('end');
};
/**
* Run the root suite and invoke `fn(failures)`
* on completion.
*
* @param {Function} fn
* @return {Runner} for chaining
* @api public
*/
Runner.prototype.run = function(fn){
var self = this
, fn = fn || function(){};
function uncaught(err){
self.uncaught(err);
}
debug('start');
// callback
this.on('end', function(){
debug('end');
process.removeListener('uncaughtException', uncaught);
fn(self.failures);
});
// run suites
this.emit('start');
this.runSuite(this.suite, function(){
debug('finished running');
self.emit('end');
});
// uncaught exception
process.on('uncaughtException', uncaught);
return this;
};
/**
* Cleanly abort execution
*
* @return {Runner} for chaining
* @api public
*/
Runner.prototype.abort = function(){
debug('aborting');
this._abort = true;
}
}); // module: runner.js
require.register("suite.js", function(module, exports, require){
/**
* Module dependencies.
*/
var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('mocha:suite')
, milliseconds = require('./ms')
, Hook = require('./hook');
/**
* Expose `Suite`.
*/
exports = module.exports = Suite;
/**
* Create a new `Suite` with the given `title`
* and parent `Suite`. When a suite with the
* same title is already present, that suite
* is returned to provide nicer reporter
* and more flexible meta-testing.
*
* @param {Suite} parent
* @param {String} title
* @return {Suite}
* @api public
*/
exports.create = function(parent, title){
var suite = new Suite(title, parent.ctx);
suite.parent = parent;
if (parent.pending) suite.pending = true;
title = suite.fullTitle();
parent.addSuite(suite);
return suite;
};
/**
* Initialize a new `Suite` with the given
* `title` and `ctx`.
*
* @param {String} title
* @param {Context} ctx
* @api private
*/
function Suite(title, parentContext) {
this.title = title;
var context = function() {};
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;
}
/**
* Inherit from `EventEmitter.prototype`.
*/
function F(){};
F.prototype = EventEmitter.prototype;
Suite.prototype = new F;
Suite.prototype.constructor = Suite;
/**
* Return a clone of this `Suite`.
*
* @return {Suite}
* @api private
*/
Suite.prototype.clone = function(){
var suite = new Suite(this.title);
debug('clone');
suite.ctx = this.ctx;
suite.timeout(this.timeout());
suite.enableTimeouts(this.enableTimeouts());
suite.slow(this.slow());
suite.bail(this.bail());
return suite;
};
/**
* Set timeout `ms` or short-hand such as "2s".
*
* @param {Number|String} ms
* @return {Suite|Number} for chaining
* @api private
*/
Suite.prototype.timeout = function(ms){
if (0 == arguments.length) return this._timeout;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('timeout %d', ms);
this._timeout = parseInt(ms, 10);
return this;
};
/**
* Set timeout `enabled`.
*
* @param {Boolean} enabled
* @return {Suite|Boolean} self or enabled
* @api private
*/
Suite.prototype.enableTimeouts = function(enabled){
if (arguments.length === 0) return this._enableTimeouts;
debug('enableTimeouts %s', enabled);
this._enableTimeouts = enabled;
return this;
}
/**
* Set slow `ms` or short-hand such as "2s".
*
* @param {Number|String} ms
* @return {Suite|Number} for chaining
* @api private
*/
Suite.prototype.slow = function(ms){
if (0 === arguments.length) return this._slow;
if ('string' == typeof ms) ms = milliseconds(ms);
debug('slow %d', ms);
this._slow = ms;
return this;
};
/**
* Sets whether to bail after first error.
*
* @parma {Boolean} bail
* @return {Suite|Number} for chaining
* @api private
*/
Suite.prototype.bail = function(bail){
if (0 == arguments.length) return this._bail;
debug('bail %s', bail);
this._bail = bail;
return this;
};
/**
* Run `fn(test[, done])` before running tests.
*
* @param {Function} fn
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.beforeAll = function(title, fn){
if (this.pending) return this;
if ('function' === typeof title) {
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.enableTimeouts(this.enableTimeouts());
hook.slow(this.slow());
hook.ctx = this.ctx;
this._beforeAll.push(hook);
this.emit('beforeAll', hook);
return this;
};
/**
* Run `fn(test[, done])` after running tests.
*
* @param {Function} fn
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.afterAll = function(title, fn){
if (this.pending) return this;
if ('function' === typeof title) {
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.enableTimeouts(this.enableTimeouts());
hook.slow(this.slow());
hook.ctx = this.ctx;
this._afterAll.push(hook);
this.emit('afterAll', hook);
return this;
};
/**
* Run `fn(test[, done])` before each test case.
*
* @param {Function} fn
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.beforeEach = function(title, fn){
if (this.pending) return this;
if ('function' === typeof title) {
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.enableTimeouts(this.enableTimeouts());
hook.slow(this.slow());
hook.ctx = this.ctx;
this._beforeEach.push(hook);
this.emit('beforeEach', hook);
return this;
};
/**
* Run `fn(test[, done])` after each test case.
*
* @param {Function} fn
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.afterEach = function(title, fn){
if (this.pending) return this;
if ('function' === typeof title) {
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.enableTimeouts(this.enableTimeouts());
hook.slow(this.slow());
hook.ctx = this.ctx;
this._afterEach.push(hook);
this.emit('afterEach', hook);
return this;
};
/**
* Add a test `suite`.
*
* @param {Suite} suite
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.addSuite = function(suite){
suite.parent = this;
suite.timeout(this.timeout());
suite.enableTimeouts(this.enableTimeouts());
suite.slow(this.slow());
suite.bail(this.bail());
this.suites.push(suite);
this.emit('suite', suite);
return this;
};
/**
* Add a `test` to this suite.
*
* @param {Test} test
* @return {Suite} for chaining
* @api private
*/
Suite.prototype.addTest = function(test){
test.parent = this;
test.timeout(this.timeout());
test.enableTimeouts(this.enableTimeouts());
test.slow(this.slow());
test.ctx = this.ctx;
this.tests.push(test);
this.emit('test', test);
return this;
};
/**
* Return the full title generated by recursively
* concatenating the parent's full title.
*
* @return {String}
* @api public
*/
Suite.prototype.fullTitle = function(){
if (this.parent) {
var full = this.parent.fullTitle();
if (full) return full + ' ' + this.title;
}
return this.title;
};
/**
* Return the total number of tests.
*
* @return {Number}
* @api public
*/
Suite.prototype.total = function(){
return this.suites.reduce(function(sum, suite){
return sum + suite.total();
}, 0) + this.tests.length;
};
/**
* Iterates through each suite recursively to find
* all tests. Applies a function in the format
* `fn(test)`.
*
* @param {Function} fn
* @return {Suite}
* @api private
*/
Suite.prototype.eachTest = function(fn){
this.tests.forEach(fn);
this.suites.forEach(function(suite){
suite.eachTest(fn);
});
return this;
};
}); // module: suite.js
require.register("test.js", function(module, exports, require){
/**
* Module dependencies.
*/
var Runnable = require('./runnable');
/**
* Expose `Test`.
*/
module.exports = Test;
/**
* Initialize a new `Test` with the given `title` and callback `fn`.
*
* @param {String} title
* @param {Function} fn
* @api private
*/
function Test(title, fn) {
Runnable.call(this, title, fn);
this.pending = !fn;
this.type = 'test';
}
/**
* Inherit from `Runnable.prototype`.
*/
function F(){};
F.prototype = Runnable.prototype;
Test.prototype = new F;
Test.prototype.constructor = Test;
}); // module: test.js
require.register("utils.js", function(module, exports, require){
/**
* Module dependencies.
*/
/**
* Escape regular expression characters in `str`.
*
* @param {String} str
* @return {String}
* @api private
*/
exports.escapeRegexp = function(str){
return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};
}); // module: utils.js
/**
* Save timer references to avoid Sinon interfering (see GH-237).
*/
/**
* Node shims.
*
* These are meant only to allow
* mocha.js to run untouched, not
* to allow running node code in
* the browser.
*/
var process = {};
process.exit = function(status){};
process.stdout = {};
var uncaughtExceptionHandlers = [];
var originalOnerrorHandler = window.onerror;
/**
* Remove uncaughtException listener.
* Revert to original onerror handler if previously defined.
*/
process.removeListener = function(e, fn){
if ('uncaughtException' == e) {
if (originalOnerrorHandler) {
window.onerror = originalOnerrorHandler;
} else {
window.onerror = function() {};
}
var i = uncaughtExceptionHandlers.indexOf(fn);
if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); }
}
};
/**
* Implements uncaughtException listener.
*/
process.on = function(e, fn){
if ('uncaughtException' == e) {
window.onerror = function(err, url, line){
fn(new Error(err + ' (' + url + ':' + line + ')'));
return true;
};
uncaughtExceptionHandlers.push(fn);
}
};
/**
* Expose mocha.
*/
var Mocha = window.Mocha = require('mocha'),
mocha = window.mocha = new Mocha();
// The BDD UI is registered by default, but no UI will be functional in the
// browser without an explicit call to the overridden `mocha.ui` (see below).
// Ensure that this default UI does not expose its methods to the global scope.
mocha.suite.removeAllListeners('pre-require');
var immediateQueue = []
, immediateTimeout;
function timeslice() {
var immediateStart = new Date().getTime();
while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) {
immediateQueue.shift()();
}
if (immediateQueue.length) {
immediateTimeout = setTimeout(timeslice, 0);
} else {
immediateTimeout = null;
}
}
/**
* High-performance override of Runner.immediately.
*/
Mocha.Runner.immediately = function(callback) {
immediateQueue.push(callback);
if (!immediateTimeout) {
immediateTimeout = setTimeout(timeslice, 0);
}
};
/**
* 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) {
uncaughtExceptionHandlers.forEach(function (fn) {
fn(err);
});
throw err;
};
/**
* Override ui to ensure that the ui functions are initialized.
* Normally this would happen in Mocha.prototype.loadFiles.
*/
mocha.ui = function(ui){
Mocha.prototype.ui.call(this, ui);
this.suite.emit('pre-require', window, null, this);
return this;
};
/**
* Setup mocha with the given setting options.
*/
mocha.setup = function(opts){
this.ui();
};
/**
* Run mocha, returning the Runner.
*/
mocha.run = function(fn){
return Mocha.prototype.run.call(mocha, function(err){
if (fn) fn(err);
});
};
/**
* Expose the process shim.
*/
Mocha.process = process;
})();
</script>
<script>
mocha.setup();
window.addEventListener('load', function() {
requestAnimationFrame(function() {
mocha.run();
});
})
</script>