[Pkg-javascript-commits] [node-mocha] 03/12: Imported Upstream version 1.21.5

Leo Iannacone l3on-guest at moszumanska.debian.org
Wed Oct 15 18:03:13 UTC 2014


This is an automated email from the git hooks/post-receive script.

l3on-guest pushed a commit to branch master
in repository node-mocha.

commit ef62083a0dff9d331e3582aaf23e2225a0234c4c
Author: Leo Iannacone <l3on at ubuntu.com>
Date:   Sun Oct 12 16:46:22 2014 +0200

    Imported Upstream version 1.21.5
---
 .travis.yml                           |   3 +-
 History.md                            |  23 ++++
 Makefile                              |  21 ++-
 bin/_mocha                            |  45 +-----
 bower.json                            |   2 +-
 component.json                        |   2 +-
 lib/browser/escape-string-regexp.js   |  11 ++
 lib/browser/glob.js                   |   0
 lib/interfaces/bdd.js                 |   7 +-
 lib/interfaces/exports.js             |   2 +-
 lib/interfaces/qunit.js               |   3 +-
 lib/interfaces/tdd.js                 |   7 +-
 lib/mocha.js                          |  13 +-
 lib/ms.js                             |   2 +-
 lib/reporters/base.js                 |   2 +-
 lib/reporters/json-cov.js             |   2 +-
 lib/reporters/json.js                 |   8 +-
 lib/reporters/nyan.js                 |   2 +-
 lib/reporters/templates/coverage.jade |   3 +-
 lib/runnable.js                       |   1 +
 lib/runner.js                         |  21 ++-
 lib/suite.js                          |   3 +-
 lib/utils.js                          | 116 ++++++++++------
 mocha.js                              | 252 ++++++++++++++++++++++++----------
 package.json                          |  17 +--
 support/compile.js                    |  14 +-
 support/tail.js                       |   3 +-
 test/acceptance/timeout.js            |  49 ++++++-
 test/acceptance/utils.js              |  31 +++++
 test/regression/issue1327/case.js     |  14 ++
 test/regression/issue1327/control.js  |  10 ++
 test/reporters/base.js                |  68 +++++++++
 test/reporters/json.js                |  19 +++
 test/runnable.js                      |  14 ++
 34 files changed, 594 insertions(+), 196 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 51f9bdd..ed05f88 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
 language: node_js
 node_js:
   - "0.11"
-  - "0.8"
   - "0.10"
