Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Update to mocha 1.2.x to allow clickable tests in browser reporter.

  • Loading branch information...
commit 8e66efec3066d8bf002638f0819220f2f1463f4e 1 parent bdabaff
@kmiyashiro kmiyashiro authored
Showing with 622 additions and 149 deletions.
  1. +1 −1  package.json
  2. +49 −3 tests/libs/mocha.css
  3. +572 −145 tests/libs/mocha.js
View
2  package.json
@@ -18,7 +18,7 @@
"expect.js" : "0.1.2"
},
"devDependencies": {
- "mocha" : "1.0.x",
+ "mocha" : "1.2.x",
"requirejs" : "1.0.x"
},
"scripts": {
View
52 tests/libs/mocha.css
@@ -1,9 +1,19 @@
+
body {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 60px 50px;
}
-#mocha h1, h2 {
+#mocha ul, #mocha li {
+ margin: 0;
+ padding: 0;
+}
+
+#mocha ul {
+ list-style: none;
+}
+
+#mocha h1, #mocha h2 {
margin: 0;
}
@@ -13,6 +23,15 @@ body {
font-weight: 200;
}
+#mocha h1 a {
+ text-decoration: none;
+ color: inherit;
+}
+
+#mocha h1 a:hover {
+ text-decoration: underline;
+}
+
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
@@ -47,13 +66,40 @@ body {
font-family: arial;
}
+#mocha .test.pass.medium .duration {
+ background: #C09853;
+}
+
+#mocha .test.pass.slow .duration {
+ background: #B94A48;
+}
+
#mocha .test.pass::before {
content: '';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
- color: #00c41c;
+ color: #00d6b2;
+}
+
+#mocha .test.pass .duration {
+ font-size: 9px;
+ margin-left: 5px;
+ padding: 2px 5px;
+ color: white;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
+}
+
+#mocha .test.pass.fast .duration {
+ display: none;
}
#mocha .test.pending {
@@ -133,4 +179,4 @@ code .comment { color: #ddd }
code .init { color: #2F6FAD }
code .string { color: #5890AD }
code .keyword { color: #8A6343 }
-code .number { color: #2F6FAD }
+code .number { color: #2F6FAD }
View
717 tests/libs/mocha.js
@@ -80,7 +80,7 @@ function isArray(obj) {
/**
* Event emitter constructor.
*
- * @api public.
+ * @api public
*/
function EventEmitter(){};
@@ -188,7 +188,7 @@ EventEmitter.prototype.removeAllListeners = function (name) {
/**
* Gets all listeners for a certain event.
*
- * @api publci
+ * @api public
*/
EventEmitter.prototype.listeners = function (name) {
@@ -407,7 +407,7 @@ module.exports = Context;
function Context(){}
/**
- * Set the context `Runnable` to `runnable`.
+ * Set or get the context `Runnable` to `runnable`.
*
* @param {Runnable} runnable
* @return {Context}
@@ -415,7 +415,8 @@ function Context(){}
*/
Context.prototype.runnable = function(runnable){
- this._runnable = runnable;
+ if (0 == arguments.length) return this._runnable;
+ this.test = this._runnable = runnable;
return this;
};
@@ -428,7 +429,7 @@ Context.prototype.runnable = function(runnable){
*/
Context.prototype.timeout = function(ms){
- this._runnable.timeout(ms);
+ this.runnable().timeout(ms);
return this;
};
@@ -441,9 +442,9 @@ Context.prototype.timeout = function(ms){
Context.prototype.inspect = function(){
return JSON.stringify(this, function(key, val){
- return '_runnable' == key
- ? undefined
- : val;
+ if ('_runnable' == key) return;
+ if ('test' == key) return;
+ return val;
}, 2);
};
@@ -484,6 +485,25 @@ Hook.prototype = new Runnable;
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){
@@ -560,7 +580,7 @@ module.exports = function(suite){
* and/or tests.
*/
- context.describe = function(title, fn){
+ context.describe = context.context = function(title, fn){
var suite = Suite.create(suites[0], title);
suites.unshift(suite);
fn();
@@ -573,7 +593,7 @@ module.exports = function(suite){
* acting as a thunk.
*/
- context.it = function(title, fn){
+ context.it = context.specify = function(title, fn){
suites[0].addTest(new Test(title, fn));
};
});
@@ -847,7 +867,6 @@ module.exports = function(suite){
}); // module: interfaces/tdd.js
require.register("mocha.js", function(module, exports, require){
-
/*!
* mocha
* Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
@@ -867,12 +886,6 @@ var path = require('browser/path');
exports = module.exports = Mocha;
/**
- * Library version.
- */
-
-exports.version = '1.0.1';
-
-/**
* Expose internals.
*/
@@ -908,6 +921,7 @@ function image(name) {
* - `globals` array of accepted globals
* - `timeout` timeout in milliseconds
* - `ignoreLeaks` ignore global leaks
+ * - `grep` string or regexp to filter tests with
*
* @param {Object} options
* @api public
@@ -917,6 +931,7 @@ 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.reporter(options.reporter);
@@ -993,17 +1008,33 @@ Mocha.prototype.growl = function(runner, reporter) {
var stats = reporter.stats;
if (stats.failures) {
var msg = stats.failures + ' of ' + runner.total + ' tests failed';
- notify(msg, { title: 'Failed', image: image('fail') });
+ notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
} else {
notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
- title: 'Passed'
- , image: image('pass')
+ name: 'mocha'
+ , title: 'Passed'
+ , image: image('ok')
});
}
});
};
/**
+ * Add regexp to grep for to the options object
+ *
+ * @param {RegExp} or {String} re
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.grep = function(re){
+ this.options.grep = 'string' == typeof re
+ ? new RegExp(re)
+ : re;
+ return this;
+};
+
+/**
* Run tests and invoke `fn()` when complete.
*
* @param {Function} fn
@@ -1036,6 +1067,16 @@ var tty = require('browser/tty')
, diff = require('browser/diff');
/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
* Check if both stdio streams are associated with a tty.
*/
@@ -1222,7 +1263,7 @@ exports.list = function(failures){
function Base(runner) {
var self = this
- , stats = this.stats = { suites: 0, tests: 0, passes: 0, failures: 0 }
+ , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
, failures = this.failures = [];
if (!runner) return;
@@ -1266,6 +1307,10 @@ function Base(runner) {
stats.end = new Date;
stats.duration = new Date - stats.start;
});
+
+ runner.on('pending', function(){
+ stats.pending++;
+ });
}
/**
@@ -1277,17 +1322,26 @@ function Base(runner) {
Base.prototype.epilogue = function(){
var stats = this.stats
- , fmt;
+ , fmt
+ , tests;
console.log();
+ function pluralize(n) {
+ return 1 == n ? 'test' : 'tests';
+ }
+
// failure
if (stats.failures) {
fmt = color('bright fail', '')
- + color('fail', ' %d of %d tests failed')
+ + color('fail', ' %d of %d %s failed')
+ color('light', ':')
- console.error(fmt, stats.failures, this.runner.total);
+ console.error(fmt,
+ stats.failures,
+ this.runner.total,
+ pluralize(this.runner.total));
+
Base.list(this.failures);
console.error();
return;
@@ -1295,10 +1349,22 @@ Base.prototype.epilogue = function(){
// pass
fmt = color('bright pass', '')
- + color('green', ' %d tests complete')
+ + color('green', ' %d %s complete')
+ color('light', ' (%dms)');
- console.log(fmt, stats.tests || 0, stats.duration);
+ console.log(fmt,
+ stats.tests || 0,
+ pluralize(stats.tests),
+ stats.duration);
+
+ // pending
+ if (stats.pending) {
+ fmt = color('pending', '')
+ + color('pending', ' %d %s pending');
+
+ console.log(fmt, stats.pending, pluralize(stats.pending));
+ }
+
console.log();
};
@@ -1326,6 +1392,7 @@ function pad(str, len) {
function errorDiff(err, type) {
return diff['diff' + type](err.actual, err.expected).map(function(str){
+ if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join('<newline>');
if (str.added) return colorLines('diff added', str.value);
if (str.removed) return colorLines('diff removed', str.value);
return str.value;
@@ -1402,28 +1469,11 @@ function Doc(runner) {
runner.on('pass', function(test){
console.log('%s <dt>%s</dt>', indent(), test.title);
- var code = utils.escape(clean(test.fn.toString()));
+ var code = utils.escape(utils.clean(test.fn.toString()));
console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
});
}
-/**
- * Strip the function definition from `str`,
- * and re-indent for pre whitespace.
- */
-
-function clean(str) {
- str = str
- .replace(/^function *\(.*\) *{/, '')
- .replace(/\s+\}$/, '');
-
- var spaces = str.match(/^\n?( *)/)[1].length
- , re = new RegExp('^ {' + spaces + '}', 'gm');
-
- str = str.replace(re, '');
-
- return str;
-}
}); // module: reporters/doc.js
require.register("reporters/dot.js", function(module, exports, require){
@@ -1532,6 +1582,13 @@ function HTMLCov(runner) {
});
}
+/**
+ * Return coverage class for `n`.
+ *
+ * @return {String}
+ * @api private
+ */
+
function coverageClass(n) {
if (n >= 75) return 'high';
if (n >= 50) return 'medium';
@@ -1552,6 +1609,16 @@ var Base = require('./base')
, escape = utils.escape;
/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
* Expose `Doc`.
*/
@@ -1588,7 +1655,8 @@ function HTML(runner) {
, failures = items[2].getElementsByTagName('em')[0]
, duration = items[3].getElementsByTagName('em')[0]
, canvas = stat.getElementsByTagName('canvas')[0]
- , stack = [root]
+ , report = fragment('<ul id="report"></ul>')
+ , stack = [report]
, progress
, ctx
@@ -1600,6 +1668,7 @@ function HTML(runner) {
if (!root) return error('#mocha div missing, add it to your document');
root.appendChild(stat);
+ root.appendChild(report);
if (progress) progress.size(40);
@@ -1607,11 +1676,12 @@ function HTML(runner) {
if (suite.root) return;
// suite
- var el = fragment('<div class="suite"><h1>%s</h1></div>', suite.title);
+ var url = location.protocol + '//' + location.host + location.pathname + '?grep=^' + utils.escapeRegexp(suite.fullTitle());
+ var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, suite.title);
// container
stack[0].appendChild(el);
- stack.unshift(document.createElement('div'));
+ stack.unshift(document.createElement('ul'));
el.appendChild(stack[0]);
});
@@ -1637,11 +1707,11 @@ function HTML(runner) {
// test
if ('passed' == test.state) {
- var el = fragment('<div class="test pass"><h2>%e</h2></div>', test.title);
+ var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span></h2></li>', test.speed, test.title, test.duration);
} else if (test.pending) {
- var el = fragment('<div class="test pass pending"><h2>%e</h2></div>', test.title);
+ var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
} else {
- var el = fragment('<div class="test fail"><h2>%e</h2></div>', test.title);
+ var el = fragment('<li class="test fail"><h2>%e</h2></li>', test.title);
var str = test.err.stack || test.err.toString();
// FF / Opera do not add the message
@@ -1673,7 +1743,7 @@ function HTML(runner) {
// code
// TODO: defer
if (!test.pending) {
- var pre = fragment('<pre><code>%e</code></pre>', clean(test.fn.toString()));
+ var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));
el.appendChild(pre);
pre.style.display = 'none';
}
@@ -1732,27 +1802,6 @@ function on(el, event, fn) {
el.attachEvent('on' + event, fn);
}
}
-
-/**
- * Strip the function definition from `str`,
- * and re-indent for pre whitespace.
- */
-
-function clean(str) {
- str = str
- .replace(/^function *\(.*\) *{/, '')
- .replace(/\s+\}$/, '');
-
- var spaces = str.match(/^\n?( *)/)[1].length
- , re = new RegExp('^ {' + spaces + '}', 'gm');
-
- str = str
- .replace(re, '')
- .replace(/^\s+/, '');
-
- return str;
-}
-
}); // module: reporters/html.js
require.register("reporters/index.js", function(module, exports, require){
@@ -2239,7 +2288,6 @@ List.prototype.constructor = List;
}); // module: reporters/list.js
require.register("reporters/markdown.js", function(module, exports, require){
-
/**
* Module dependencies.
*/
@@ -2319,9 +2367,9 @@ function Markdown(runner) {
});
runner.on('pass', function(test){
- var code = clean(test.fn.toString());
+ var code = utils.clean(test.fn.toString());
buf += test.title + '.\n';
- buf += '\n```js';
+ buf += '\n```js\n';
buf += code + '\n';
buf += '```\n\n';
});
@@ -2332,24 +2380,6 @@ function Markdown(runner) {
process.stdout.write(buf);
});
}
-
-/**
- * Strip the function definition from `str`,
- * and re-indent for pre whitespace.
- */
-
-function clean(str) {
- str = str
- .replace(/^function *\(.*\) *{/, '')
- .replace(/\s+\}$/, '');
-
- var spaces = str.match(/^\n?( *)/)[1].length
- , re = new RegExp('^ {' + spaces + '}', 'gm');
-
- str = str.replace(re, '');
-
- return str;
-}
}); // module: reporters/markdown.js
require.register("reporters/min.js", function(module, exports, require){
@@ -2394,6 +2424,271 @@ Min.prototype.constructor = Min;
}); // module: reporters/min.js
+require.register("reporters/nyan.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = NyanCat;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function NyanCat(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , width = Base.window.width * .75 | 0
+ , rainbowColors = this.rainbowColors = self.generateColors()
+ , colorIndex = this.colorIndex = 0
+ , numerOfLines = this.numberOfLines = 4
+ , trajectories = this.trajectories = [[], [], [], []]
+ , nyanCatWidth = this.nyanCatWidth = 11
+ , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)
+ , scoreboardWidth = this.scoreboardWidth = 5
+ , tick = this.tick = 0
+ , n = 0;
+
+ runner.on('start', function(){
+ Base.cursor.hide();
+ self.draw('start');
+ });
+
+ runner.on('pending', function(test){
+ self.draw('pending');
+ });
+
+ runner.on('pass', function(test){
+ self.draw('pass');
+ });
+
+ runner.on('fail', function(test, err){
+ self.draw('fail');
+ });
+
+ runner.on('end', function(){
+ Base.cursor.show();
+ for (var i = 0; i < self.numberOfLines; i++) write('\n');
+ self.epilogue();
+ });
+}
+
+/**
+ * Draw the nyan cat with runner `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.draw = function(status){
+ this.appendRainbow();
+ this.drawScoreboard();
+ this.drawRainbow();
+ this.drawNyanCat(status);
+ this.tick = !this.tick;
+};
+
+/**
+ * Draw the "scoreboard" showing the number
+ * of passes, failures and pending tests.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawScoreboard = function(){
+ var stats = this.stats;
+ var colors = Base.colors;
+
+ function draw(color, n) {
+ write(' ');
+ write('\033[' + color + 'm' + n + '\033[0m');
+ write('\n');
+ }
+
+ draw(colors.green, stats.passes);
+ draw(colors.fail, stats.failures);
+ draw(colors.pending, stats.pending);
+ write('\n');
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * 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);
+ }
+};
+
+/**
+ * Draw the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawRainbow = function(){
+ var self = this;
+
+ this.trajectories.forEach(function(line, index) {
+ write('\033[' + self.scoreboardWidth + 'C');
+ write(line.join(''));
+ write('\n');
+ });
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw the nyan cat with `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.drawNyanCat = function(status) {
+ var self = this;
+ var startWidth = this.scoreboardWidth + this.trajectories[0].length;
+
+ [0, 1, 2, 3].forEach(function(index) {
+ write('\033[' + startWidth + 'C');
+
+ switch (index) {
+ case 0:
+ write('_,------,');
+ write('\n');
+ break;
+ case 1:
+ var padding = self.tick ? ' ' : ' ';
+ write('_|' + padding + '/\\_/\\ ');
+ write('\n');
+ break;
+ case 2:
+ var padding = self.tick ? '_' : '__';
+ var tail = self.tick ? '~' : '^';
+ var face;
+ switch (status) {
+ case 'pass':
+ face = '( ^ .^)';
+ break;
+ case 'fail':
+ face = '( o .o)';
+ break;
+ default:
+ face = '( - .-)';
+ }
+ write(tail + '|' + padding + face + ' ');
+ write('\n');
+ break;
+ case 3:
+ var padding = self.tick ? ' ' : ' ';
+ write(padding + '"" "" ');
+ write('\n');
+ break;
+ }
+ });
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Move cursor up `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorUp = function(n) {
+ write('\033[' + n + 'A');
+};
+
+/**
+ * Move cursor down `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorDown = function(n) {
+ write('\033[' + n + 'B');
+};
+
+/**
+ * Generate rainbow colors.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+NyanCat.prototype.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;
+};
+
+/**
+ * Apply rainbow to the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+NyanCat.prototype.rainbowify = function(str){
+ var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
+ this.colorIndex += 1;
+ return '\033[38;5;' + color + 'm' + str + '\033[0m';
+};
+
+/**
+ * Stdout helper.
+ */
+
+function write(string) {
+ process.stdout.write(string);
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+NyanCat.prototype = new Base;
+NyanCat.prototype.constructor = NyanCat;
+
+
+}); // module: reporters/nyan.js
+
require.register("reporters/progress.js", function(module, exports, require){
/**
@@ -2450,8 +2745,9 @@ function Progress(runner, options) {
// tests complete
runner.on('test end', function(){
+ complete++;
var incomplete = total - complete
- , percent = complete++ / total
+ , percent = complete / total
, n = width * percent | 0
, i = width - n;
@@ -2675,23 +2971,23 @@ function Teamcity(runner) {
});
runner.on('test', function(test) {
- console.log("##teamcity[testStarted name='%s']", escape(test.fullTitle()));
+ console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
});
runner.on('fail', function(test, err) {
- console.log("##teamcity[testFailed name='%s' message='%s']", escape(test.fullTitle()), escape(err.message));
+ console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
});
runner.on('pending', function(test) {
- console.log("##teamcity[testIgnored name='%s' message='pending']", escape(test.fullTitle()));
+ console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
});
runner.on('test end', function(test) {
- console.log("##teamcity[testFinished name='%s' duration='%s']", escape(test.fullTitle()), test.duration);
+ console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
});
runner.on('end', function() {
- console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']", stats.duration);
+ console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
});
}
@@ -2700,8 +2996,18 @@ function Teamcity(runner) {
*/
function escape(str) {
- return str.replace(/'/g, "|'");
+ return str
+ .replace(/\|/g, "||")
+ .replace(/\n/g, "|n")
+ .replace(/\r/g, "|r")
+ .replace(/\[/g, "|[")
+ .replace(/\]/g, "|]")
+ .replace(/\u0085/g, "|x")
+ .replace(/\u2028/g, "|l")
+ .replace(/\u2029/g, "|p")
+ .replace(/'/g, "|'");
}
+
}); // module: reporters/teamcity.js
require.register("reporters/xunit.js", function(module, exports, require){
@@ -2715,6 +3021,16 @@ var Base = require('./base')
, escape = utils.escape;
/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
* Expose `XUnit`.
*/
@@ -2821,6 +3137,16 @@ var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('runnable');
/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
* Expose `Runnable`.
*/
@@ -2890,6 +3216,22 @@ Runnable.prototype.clearTimeout = function(){
};
/**
+ * 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
@@ -2991,6 +3333,8 @@ var EventEmitter = require('browser/events').EventEmitter
, debug = require('browser/debug')('runner')
, Test = require('./test')
, utils = require('./utils')
+ , filter = utils.filter
+ , keys = utils.keys
, noop = function(){};
/**
@@ -3039,7 +3383,8 @@ Runner.prototype.constructor = Runner;
/**
- * Run tests with full titles matching `re`.
+ * Run tests with full titles matching `re`. Updates runner.total
+ * with number of tests matched.
*
* @param {RegExp} re
* @return {Runner} for chaining
@@ -3049,10 +3394,31 @@ Runner.prototype.constructor = Runner;
Runner.prototype.grep = function(re){
debug('grep %s', re);
this._grep = re;
+ 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){
+ if (self._grep.test(test.fullTitle())) total++;
+ });
+
+ return total;
+};
+
+/**
* Allow the given `arr` of globals.
*
* @param {Array} arr
@@ -3077,10 +3443,7 @@ Runner.prototype.globals = function(arr){
Runner.prototype.checkGlobals = function(test){
if (this.ignoreLeaks) return;
-
- var leaks = utils.filter(utils.keys(global), function(key){
- return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key);
- }, this);
+ var leaks = filterLeaks(this._globals);
this._globals = this._globals.concat(leaks);
@@ -3102,6 +3465,9 @@ Runner.prototype.checkGlobals = function(test){
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);
};
@@ -3151,6 +3517,8 @@ Runner.prototype.hook = function(name, fn){
hook.run(function(err){
hook.removeAllListeners('error');
+ var testError = hook.error();
+ if (testError) self.fail(self.test, testError);
if (err) return self.failHook(hook, err);
self.emit('hook end', hook);
next(++i);
@@ -3328,10 +3696,14 @@ Runner.prototype.runTests = function(suite, fn){
*/
Runner.prototype.runSuite = function(suite, fn){
- var self = this
+ 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() {
@@ -3394,10 +3766,15 @@ Runner.prototype.run = function(fn){
debug('start');
+ // uncaught callback
+ function uncaught(err) {
+ self.uncaught(err);
+ }
+
// callback
this.on('end', function(){
debug('end');
- process.removeListener('uncaughtException', this.uncaught);
+ process.removeListener('uncaughtException', uncaught);
fn(self.failures);
});
@@ -3409,13 +3786,28 @@ Runner.prototype.run = function(fn){
});
// uncaught exception
- process.on('uncaughtException', function(err){
- self.uncaught(err);
- });
+ process.on('uncaughtException', uncaught);
return this;
};
+/**
+ * Filter leaks with the given globals flagged as `ok`.
+ *
+ * @param {Array} ok
+ * @return {Array}
+ * @api private
+ */
+
+function filterLeaks(ok) {
+ return filter(keys(global), function(key){
+ var matched = filter(ok, function(ok){
+ if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
+ return key == ok;
+ });
+ return matched.length == 0 && (!global.navigator || 'onerror' !== key);
+ });
+}
}); // module: runner.js
require.register("suite.js", function(module, exports, require){
@@ -3669,6 +4061,24 @@ Suite.prototype.total = function(){
}, 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){
+ utils.forEach(this.tests, fn);
+ utils.forEach(this.suites, function(suite){
+ suite.eachTest(fn);
+ });
+ return this;
+};
+
}); // module: suite.js
require.register("test.js", function(module, exports, require){
@@ -3707,22 +4117,6 @@ Test.prototype = new Runnable;
Test.prototype.constructor = Test;
-/**
- * Inspect the context void of private properties.
- *
- * @return {String}
- * @api private
- */
-
-Test.prototype.inspect = function(){
- return JSON.stringify(this, function(key, val){
- return '_' == key[0]
- ? undefined
- : 'parent' == key
- ? '#<Suite>'
- : val;
- }, 2);
-};
}); // module: test.js
require.register("utils.js", function(module, exports, require){
@@ -3907,6 +4301,7 @@ exports.files = function(dir, ret){
*
* @param {String} str
* @return {String}
+ * @api private
*/
exports.slug = function(str){
@@ -3915,6 +4310,36 @@ exports.slug = function(str){
.replace(/ +/g, '-')
.replace(/[^-\w]/g, '');
};
+
+/**
+ * Strip the function definition from `str`,
+ * and re-indent for pre whitespace.
+ */
+
+exports.clean = function(str) {
+ str = str
+ .replace(/^function *\(.*\) *{/, '')
+ .replace(/\s+\}$/, '');
+
+ var spaces = str.match(/^\n?( *)/)[1].length
+ , re = new RegExp('^ {' + spaces + '}', 'gm');
+
+ str = str.replace(re, '');
+
+ return str.trim();
+};
+
+/**
+ * Escape regular expression characters in `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.escapeRegexp = function(str){
+ return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
+};
}); // module: utils.js
/**
* Node shims.
@@ -3945,15 +4370,16 @@ process.nextTick = (function(){
var timeouts = []
, name = 'mocha-zero-timeout'
+ window.addEventListener('message', function(e){
+ if (e.source == window && e.data == name) {
+ if (e.stopPropagation) e.stopPropagation();
+ if (timeouts.length) timeouts.shift()();
+ }
+ }, true);
+
return function(fn){
timeouts.push(fn);
window.postMessage(name, '*');
- window.addEventListener('message', function(e){
- if (e.source == window && e.data == name) {
- if (e.stopPropagation) e.stopPropagation();
- if (timeouts.length) timeouts.shift()();
- }
- }, true);
}
})();
@@ -3985,10 +4411,11 @@ window.mocha = require('mocha');
// boot
;(function(){
- var suite = new mocha.Suite('', new mocha.Context)
- , utils = mocha.utils
+ var utils = mocha.utils
, options = {}
+ mocha.suite = new mocha.Suite('', new mocha.Context());
+
/**
* Highlight the given string of `js`.
*/
@@ -4022,13 +4449,13 @@ window.mocha = require('mocha');
function parse(qs) {
return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
- var i = pair.indexOf('=')
- , key = pair.slice(0, i)
- , val = pair.slice(++i);
+ var i = pair.indexOf('=')
+ , key = pair.slice(0, i)
+ , val = pair.slice(++i);
- obj[key] = decodeURIComponent(val);
- return obj;
- }, {});
+ obj[key] = decodeURIComponent(val);
+ return obj;
+ }, {});
}
/**
@@ -4041,9 +4468,9 @@ window.mocha = require('mocha');
ui = mocha.interfaces[options.ui];
if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
- if (options.timeout) suite.timeout(options.timeout);
- ui(suite);
- suite.emit('pre-require', window);
+ if (options.timeout) mocha.suite.timeout(options.timeout);
+ ui(mocha.suite);
+ mocha.suite.emit('pre-require', window);
};
/**
@@ -4051,8 +4478,8 @@ window.mocha = require('mocha');
*/
mocha.run = function(fn){
- suite.emit('run');
- var runner = new mocha.Runner(suite);
+ mocha.suite.emit('run');
+ var runner = new mocha.Runner(mocha.suite);
var Reporter = options.reporter || mocha.reporters.HTML;
var reporter = new Reporter(runner);
var query = parse(window.location.search || "");
Please sign in to comment.
Something went wrong with that request. Please try again.