+  - "0.8"
+  - "0.6"
diff --git a/History.md b/History.md
index 358f45f..9a63be6 100644
--- a/History.md
+++ b/History.md
@@ -1,3 +1,26 @@
+
+1.21.5 / 2014-10-11
+==================
+
+ * fix: build for NodeJS v0.6.x
+ * fix: do not attempt to highlight syntax when non-HTML reporter is used
+ * update: escape-string-regexp to 1.0.2.
+ * fix: botched indentation in canonicalize()
+ * fix: .gitignore: ignore .patch and .diff files
+ * fix: changed 'Catched' to 'Caught' in uncaught exception error handler messages
+ * add: `pending` field for json reporter
+ * fix: Runner.prototype.uncaught: don't double-end runnables that already have a state.
+ * fix: --recursive, broken by f0facd2e
+ * update: replaces escapeRegexp with the escape-string-regexp package.
+ * update: commander to 2.3.0.
+ * update: diff to 1.0.8.
+ * fix: ability to disable syntax highlighting (#1329)
+ * fix: added empty object to errorJSON() call to catch when no error is present
+ * fix: never time out after calling enableTimeouts(false)
+ * fix: timeout(0) will work at suite level (#1300) 
+ * Fix for --watch+only() issue (#888 )
+ * fix: respect err.showDiff, add Base reporter test (#810)
+
 1.22.1-3 / 2014-07-27
 ==================
 
diff --git a/Makefile b/Makefile
index 77efec7..72c4814 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 
-REPORTER ?= dot
+REPORTER ?= spec
 TM_BUNDLE = JavaScript\ mocha.tmbundle
 SRC = $(shell find lib -name "*.js" -type f | sort)
 SUPPORT = $(wildcard support/*.js)
@@ -9,7 +9,10 @@ all: mocha.js
 lib/browser/diff.js: node_modules/diff/diff.js
 	cp node_modules/diff/diff.js lib/browser/diff.js
 
-mocha.js: $(SRC) $(SUPPORT) lib/browser/diff.js
+lib/browser/escape-string-regexp.js: node_modules/escape-string-regexp/index.js
+	cp node_modules/escape-string-regexp/index.js lib/browser/escape-string-regexp.js
+
+mocha.js: $(SRC) $(SUPPORT) lib/browser/diff.js lib/browser/escape-string-regexp.js
 	@node support/compile $(SRC)
 	@cat \
 	  support/head.js \
@@ -20,6 +23,7 @@ mocha.js: $(SRC) $(SUPPORT) lib/browser/diff.js
 
 clean:
 	rm -f mocha.js
+	rm -rf test-outputs
 	rm -fr lib-cov
 	rm -f coverage.html
 
@@ -32,7 +36,7 @@ lib-cov:
 
 test: test-unit
 
-test-all: test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only test-failing
+test-all: test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only test-failing test-regression
 
 test-jsapi:
 	@node test/jsapi
@@ -44,9 +48,18 @@ test-unit:
 		--growl \
 		test/*.js
 
-test-failing:
+test-regression: test-outputs/issue1327/case-out.json
 	@./bin/mocha \
 		--reporter $(REPORTER) \
+		test/regression/issue*/control.js
+
+test-outputs/issue1327/case-out.json: test/regression/issue1327/case.js
+	@mkdir -p $(dir $@) || true
+	@./bin/mocha --reporter json $< > $@ || true
+
+test-failing:
+	./bin/mocha \
+		--reporter $(REPORTER) \
 		test/acceptance/failing/timeout.js > /dev/null 2>&1 ; \
 		failures="$$?" ; \
 		if [ "$$failures" != '2' ] ; then \
diff --git a/bin/_mocha b/bin/_mocha
index 7c39c6c..3032690 100755
--- a/bin/_mocha
+++ b/bin/_mocha
@@ -284,25 +284,22 @@ program.compilers.forEach(function(c) {
   extensions.push(ext);
 });
 
-var re = new RegExp('\\.(' + extensions.join('|') + ')$');
-
 // requires
 
 requires.forEach(function(mod) {
   require(mod);
 });
 
-// files
+//args
 
-var files = []
-  , args = program.args;
+var args = program.args;
 
 // default files to test/*.{js,coffee}
 
 if (!args.length) args.push('test');
 
 args.forEach(function(arg){
-  files = files.concat(lookupFiles(arg, program.recursive));
+  files = files.concat(utils.lookupFiles(arg, extensions, program.recursive));
 });
 
 // resolve
@@ -357,6 +354,8 @@ if (program.watch) {
   function rerun() {
     purge();
     stop()
+    if (!program.grep)
+      mocha.grep(null);
     mocha.suite = mocha.suite.clone();
     mocha.suite.ctx = new Mocha.Context;
     mocha.ui(program.ui);
@@ -440,40 +439,6 @@ function stop() {
 }
 
 /**
- * Lookup file names at the given `path`.
- */
-
-function lookupFiles(path, recursive) {
-  var files = [];
-
-  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;
-    }
-  }
-
-  var stat = fs.statSync(path);
-  if (stat.isFile()) return path;
-
-  fs.readdirSync(path).forEach(function(file){
-    file = join(path, file);
-    var stat = fs.statSync(file);
-    if (stat.isDirectory()) {
-      if (recursive) files = files.concat(lookupFiles(file, recursive));
-      return
-    }
-    if (!stat.isFile() || !re.test(file) || basename(file)[0] == '.') return;
-    files.push(file);
-  });
-
-  return files;
-}
-
-/**
  * Play the given array of strings.
  */
 
diff --git a/bower.json b/bower.json
index 0305ec8..839191b 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "mocha",
-  "version": "1.21.4",
+  "version": "1.21.5",
   "main": [
     "mocha.js",
     "mocha.css"
diff --git a/component.json b/component.json
index 8ad5826..eb7cdb8 100644
--- a/component.json
+++ b/component.json
@@ -1,6 +1,6 @@
 {
   "name": "mocha",
-  "version": "1.21.4",
+  "version": "1.21.5",
   "repo": "visionmedia/mocha",
   "description": "simple, flexible, fun test framework",
   "keywords": [
diff --git a/lib/browser/escape-string-regexp.js b/lib/browser/escape-string-regexp.js
new file mode 100644
index 0000000..ac6572c
--- /dev/null
+++ b/lib/browser/escape-string-regexp.js
@@ -0,0 +1,11 @@
+'use strict';
+
+var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
+
+module.exports = function (str) {
+	if (typeof str !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	return str.replace(matchOperatorsRe,  '\\$&');
+};
diff --git a/lib/browser/glob.js b/lib/browser/glob.js
new file mode 100644
index 0000000..e69de29
diff --git a/lib/interfaces/bdd.js b/lib/interfaces/bdd.js
index ebf6f0f..ac16d72 100644
--- a/lib/interfaces/bdd.js
+++ b/lib/interfaces/bdd.js
@@ -5,7 +5,8 @@
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');
+  , utils = require('../utils')
+  , escapeRe = require('escape-string-regexp');
 
 /**
  * BDD-style interface:
@@ -108,7 +109,7 @@ module.exports = function(suite){
 
     context.it = context.specify = function(title, fn){
       var suite = suites[0];
-      if (suite.pending) var fn = null;
+      if (suite.pending) fn = null;
       var test = new Test(title, fn);
       test.file = file;
       suite.addTest(test);
@@ -121,7 +122,7 @@ module.exports = function(suite){
 
     context.it.only = function(title, fn){
       var test = context.it(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
       return test;
     };
diff --git a/lib/interfaces/exports.js b/lib/interfaces/exports.js
index d933274..cedb905 100644
--- a/lib/interfaces/exports.js
+++ b/lib/interfaces/exports.js
@@ -52,7 +52,7 @@ module.exports = function(suite){
             suites[0].addTest(test);
         }
       } else {
-        var suite = Suite.create(suites[0], key);
+        suite = Suite.create(suites[0], key);
         suites.unshift(suite);
         visit(obj[key]);
         suites.shift();
diff --git a/lib/interfaces/qunit.js b/lib/interfaces/qunit.js
index 02d5007..0a22641 100644
--- a/lib/interfaces/qunit.js
+++ b/lib/interfaces/qunit.js
@@ -5,6 +5,7 @@
 
 var Suite = require('../suite')
   , Test = require('../test')
+  , escapeRe = require('escape-string-regexp')
   , utils = require('../utils');
 
 /**
@@ -109,7 +110,7 @@ module.exports = function(suite){
 
     context.test.only = function(title, fn){
       var test = context.test(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
     };
 
diff --git a/lib/interfaces/tdd.js b/lib/interfaces/tdd.js
index 6d0c3d6..dc43e41 100644
--- a/lib/interfaces/tdd.js
+++ b/lib/interfaces/tdd.js
@@ -5,7 +5,8 @@
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');;
+  , escapeRe = require('escape-string-regexp')
+  , utils = require('../utils');
 
 /**
  * TDD-style interface:
@@ -112,7 +113,7 @@ module.exports = function(suite){
 
     context.test = function(title, fn){
       var suite = suites[0];
-      if (suite.pending) var fn = null;
+      if (suite.pending) fn = null;
       var test = new Test(title, fn);
       test.file = file;
       suite.addTest(test);
@@ -125,7 +126,7 @@ module.exports = function(suite){
 
     context.test.only = function(title, fn){
       var test = context.test(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
     };
 
diff --git a/lib/mocha.js b/lib/mocha.js
index 8e57487..73bdaf9 100644
--- a/lib/mocha.js
+++ b/lib/mocha.js
@@ -9,6 +9,7 @@
  */
 
 var path = require('path')
+  , escapeRe = require('escape-string-regexp')
   , utils = require('./utils');
 
 /**
@@ -220,7 +221,7 @@ Mocha.prototype._growl = function(runner, reporter) {
 
 Mocha.prototype.grep = function(re){
   this.options.grep = 'string' == typeof re
-    ? new RegExp(utils.escapeRegexp(re))
+    ? new RegExp(escapeRe(re))
     : re;
   return this;
 };
@@ -371,6 +372,16 @@ Mocha.prototype.asyncOnly = function(){
 };
 
 /**
+ * Disable syntax highlighting (in browser).
+ * @returns {Mocha}
+ * @api public
+ */
+Mocha.prototype.noHighlighting = function() {
+  this.options.noHighlighting = true;
+  return this;
+};
+
+/**
  * Run tests and invoke `fn()` when complete.
  *
  * @param {Function} fn
diff --git a/lib/ms.js b/lib/ms.js
index 4096637..ba451fa 100644
--- a/lib/ms.js
+++ b/lib/ms.js
@@ -24,7 +24,7 @@ var y = d * 365.25;
 module.exports = function(val, options){
   options = options || {};
   if ('string' == typeof val) return parse(val);
-  return options.long ? longFormat(val) : shortFormat(val);
+  return options['long'] ? longFormat(val) : shortFormat(val);
 };
 
 /**
diff --git a/lib/reporters/base.js b/lib/reporters/base.js
index 2690fa1..00c94de 100644
--- a/lib/reporters/base.js
+++ b/lib/reporters/base.js
@@ -185,7 +185,7 @@ exports.list = function(failures){
     }
 
     // actual / expected diff
-    if ('string' == typeof actual && 'string' == typeof expected) {
+    if (err.showDiff && 'string' == typeof actual && 'string' == typeof 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);
diff --git a/lib/reporters/json-cov.js b/lib/reporters/json-cov.js
index 73d0009..83e57f4 100644
--- a/lib/reporters/json-cov.js
+++ b/lib/reporters/json-cov.js
@@ -89,7 +89,7 @@ function map(cov) {
   }
 
   return ret;
-};
+}
 
 /**
  * Map jscoverage data for a single source file
diff --git a/lib/reporters/json.js b/lib/reporters/json.js
index d037120..4ec9e12 100644
--- a/lib/reporters/json.js
+++ b/lib/reporters/json.js
@@ -25,6 +25,7 @@ function JSONReporter(runner) {
   Base.call(this, runner);
 
   var tests = []
+    , pending = []
     , failures = []
     , passes = [];
 
@@ -40,10 +41,15 @@ function JSONReporter(runner) {
     failures.push(test);
   });
 
+  runner.on('pending', function(test){
+    pending.push(test);
+  });
+
   runner.on('end', function(){
     var obj = {
       stats: self.stats,
       tests: tests.map(clean),
+      pending: pending.map(clean),
       failures: failures.map(clean),
       passes: passes.map(clean)
     };
@@ -68,7 +74,7 @@ function clean(test) {
     title: test.title,
     fullTitle: test.fullTitle(),
     duration: test.duration,
-    err: errorJSON(test.err)
+    err: errorJSON(test.err || {})
   }
 }
 
diff --git a/lib/reporters/nyan.js b/lib/reporters/nyan.js
index 4501f6b..a8d43bf 100644
--- a/lib/reporters/nyan.js
+++ b/lib/reporters/nyan.js
@@ -185,7 +185,7 @@ NyanCat.prototype.face = function() {
   } else {
     return '( - .-)';
   }
-}
+};
 
 /**
  * Move cursor up `n`.
diff --git a/lib/reporters/templates/coverage.jade b/lib/reporters/templates/coverage.jade
index b78119f..edd59d8 100644
--- a/lib/reporters/templates/coverage.jade
+++ b/lib/reporters/templates/coverage.jade
@@ -1,7 +1,8 @@
-!!! 5
+doctype html
 html
   head
     title Coverage
+    meta(charset='utf-8')
     include script.html
     include style.html
   body
diff --git a/lib/runnable.js b/lib/runnable.js
index 2696293..9409007 100644
--- a/lib/runnable.js
+++ b/lib/runnable.js
@@ -154,6 +154,7 @@ Runnable.prototype.resetTimeout = function(){
   if (!this._enableTimeouts) return;
   this.clearTimeout();
   this.timer = setTimeout(function(){
+    if (!self._enableTimeouts) return;
     self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
     self.timedOut = true;
   }, ms);
diff --git a/lib/runner.js b/lib/runner.js
index 61fc27a..b5a6d49 100644
--- a/lib/runner.js
+++ b/lib/runner.js
@@ -533,18 +533,25 @@ Runner.prototype.runSuite = function(suite, fn){
 
 Runner.prototype.uncaught = function(err){
   if (err) {
-    debug('uncaught exception %s', err.message);
+    debug('uncaught exception %s', err !== function () {
+      return this;
+    }.call(err) ? err : ( err.message || err ));
   } else {
     debug('uncaught undefined exception');
-    err = new Error('Catched undefined error, did you throw without specifying what?');
+    err = new Error('Caught undefined error, did you throw without specifying what?');
   }
-  
-  var runnable = this.currentRunnable;
-  if (!runnable || 'failed' == runnable.state) return;
-  runnable.clearTimeout();
   err.uncaught = true;
+
+  var runnable = this.currentRunnable;
+  if (!runnable) return;
+
+  var wasAlreadyDone = runnable.state;
   this.fail(runnable, err);
 
+  runnable.clearTimeout();
+
+  if (wasAlreadyDone) return;
+
   // recover from test
   if ('test' == runnable.type) {
     this.emit('test end', runnable);
@@ -604,7 +611,7 @@ Runner.prototype.run = function(fn){
 Runner.prototype.abort = function(){
   debug('aborting');
   this._abort = true;
-}
+};
 
 /**
  * Filter leaks with the given globals flagged as `ok`.
diff --git a/lib/suite.js b/lib/suite.js
index ee5983e..e8696f4 100644
--- a/lib/suite.js
+++ b/lib/suite.js
@@ -99,6 +99,7 @@ Suite.prototype.clone = function(){
 
 Suite.prototype.timeout = function(ms){
   if (0 == arguments.length) return this._timeout;
+  if (ms === 0) this._enableTimeouts = false;
   if ('string' == typeof ms) ms = milliseconds(ms);
   debug('timeout %d', ms);
   this._timeout = parseInt(ms, 10);
@@ -118,7 +119,7 @@ Suite.prototype.enableTimeouts = function(enabled){
   debug('enableTimeouts %s', enabled);
   this._enableTimeouts = enabled;
   return this;
-}
+};
 
 /**
  * Set slow `ms` or short-hand such as "2s".
diff --git a/lib/utils.js b/lib/utils.js
index bd84083..ecc0a14 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -4,6 +4,9 @@
 
 var fs = require('fs')
   , path = require('path')
+  , basename = path.basename
+  , exists = fs.existsSync || path.existsSync
+  , glob = require('glob')
   , join = path.join
   , debug = require('debug')('mocha:watch');
 
@@ -225,18 +228,6 @@ exports.clean = function(str) {
 };
 
 /**
- * Escape regular expression characters in `str`.
- *
- * @param {String} str
- * @return {String}
- * @api private
- */
-
-exports.escapeRegexp = function(str){
-  return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
-};
-
-/**
  * Trim the given `str`.
  *
  * @param {String} str
@@ -295,7 +286,7 @@ function highlight(js) {
  */
 
 exports.highlightTags = function(name) {
-  var code = document.getElementsByTagName(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);
   }
@@ -313,38 +304,85 @@ exports.highlightTags = function(name) {
 exports.stringify = function(obj) {
   if (obj instanceof RegExp) return obj.toString();
   return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
-}
+};
 
 /**
  * Return a new object that has the keys in sorted order.
  * @param {Object} obj
+ * @param {Array} [stack]
  * @return {Object}
  * @api private
  */
 
 exports.canonicalize = function(obj, stack) {
-   stack = stack || [];
-
-   if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
-
-   var canonicalizedObj;
-
-   if ({}.toString.call(obj) === '[object Array]') {
-     stack.push(obj);
-     canonicalizedObj = exports.map(obj, function(item) {
-       return exports.canonicalize(item, stack);
-     });
-     stack.pop();
-   } else if (typeof obj === 'object' && obj !== null) {
-     stack.push(obj);
-     canonicalizedObj = {};
-     exports.forEach(exports.keys(obj).sort(), function(key) {
-       canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
-     });
-     stack.pop();
-   } else {
-     canonicalizedObj = obj;
-   }
-
-   return canonicalizedObj;
- }
+  stack = stack || [];
+
+  if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
+
+  var canonicalizedObj;
+
+  if ({}.toString.call(obj) === '[object Array]') {
+    stack.push(obj);
+    canonicalizedObj = exports.map(obj, function (item) {
+      return exports.canonicalize(item, stack);
+    });
+    stack.pop();
+  } else if (typeof obj === 'object' && obj !== null) {
+    stack.push(obj);
+    canonicalizedObj = {};
+    exports.forEach(exports.keys(obj).sort(), function (key) {
+      canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
+    });
+    stack.pop();
+  } else {
+    canonicalizedObj = obj;
+  }
+
+  return canonicalizedObj;
+ };
+
+/**
+ * Lookup file names at the given `path`.
+ */
+exports.lookupFiles = 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 = fs.statSync(path);
+    if (stat.isFile()) return path;
+  }
+  catch (ignored) {
+    return;
+  }
+
+  fs.readdirSync(path).forEach(function(file){
+    file = join(path, file);
+    try {
+      var stat = fs.statSync(file);
+      if (stat.isDirectory()) {
+        if (recursive) {
+          files = files.concat(lookupFiles(file, extensions, recursive));
+        }
+        return;
+      }
+    }
+    catch (ignored) {
+      return;
+    }
+    if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return;
+    files.push(file);
+  });
+
+  return files;
+};
diff --git a/mocha.js b/mocha.js
index 079aa58..e8bee79 100644
--- a/mocha.js
+++ b/mocha.js
@@ -224,7 +224,22 @@ var JsDiff = (function() {
 
   var LineDiff = new Diff();
   LineDiff.tokenize = function(value) {
-    return value.split(/^/m);
+    var retLines = [],
+        lines = value.split(/^/m);
+
+    for(var i = 0; i < lines.length; i++) {
+      var line = lines[i],
+          lastLine = lines[i - 1];
+
+      // Merge lines that may contain windows new lines
+      if (line == '\n' && lastLine && lastLine[lastLine.length - 1] === '\r') {
+        retLines[retLines.length - 1] += '\n';
+      } else if (line) {
+        retLines.push(line);
+      }
+    }
+
+    return retLines;
   };
 
   return {
@@ -414,6 +429,21 @@ if (typeof module !== 'undefined') {
 
 }); // module: browser/diff.js
 
+require.register("browser/escape-string-regexp.js", function(module, exports, require){
+'use strict';
+
+var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
+
+module.exports = function (str) {
+	if (typeof str !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	return str.replace(matchOperatorsRe,  '\\$&');
+};
+
+}); // module: browser/escape-string-regexp.js
+
 require.register("browser/events.js", function(module, exports, require){
 
 /**
@@ -599,6 +629,10 @@ require.register("browser/fs.js", function(module, exports, require){
 
 }); // module: browser/fs.js
 
+require.register("browser/glob.js", function(module, exports, require){
+
+}); // module: browser/glob.js
+
 require.register("browser/path.js", function(module, exports, require){
 
 }); // module: browser/path.js
@@ -902,7 +936,8 @@ require.register("interfaces/bdd.js", function(module, exports, require){
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');
+  , utils = require('../utils')
+  , escapeRe = require('browser/escape-string-regexp');
 
 /**
  * BDD-style interface:
@@ -1005,7 +1040,7 @@ module.exports = function(suite){
 
     context.it = context.specify = function(title, fn){
       var suite = suites[0];
-      if (suite.pending) var fn = null;
+      if (suite.pending) fn = null;
       var test = new Test(title, fn);
       test.file = file;
       suite.addTest(test);
@@ -1018,7 +1053,7 @@ module.exports = function(suite){
 
     context.it.only = function(title, fn){
       var test = context.it(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
       return test;
     };
@@ -1092,7 +1127,7 @@ module.exports = function(suite){
             suites[0].addTest(test);
         }
       } else {
-        var suite = Suite.create(suites[0], key);
+        suite = Suite.create(suites[0], key);
         suites.unshift(suite);
         visit(obj[key]);
         suites.shift();
@@ -1120,6 +1155,7 @@ require.register("interfaces/qunit.js", function(module, exports, require){
 
 var Suite = require('../suite')
   , Test = require('../test')
+  , escapeRe = require('browser/escape-string-regexp')
   , utils = require('../utils');
 
 /**
@@ -1224,7 +1260,7 @@ module.exports = function(suite){
 
     context.test.only = function(title, fn){
       var test = context.test(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
     };
 
@@ -1248,7 +1284,8 @@ require.register("interfaces/tdd.js", function(module, exports, require){
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');;
+  , escapeRe = require('browser/escape-string-regexp')
+  , utils = require('../utils');
 
 /**
  * TDD-style interface:
@@ -1355,7 +1392,7 @@ module.exports = function(suite){
 
     context.test = function(title, fn){
       var suite = suites[0];
-      if (suite.pending) var fn = null;
+      if (suite.pending) fn = null;
       var test = new Test(title, fn);
       test.file = file;
       suite.addTest(test);
@@ -1368,7 +1405,7 @@ module.exports = function(suite){
 
     context.test.only = function(title, fn){
       var test = context.test(title, fn);
-      var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$';
+      var reString = '^' + escapeRe(test.fullTitle()) + '$';
       mocha.grep(new RegExp(reString));
     };
 
@@ -1396,6 +1433,7 @@ require.register("mocha.js", function(module, exports, require){
  */
 
 var path = require('browser/path')
+  , escapeRe = require('browser/escape-string-regexp')
   , utils = require('./utils');
 
 /**
@@ -1607,7 +1645,7 @@ Mocha.prototype._growl = function(runner, reporter) {
 
 Mocha.prototype.grep = function(re){
   this.options.grep = 'string' == typeof re
-    ? new RegExp(utils.escapeRegexp(re))
+    ? new RegExp(escapeRe(re))
     : re;
   return this;
 };
@@ -1758,6 +1796,16 @@ Mocha.prototype.asyncOnly = function(){
 };
 
 /**
+ * Disable syntax highlighting (in browser).
+ * @returns {Mocha}
+ * @api public
+ */
+Mocha.prototype.noHighlighting = function() {
+  this.options.noHighlighting = true;
+  return this;
+};
+
+/**
  * Run tests and invoke `fn()` when complete.
  *
  * @param {Function} fn
@@ -1811,7 +1859,7 @@ var y = d * 365.25;
 module.exports = function(val, options){
   options = options || {};
   if ('string' == typeof val) return parse(val);
-  return options.long ? longFormat(val) : shortFormat(val);
+  return options['long'] ? longFormat(val) : shortFormat(val);
 };
 
 /**
@@ -2085,7 +2133,7 @@ exports.list = function(failures){
     }
 
     // actual / expected diff
-    if ('string' == typeof actual && 'string' == typeof expected) {
+    if (err.showDiff && 'string' == typeof actual && 'string' == typeof 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);
@@ -2943,7 +2991,7 @@ function map(cov) {
   }
 
   return ret;
-};
+}
 
 /**
  * Map jscoverage data for a single source file
@@ -3100,6 +3148,7 @@ function JSONReporter(runner) {
   Base.call(this, runner);
 
   var tests = []
+    , pending = []
     , failures = []
     , passes = [];
 
@@ -3111,21 +3160,23 @@ function JSONReporter(runner) {
     passes.push(test);
   });
 
-  runner.on('fail', function(test, err){
+  runner.on('fail', function(test){
     failures.push(test);
-    if (err === Object(err)) {
-      test.errMsg = err.message;
-      test.errStack = err.stack;
-    }
+  });
+
+  runner.on('pending', function(test){
+    pending.push(test);
   });
 
   runner.on('end', function(){
     var obj = {
       stats: self.stats,
       tests: tests.map(clean),
+      pending: pending.map(clean),
       failures: failures.map(clean),
       passes: passes.map(clean)
     };
+
     runner.testResults = obj;
 
     process.stdout.write(JSON.stringify(obj, null, 2));
@@ -3146,12 +3197,24 @@ function clean(test) {
     title: test.title,
     fullTitle: test.fullTitle(),
     duration: test.duration,
-    err: test.err,
-    errStack: test.err.stack,
-    errMessage: test.err.message
+    err: errorJSON(test.err || {})
   }
 }
 
+/**
+ * Transform `error` into a JSON object.
+ * @param {Error} err
+ * @return {Object}
+ */
+
+function errorJSON(err) {
+  var res = {};
+  Object.getOwnPropertyNames(err).forEach(function(key) {
+    res[key] = err[key];
+  }, err);
+  return res;
+}
+
 }); // module: reporters/json.js
 
 require.register("reporters/landing.js", function(module, exports, require){
@@ -3658,7 +3721,7 @@ NyanCat.prototype.face = function() {
   } else {
     return '( - .-)';
   }
-}
+};
 
 /**
  * Move cursor up `n`.
@@ -4203,6 +4266,7 @@ Runnable.prototype.constructor = Runnable;
 
 Runnable.prototype.timeout = function(ms){
   if (0 == arguments.length) return this._timeout;
+  if (ms === 0) this._enableTimeouts = false;
   if ('string' == typeof ms) ms = milliseconds(ms);
   debug('timeout %d', ms);
   this._timeout = ms;
@@ -4292,6 +4356,7 @@ Runnable.prototype.resetTimeout = function(){
   if (!this._enableTimeouts) return;
   this.clearTimeout();
   this.timer = setTimeout(function(){
+    if (!self._enableTimeouts) return;
     self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
     self.timedOut = true;
   }, ms);
@@ -4942,18 +5007,25 @@ Runner.prototype.runSuite = function(suite, fn){
 
 Runner.prototype.uncaught = function(err){
   if (err) {
-    debug('uncaught exception %s', err.message);
+    debug('uncaught exception %s', err !== function () {
+      return this;
+    }.call(err) ? err : ( err.message || err ));
   } else {
     debug('uncaught undefined exception');
-    err = new Error('Catched undefined error, did you throw without specifying what?');
+    err = new Error('Caught undefined error, did you throw without specifying what?');
   }
-  
-  var runnable = this.currentRunnable;
-  if (!runnable || 'failed' == runnable.state) return;
-  runnable.clearTimeout();
   err.uncaught = true;
+
+  var runnable = this.currentRunnable;
+  if (!runnable) return;
+
+  var wasAlreadyDone = runnable.state;
   this.fail(runnable, err);
 
+  runnable.clearTimeout();
+
+  if (wasAlreadyDone) return;
+
   // recover from test
   if ('test' == runnable.type) {
     this.emit('test end', runnable);
@@ -5013,7 +5085,7 @@ Runner.prototype.run = function(fn){
 Runner.prototype.abort = function(){
   debug('aborting');
   this._abort = true;
-}
+};
 
 /**
  * Filter leaks with the given globals flagged as `ok`.
@@ -5182,6 +5254,7 @@ Suite.prototype.clone = function(){
 
 Suite.prototype.timeout = function(ms){
   if (0 == arguments.length) return this._timeout;
+  if (ms === 0) this._enableTimeouts = false;
   if ('string' == typeof ms) ms = milliseconds(ms);
   debug('timeout %d', ms);
   this._timeout = parseInt(ms, 10);
@@ -5201,7 +5274,7 @@ Suite.prototype.enableTimeouts = function(enabled){
   debug('enableTimeouts %s', enabled);
   this._enableTimeouts = enabled;
   return this;
-}
+};
 
 /**
  * Set slow `ms` or short-hand such as "2s".
@@ -5476,6 +5549,9 @@ require.register("utils.js", function(module, exports, require){
 
 var fs = require('browser/fs')
   , path = require('browser/path')
+  , basename = path.basename
+  , exists = fs.existsSync || path.existsSync
+  , glob = require('browser/glob')
   , join = path.join
   , debug = require('browser/debug')('mocha:watch');
 
@@ -5697,18 +5773,6 @@ exports.clean = function(str) {
 };
 
 /**
- * Escape regular expression characters in `str`.
- *
- * @param {String} str
- * @return {String}
- * @api private
- */
-
-exports.escapeRegexp = function(str){
-  return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
-};
-
-/**
  * Trim the given `str`.
  *
  * @param {String} str
@@ -5767,7 +5831,7 @@ function highlight(js) {
  */
 
 exports.highlightTags = function(name) {
-  var code = document.getElementsByTagName(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);
   }
@@ -5785,41 +5849,88 @@ exports.highlightTags = function(name) {
 exports.stringify = function(obj) {
   if (obj instanceof RegExp) return obj.toString();
   return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
-}
+};
 
 /**
  * Return a new object that has the keys in sorted order.
  * @param {Object} obj
+ * @param {Array} [stack]
  * @return {Object}
  * @api private
  */
 
 exports.canonicalize = function(obj, stack) {
-   stack = stack || [];
-
-   if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
-
-   var canonicalizedObj;
-
-   if ({}.toString.call(obj) === '[object Array]') {
-     stack.push(obj);
-     canonicalizedObj = exports.map(obj, function(item) {
-       return exports.canonicalize(item, stack);
-     });
-     stack.pop();
-   } else if (typeof obj === 'object' && obj !== null) {
-     stack.push(obj);
-     canonicalizedObj = {};
-     exports.forEach(exports.keys(obj).sort(), function(key) {
-       canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
-     });
-     stack.pop();
-   } else {
-     canonicalizedObj = obj;
-   }
-
-   return canonicalizedObj;
- }
+  stack = stack || [];
+
+  if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
+
+  var canonicalizedObj;
+
+  if ({}.toString.call(obj) === '[object Array]') {
+    stack.push(obj);
+    canonicalizedObj = exports.map(obj, function (item) {
+      return exports.canonicalize(item, stack);
+    });
+    stack.pop();
+  } else if (typeof obj === 'object' && obj !== null) {
+    stack.push(obj);
+    canonicalizedObj = {};
+    exports.forEach(exports.keys(obj).sort(), function (key) {
+      canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
+    });
+    stack.pop();
+  } else {
+    canonicalizedObj = obj;
+  }
+
+  return canonicalizedObj;
+ };
+
+/**
+ * Lookup file names at the given `path`.
+ */
+exports.lookupFiles = 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 = fs.statSync(path);
+    if (stat.isFile()) return path;
+  }
+  catch (ignored) {
+    return;
+  }
+
+  fs.readdirSync(path).forEach(function(file){
+    file = join(path, file);
+    try {
+      var stat = fs.statSync(file);
+      if (stat.isDirectory()) {
+        if (recursive) {
+          files = files.concat(lookupFiles(file, extensions, recursive));
+        }
+        return;
+      }
+    }
+    catch (ignored) {
+      return;
+    }
+    if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return;
+    files.push(file);
+  });
+
+  return files;
+};
 
 }); // module: utils.js
 // The global object is "self" in Web Workers.
@@ -5968,7 +6079,8 @@ mocha.run = function(fn){
 
   return Mocha.prototype.run.call(mocha, function(err){
     // The DOM Document is not available in Web Workers.
-    if (global.document) {
+    var document = global.document;
+    if (document && document.getElementById('mocha') && options.noHighlighting !== true) {
       Mocha.utils.highlightTags('code');
     }
     if (fn) fn(err);
diff --git a/package.json b/package.json
index a8dd6a2..ce702d2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "mocha",
-  "version": "1.21.4",
+  "version": "1.21.5",
   "description": "simple, flexible, fun test framework",
   "keywords": [
     "mocha",
@@ -36,16 +36,17 @@
     "test": "make test-all"
   },
   "dependencies": {
-    "commander": "2.0.0",
-    "growl": "1.8.x",
+    "commander": "2.3.0",
+    "debug": "2.0.0",
+    "diff": "1.0.8",
+    "escape-string-regexp": "1.0.2",
+    "glob": "3.2.3",
+    "growl": "1.8.1",
     "jade": "0.26.3",
-    "diff": "1.0.7",
-    "debug": "*",
-    "mkdirp": "0.3.5",
-    "glob": "3.2.3"
+    "mkdirp": "0.5.0"
   },
   "devDependencies": {
-    "coffee-script": "~1.7.1",
+    "coffee-script": "~1.8.0",
     "should": "~4.0.0"
   },
   "files": [
diff --git a/support/compile.js b/support/compile.js
index 39a5322..a0a94d2 100644
--- a/support/compile.js
+++ b/support/compile.js
@@ -43,12 +43,14 @@ function parse(js) {
 
 function parseRequires(js) {
   return js
-    .replace(/require\('events'\)/g, "require('browser/events')")
-    .replace(/require\('debug'\)/g, "require('browser/debug')")
-    .replace(/require\('path'\)/g, "require('browser/path')")
-    .replace(/require\('diff'\)/g, "require('browser/diff')")
-    .replace(/require\('tty'\)/g, "require('browser/tty')")
-    .replace(/require\('fs'\)/g, "require('browser/fs')")
+    .replace(/require\('events'\)/g               , "require('browser/events')")
+    .replace(/require\('debug'\)/g                , "require('browser/debug')")
+    .replace(/require\('path'\)/g                 , "require('browser/path')")
+    .replace(/require\('diff'\)/g                 , "require('browser/diff')")
+    .replace(/require\('tty'\)/g                  , "require('browser/tty')")
+    .replace(/require\('escape-string-regexp'\)/g , "require('browser/escape-string-regexp')")
+    .replace(/require\('glob'\)/g                 , "require('browser/glob')")
+    .replace(/require\('fs'\)/g                   , "require('browser/fs')");
 }
 
 /**
diff --git a/support/tail.js b/support/tail.js
index 16be67c..e9c0c0d 100644
--- a/support/tail.js
+++ b/support/tail.js
@@ -144,7 +144,8 @@ mocha.run = function(fn){
 
   return Mocha.prototype.run.call(mocha, function(err){
     // The DOM Document is not available in Web Workers.
-    if (global.document) {
+    var document = global.document;
+    if (document && document.getElementById('mocha') && options.noHighlighting !== true) {
       Mocha.utils.highlightTags('code');
     }
     if (fn) fn(err);
diff --git a/test/acceptance/timeout.js b/test/acceptance/timeout.js
index 3e865f9..a12f2fb 100644
--- a/test/acceptance/timeout.js
+++ b/test/acceptance/timeout.js
@@ -25,11 +25,56 @@ describe('timeouts', function(){
       this.timeout(1);
       setTimeout(done, 2);
     });
-    
+
     it('should work with timeout(0)', function(done) {
       this.timeout(0);
       setTimeout(done, 1);
     })
+
+    describe('using beforeEach', function() {
+      beforeEach(function () {
+        this.timeout(0);
+      })
+
+      it('should work with timeout(0)', function(done) {
+        setTimeout(done, 1);
+      })
+    })
+
+    describe('using before', function() {
+      before(function () {
+        this.timeout(0);
+      })
+
+      it('should work with timeout(0)', function(done) {
+        setTimeout(done, 1);
+      })
+    })
+
+    describe('using enableTimeouts(false)', function() {
+      this.timeout(4);
+
+      it('should suppress timeout(4)', function(done) {
+        // The test is in the before() call.
+        this.enableTimeouts(false);
+        setTimeout(done, 50);
+      })
+    })
+
+    describe('suite-level', function() {
+      this.timeout(0);
+
+      it('should work with timeout(0)', function(done) {
+        setTimeout(done, 1);
+      })
+
+      describe('nested suite', function () {
+        it('should work with timeout(0)', function(done) {
+          setTimeout(done, 1);
+        })
+
+      })
+    })
   });
-  
+
 })
diff --git a/test/acceptance/utils.js b/test/acceptance/utils.js
index 9c900a9..4bb52e3 100644
--- a/test/acceptance/utils.js
+++ b/test/acceptance/utils.js
@@ -86,4 +86,35 @@ describe('lib/utils', function () {
       utils.stringify(travis).should.equal('{\n  "name": "travis"\n  "whoami": "[Circular]"\n}');
     });
   });
+
+  describe('lookupFiles', function () {
+    var fs = require('fs'),
+      path = require('path'),
+      existsSync = fs.existsSync || path.existsSync;
+
+    beforeEach(function () {
+      fs.writeFileSync('/tmp/mocha-utils.js', 'yippy skippy ying yang yow');
+      fs.symlinkSync('/tmp/mocha-utils.js', '/tmp/mocha-utils-link.js');
+    });
+
+    it('should not choke on symlinks', function () {
+      utils.lookupFiles('/tmp', ['js'], false)
+        .should.containEql('/tmp/mocha-utils-link.js')
+        .and.containEql('/tmp/mocha-utils.js')
+        .and.have.lengthOf(2);
+      existsSync('/tmp/mocha-utils-link.js').should.be.true;
+      fs.rename('/tmp/mocha-utils.js', '/tmp/bob');
+      existsSync('/tmp/mocha-utils-link.js').should.be.true;
+      utils.lookupFiles('/tmp', ['js'], false).should.eql([]);
+    });
+
+    afterEach(function () {
+      ['/tmp/mocha-utils.js', '/tmp/mocha-utils-link.js', '/tmp/bob'].forEach(function (path) {
+        try {
+          fs.unlinkSync(path);
+        }
+        catch (ignored) {}
+      });
+    });
+  });
 });
diff --git a/test/regression/issue1327/case.js b/test/regression/issue1327/case.js
new file mode 100644
index 0000000..295ec12
--- /dev/null
+++ b/test/regression/issue1327/case.js
@@ -0,0 +1,14 @@
+var debug = require('debug')('mocha:issue1327');
+it("test 1", function() {
+    debug("This runs only once.");
+    process.nextTick(function() {
+        throw "Too bad";
+    });
+});
+it("test 2", function() {
+    debug("This should run once - Previously wasn't called at all.");
+});
+it("test 3", function() {
+    debug("This used to run twice.");
+    throw new Error("OUCH");
+});
diff --git a/test/regression/issue1327/control.js b/test/regression/issue1327/control.js
new file mode 100644
index 0000000..b77555d
--- /dev/null
+++ b/test/regression/issue1327/control.js
@@ -0,0 +1,10 @@
+var assert = require("assert"),
+    fs = require("fs");
+
+describe("GitHub issue #1327: expected behavior of case.js", function() {
+    it("should have run 3 tests", function() {
+        var results = JSON.parse(fs.readFileSync(
+            "test-outputs/issue1327/case-out.json"));
+        results.stats.tests.should.equal(3);
+    });
+});
diff --git a/test/reporters/base.js b/test/reporters/base.js
new file mode 100644
index 0000000..e8fe1e6
--- /dev/null
+++ b/test/reporters/base.js
@@ -0,0 +1,68 @@
+var Base = require('../../lib/reporters/base');
+
+describe('Base reporter', function () {
+
+  it('should show diffs with showDiff property set', function () {
+    var err = new Error('test'),
+      stderr = [],
+      stderrWrite = process.stderr.write,
+      errOut;
+
+    err.actual = "a1";
+    err.expected = "e1";
+    err.showDiff = true;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stderr.write = function (string) {
+      stderr.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stderr.write = stderrWrite;
+
+    errOut = stderr.join('\n');
+
+    errOut.should.match(/test/);
+    errOut.should.match(/actual/);
+    errOut.should.match(/expected/);
+
+  });
+
+  it('should not show diffs when showDiff property set', function () {
+    var err = new Error('test'),
+      stderr = [],
+      stderrWrite = process.stderr.write,
+      errOut;
+
+    err.actual = "a1";
+    err.expected = "e1";
+    err.showDiff = false;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stderr.write = function (string) {
+      stderr.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stderr.write = stderrWrite;
+
+    errOut = stderr.join('\n');
+
+    errOut.should.match(/test/);
+    errOut.should.not.match(/actual/);
+    errOut.should.not.match(/expected/);
+
+  });
+});
diff --git a/test/reporters/json.js b/test/reporters/json.js
index e5c1a0a..56173bf 100644
--- a/test/reporters/json.js
+++ b/test/reporters/json.js
@@ -40,4 +40,23 @@ describe('json reporter', function(){
      });
   })
 
+  it('should have 1 test pending', function(done) {
+    var testTitle = 'json test 1';
+
+     suite.addTest(new Test(testTitle));
+
+     runner.run(function(failureCount) {
+       failureCount.should.be.exactly(0);
+       runner.should.have.property('testResults');
+       runner.testResults.should.have.property('pending');
+       runner.testResults.pending.should.be.an.instanceOf(Array);
+       runner.testResults.pending.should.have.a.lengthOf(1);
+
+       var pending = runner.testResults.pending[0];
+       pending.should.have.property('title', testTitle);
+
+       done();
+     });
+  })
+
 })
diff --git a/test/runnable.js b/test/runnable.js
index ee20c8a..6127b4e 100644
--- a/test/runnable.js
+++ b/test/runnable.js
@@ -225,6 +225,20 @@ describe('Runnable(title, fn)', function(){
             done();
           });
         })
+
+        it('should not throw its own exception if passed a non-object', function (done) {
+          var test = new Runnable('foo', function(done) {
+            throw null;
+            process.nextTick(done);
+          });
+
+          test.run(function(err) {
+            if (err !== null) {
+              throw new should.AssertionError('err should be null');
+            }
+            done();
+          })
+        });
       })
 
       describe('when an error is passed', function(){

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-mocha.git



More information about the Pkg-javascript-commits mailing list