From a67a4d5e9bfab1a6e3834e38a3fc2739e9375212 Mon Sep 17 00:00:00 2001
From: mattab <matthieu.aubry@gmail.com>
Date: Fri, 6 Mar 2015 16:23:26 +1300
Subject: [PATCH] Updating mocha to latest stable (cherry picked from commit
 e7f236e)

---
 tests/UI/config.dist.js                       |    2 +-
 tests/lib/mocha-1.17.1/.travis.yml            |    4 -
 tests/lib/mocha-1.17.1/Readme.md              |  172 ---
 tests/lib/mocha-1.17.1/bower.json             |   20 -
 tests/lib/mocha-1.17.1/lib/utils.js           |  299 -----
 tests/lib/mocha-1.17.1/package.json           |   49 -
 tests/lib/mocha-1.17.1/support/foot.js        |    1 -
 .../mocha-1.17.1/test/acceptance/context.js   |   26 -
 .../mocha-1.17.1/test/acceptance/timeout.js   |   21 -
 .../lib/mocha-1.17.1/test/acceptance/utils.js |   59 -
 tests/lib/mocha-2.1.0/.editorconfig           |   18 +
 .../{mocha-1.17.1 => mocha-2.1.0}/.gitignore  |    3 +
 tests/lib/mocha-2.1.0/.mailmap                |    1 +
 tests/lib/mocha-2.1.0/.travis.yml             |    9 +
 tests/lib/mocha-2.1.0/CONTRIBUTING.md         |   49 +
 .../History.md => mocha-2.1.0/HISTORY.md}     |  150 +++
 .../lib/{mocha-1.17.1 => mocha-2.1.0}/LICENSE |    2 +-
 .../{mocha-1.17.1 => mocha-2.1.0}/Makefile    |   36 +-
 tests/lib/mocha-2.1.0/README.md               |  226 ++++
 .../{mocha-1.17.1 => mocha-2.1.0}/bin/_mocha  |  131 +--
 .../{mocha-1.17.1 => mocha-2.1.0}/bin/mocha   |   14 +-
 tests/lib/mocha-2.1.0/bower.json              |   47 +
 .../component.json                            |   14 +-
 .../Snippets/bdd - after each.tmSnippet       |    0
 .../Snippets/bdd - after.tmSnippet            |    0
 .../Snippets/bdd - before each.tmSnippet      |    0
 .../Snippets/bdd - before.tmSnippet           |    0
 .../Snippets/bdd - describe.tmSnippet         |    0
 .../Snippets/bdd - it.tmSnippet               |    0
 .../Snippets/tdd - assert.tmSnippet           |    0
 .../Snippets/tdd - assert_deepEqual.tmSnippet |    0
 .../Snippets/tdd - assert_equal.tmSnippet     |    0
 .../Snippets/tdd - assert_fail.tmSnippet      |    0
 .../tdd - assert_isFunction.tmSnippet         |    0
 .../Snippets/tdd - setup.tmSnippet            |    0
 .../Snippets/tdd - suite.tmSnippet            |    0
 .../Snippets/tdd - teardown.tmSnippet         |    0
 .../Snippets/tdd - test.tmSnippet             |    0
 .../JavaScript mocha.tmbundle/info.plist      |    0
 .../images/error.png                          |  Bin
 .../images/ok.png                             |  Bin
 .../{mocha-1.17.1 => mocha-2.1.0}/index.js    |    3 +-
 .../lib/browser/debug.js                      |    1 -
 .../lib/browser/escape-string-regexp.js       |   11 +
 .../lib/browser/events.js                     |    3 +-
 .../lib/browser/fs.js                         |    0
 .../lib/browser/glob.js}                      |    0
 tests/lib/mocha-2.1.0/lib/browser/path.js     |    0
 .../lib/browser/progress.js                   |    0
 .../lib/browser/tty.js                        |    1 -
 .../lib/context.js                            |   16 +-
 .../{mocha-1.17.1 => mocha-2.1.0}/lib/hook.js |    1 -
 .../lib/interfaces/bdd.js                     |   26 +-
 .../lib/interfaces/exports.js                 |    9 +-
 .../lib/interfaces/index.js                   |    1 -
 .../lib/interfaces/qunit.js                   |   22 +-
 .../lib/interfaces/tdd.js                     |   26 +-
 .../lib/mocha.js                              |   76 +-
 .../{mocha-1.17.1 => mocha-2.1.0}/lib/ms.js   |    2 +-
 .../lib/reporters/base.js                     |   73 +-
 .../lib/reporters/doc.js                      |    8 +-
 .../lib/reporters/dot.js                      |    6 +-
 .../lib/reporters/html-cov.js                 |    3 +-
 .../lib/reporters/html.js                     |   23 +-
 .../lib/reporters/index.js                    |    1 -
 .../lib/reporters/json-cov.js                 |    3 +-
 .../lib/reporters/json-stream.js              |    7 +-
 .../lib/reporters/json.js                     |   40 +-
 .../lib/reporters/landing.js                  |    7 +-
 .../lib/reporters/list.js                     |    1 -
 .../lib/reporters/markdown.js                 |   21 +-
 .../lib/reporters/min.js                      |    1 -
 .../lib/reporters/nyan.js                     |   28 +-
 .../lib/reporters/progress.js                 |   10 +-
 .../lib/reporters/spec.js                     |    1 -
 .../lib/reporters/tap.js                      |    1 -
 .../lib/reporters/templates/coverage.jade     |    3 +-
 .../lib/reporters/templates/menu.jade         |    0
 .../lib/reporters/templates/script.html       |    0
 .../lib/reporters/templates/style.html        |    2 +-
 .../lib/reporters/xunit.js                    |   52 +-
 .../lib/runnable.js                           |   86 +-
 .../lib/runner.js                             |   30 +-
 .../lib/suite.js                              |   73 +-
 .../lib/template.html                         |    0
 .../{mocha-1.17.1 => mocha-2.1.0}/lib/test.js |    1 -
 tests/lib/mocha-2.1.0/lib/utils.js            |  548 +++++++++
 .../media/logo.svg                            |   15 +-
 .../{mocha-1.17.1 => mocha-2.1.0}/mocha.css   |    0
 .../{mocha-1.17.1 => mocha-2.1.0}/mocha.js    | 1005 ++++++++++++-----
 tests/lib/mocha-2.1.0/package.json            |   73 ++
 .../support/compile.js                        |   15 +-
 tests/lib/mocha-2.1.0/support/foot.js         |    1 +
 .../support/head.js                           |    0
 .../support/tail.js                           |   18 +-
 .../mocha-2.1.0/test/acceptance/context.js    |   72 ++
 .../test/acceptance/diffs.js                  |   15 +-
 .../test/acceptance/duration.js               |    1 -
 .../test/acceptance/failing/timeout.js        |   17 +
 .../test/acceptance/fixtures/css.in           |    2 +-
 .../test/acceptance/fixtures/css.out          |    2 +-
 .../test/acceptance/fs.js                     |    1 -
 .../test/acceptance/glob/glob.js              |    1 -
 .../test/acceptance/glob/glob.sh              |    0
 .../test/acceptance/globals.js                |    1 -
 .../test/acceptance/http.js                   |    5 +-
 .../test/acceptance/interfaces/bdd.js         |    1 -
 .../test/acceptance/interfaces/exports.js     |    1 -
 .../test/acceptance/interfaces/qunit.js       |    3 +-
 .../test/acceptance/interfaces/tdd.js         |    1 -
 .../test/acceptance/misc/asyncOnly.js         |    1 -
 .../test/acceptance/misc/bail.js              |    1 -
 .../test/acceptance/misc/cascade.js           |    1 -
 .../test/acceptance/misc/exit.js              |    5 +
 .../test/acceptance/misc/grep.js              |    1 -
 .../test/acceptance/misc/many.js              |    2 +-
 .../test/acceptance/misc/nontty.js            |    1 -
 .../test/acceptance/misc/only/bdd.js          |    3 +-
 .../test/acceptance/misc/only/qunit.js        |    3 +-
 .../test/acceptance/misc/only/tdd.js          |    3 +-
 .../test/acceptance/multiple.done.js          |   11 +-
 .../test/acceptance/pending.js                |    3 +-
 .../test/acceptance/require/a.js              |    0
 .../test/acceptance/require/b.coffee          |    0
 .../test/acceptance/require/c.js              |    0
 .../test/acceptance/require/d.coffee          |    0
 .../test/acceptance/require/require.js        |    1 -
 .../test/acceptance/required-tokens.js        |    0
 .../test/acceptance/root.js                   |    3 +-
 .../test/acceptance/sort/alpha.js             |    2 +-
 .../test/acceptance/sort/beta.js              |    2 +-
 .../test/acceptance/test.coffee               |    2 +-
 .../test/acceptance/test.foo                  |    0
 .../lib/mocha-2.1.0/test/acceptance/throw.js  |  111 ++
 .../mocha-2.1.0/test/acceptance/timeout.js    |   79 ++
 .../test/acceptance/uncaught.js               |    3 +-
 .../lib/mocha-2.1.0/test/acceptance/utils.js  |  263 +++++
 .../test/browser/array.js                     |    0
 .../test/browser/index.html                   |    0
 .../test/browser/large.html                   |    0
 .../test/browser/large.js                     |    3 +-
 .../test/browser/opts.html                    |    0
 .../test/browser/opts.js                      |    0
 tests/lib/mocha-2.1.0/test/color.js           |   17 +
 .../test/compiler/foo.js                      |    0
 .../test/grep.js                              |    1 -
 .../test/hook.async.js                        |    1 -
 .../test/hook.err.js                          |    2 +-
 .../test/hook.sync.js                         |    3 +-
 .../test/hook.sync.nested.js                  |    1 -
 .../test/hook.timeout.js                      |    3 +-
 .../test/http.meta.2.js                       |    6 +-
 .../test/http.meta.js                         |    5 +-
 .../test/jsapi/index.js                       |    1 -
 .../test/mocha.opts                           |    0
 .../test/regression/issue1327/case.js         |   14 +
 .../test/regression/issue1327/control.js      |   10 +
 tests/lib/mocha-2.1.0/test/reporters/base.js  |  136 +++
 tests/lib/mocha-2.1.0/test/reporters/json.js  |   61 +
 .../test/reporters/nyan.js                    |    1 +
 .../test/runnable.js                          |  165 ++-
 .../test/runner.js                            |   31 +-
 .../test/suite.js                             |   76 +-
 .../test/utils.js                             |   18 +-
 164 files changed, 3568 insertions(+), 1318 deletions(-)
 delete mode 100644 tests/lib/mocha-1.17.1/.travis.yml
 delete mode 100644 tests/lib/mocha-1.17.1/Readme.md
 delete mode 100644 tests/lib/mocha-1.17.1/bower.json
 delete mode 100644 tests/lib/mocha-1.17.1/lib/utils.js
 delete mode 100644 tests/lib/mocha-1.17.1/package.json
 delete mode 100644 tests/lib/mocha-1.17.1/support/foot.js
 delete mode 100644 tests/lib/mocha-1.17.1/test/acceptance/context.js
 delete mode 100644 tests/lib/mocha-1.17.1/test/acceptance/timeout.js
 delete mode 100644 tests/lib/mocha-1.17.1/test/acceptance/utils.js
 create mode 100644 tests/lib/mocha-2.1.0/.editorconfig
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/.gitignore (81%)
 create mode 100644 tests/lib/mocha-2.1.0/.mailmap
 create mode 100644 tests/lib/mocha-2.1.0/.travis.yml
 create mode 100644 tests/lib/mocha-2.1.0/CONTRIBUTING.md
 rename tests/lib/{mocha-1.17.1/History.md => mocha-2.1.0/HISTORY.md} (78%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/LICENSE (94%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/Makefile (74%)
 create mode 100644 tests/lib/mocha-2.1.0/README.md
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/bin/_mocha (81%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/bin/mocha (69%)
 create mode 100644 tests/lib/mocha-2.1.0/bower.json
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/component.json (59%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - after each.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - after.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - before each.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - before.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - describe.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/bdd - it.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_deepEqual.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_equal.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_fail.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_isFunction.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - setup.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - suite.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - teardown.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/Snippets/tdd - test.tmSnippet (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/editors/JavaScript mocha.tmbundle/info.plist (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/images/error.png (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/images/ok.png (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/index.js (69%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/browser/debug.js (98%)
 create mode 100644 tests/lib/mocha-2.1.0/lib/browser/escape-string-regexp.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/browser/events.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/browser/fs.js (100%)
 rename tests/lib/{mocha-1.17.1/lib/browser/path.js => mocha-2.1.0/lib/browser/glob.js} (100%)
 create mode 100644 tests/lib/mocha-2.1.0/lib/browser/path.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/browser/progress.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/browser/tty.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/context.js (78%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/hook.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/interfaces/bdd.js (80%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/interfaces/exports.js (85%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/interfaces/index.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/interfaces/qunit.js (80%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/interfaces/tdd.js (80%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/mocha.js (82%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/ms.js (96%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/base.js (86%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/doc.js (76%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/dot.js (91%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/html-cov.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/html.js (92%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/index.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/json-cov.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/json-stream.js (90%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/json.js (58%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/landing.js (92%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/list.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/markdown.js (81%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/min.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/nyan.js (92%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/progress.js (91%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/spec.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/tap.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/templates/coverage.jade (97%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/templates/menu.jade (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/templates/script.html (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/templates/style.html (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/reporters/xunit.js (62%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/runnable.js (67%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/runner.js (97%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/suite.js (75%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/template.html (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/lib/test.js (99%)
 create mode 100644 tests/lib/mocha-2.1.0/lib/utils.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/media/logo.svg (72%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/mocha.css (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/mocha.js (85%)
 create mode 100644 tests/lib/mocha-2.1.0/package.json
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/support/compile.js (82%)
 create mode 100644 tests/lib/mocha-2.1.0/support/foot.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/support/head.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/support/tail.js (87%)
 create mode 100644 tests/lib/mocha-2.1.0/test/acceptance/context.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/diffs.js (86%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/duration.js (99%)
 create mode 100644 tests/lib/mocha-2.1.0/test/acceptance/failing/timeout.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/fixtures/css.in (98%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/fixtures/css.out (98%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/fs.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/glob/glob.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/glob/glob.sh (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/globals.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/http.js (84%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/interfaces/bdd.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/interfaces/exports.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/interfaces/qunit.js (98%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/interfaces/tdd.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/asyncOnly.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/bail.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/cascade.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/exit.js (77%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/grep.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/many.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/nontty.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/only/bdd.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/only/qunit.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/misc/only/tdd.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/multiple.done.js (63%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/pending.js (95%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/require/a.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/require/b.coffee (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/require/c.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/require/d.coffee (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/require/require.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/required-tokens.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/root.js (98%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/sort/alpha.js (97%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/sort/beta.js (96%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/test.coffee (70%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/test.foo (100%)
 create mode 100644 tests/lib/mocha-2.1.0/test/acceptance/throw.js
 create mode 100644 tests/lib/mocha-2.1.0/test/acceptance/timeout.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/acceptance/uncaught.js (99%)
 create mode 100644 tests/lib/mocha-2.1.0/test/acceptance/utils.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/array.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/index.html (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/large.html (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/large.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/opts.html (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/browser/opts.js (100%)
 create mode 100644 tests/lib/mocha-2.1.0/test/color.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/compiler/foo.js (100%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/grep.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/hook.async.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/hook.err.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/hook.sync.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/hook.sync.nested.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/hook.timeout.js (96%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/http.meta.2.js (95%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/http.meta.js (95%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/jsapi/index.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/mocha.opts (100%)
 create mode 100644 tests/lib/mocha-2.1.0/test/regression/issue1327/case.js
 create mode 100644 tests/lib/mocha-2.1.0/test/regression/issue1327/control.js
 create mode 100644 tests/lib/mocha-2.1.0/test/reporters/base.js
 create mode 100644 tests/lib/mocha-2.1.0/test/reporters/json.js
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/reporters/nyan.js (99%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/runnable.js (59%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/runner.js (90%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/suite.js (77%)
 rename tests/lib/{mocha-1.17.1 => mocha-2.1.0}/test/utils.js (67%)

diff --git a/tests/UI/config.dist.js b/tests/UI/config.dist.js
index 93aa763cf1..687cebc0de 100644
--- a/tests/UI/config.dist.js
+++ b/tests/UI/config.dist.js
@@ -30,7 +30,7 @@ exports.php = 'php';
 /**
  * The folder in tests/lib that holds mocha.
  */
-exports.mocha = 'mocha-1.17.1';
+exports.mocha = 'mocha-2.1.0';
 
 /**
  * The folder in tests/lib that holds chai.
diff --git a/tests/lib/mocha-1.17.1/.travis.yml b/tests/lib/mocha-1.17.1/.travis.yml
deleted file mode 100644
index 09d3ef3784..0000000000
--- a/tests/lib/mocha-1.17.1/.travis.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-language: node_js
-node_js:
-  - 0.8
-  - 0.10
diff --git a/tests/lib/mocha-1.17.1/Readme.md b/tests/lib/mocha-1.17.1/Readme.md
deleted file mode 100644
index 9340cacfda..0000000000
--- a/tests/lib/mocha-1.17.1/Readme.md
+++ /dev/null
@@ -1,172 +0,0 @@
- [![Build Status](https://secure.travis-ci.org/visionmedia/mocha.png)](http://travis-ci.org/visionmedia/mocha)
-
-  [![Mocha test framework](http://f.cl.ly/items/3l1k0n2A1U3M1I1L210p/Screen%20Shot%202012-02-24%20at%202.21.43%20PM.png)](http://visionmedia.github.io/mocha)
-
-  Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://visionmedia.github.io/mocha).
-
-## Contributors
-
-```
-
- project  : mocha
- repo age : 2 years, 4 months ago
- commits  : 1314
- active   : 372 days
- files    : 141
- authors  :
-   582    TJ Holowaychuk          44.3%
-   389    Tj Holowaychuk          29.6%
-    46    Travis Jeffery          3.5%
-    31    Guillermo Rauch         2.4%
-    13    Attila Domokos          1.0%
-    10    John Firebaugh          0.8%
-     8    Jo Liss                 0.6%
-     7    Nathan Rajlich          0.5%
-     6    Mike Pennisi            0.5%
-     6    James Carr              0.5%
-     6    Brendan Nee             0.5%
-     5    Aaron Heckmann          0.4%
-     5    Ryunosuke SATO          0.4%
-     4    hokaccha                0.3%
-     4    Joshua Krall            0.3%
-     4    Xavier Antoviaque       0.3%
-     3    Jesse Dailey            0.2%
-     3    Forbes Lindesay         0.2%
-     3    Sindre Sorhus           0.2%
-     3    Cory Thomas             0.2%
-     3    Fredrik Enestad         0.2%
-     3    Ben Lindsey             0.2%
-     3    Tyson Tate              0.2%
-     3    Mathieu Desvé          0.2%
-     3    Valentin Agachi         0.2%
-     3    Wil Moore III           0.2%
-     3    Merrick Christensen     0.2%
-     3    eiji.ienaga             0.2%
-     3    fool2fish               0.2%
-     3    Nathan Bowser           0.2%
-     3    Paul Miller             0.2%
-     2    Juzer Ali               0.2%
-     2    Pete Hawkins            0.2%
-     2    Jonas Westerlund        0.2%
-     2    Arian Stolwijk          0.2%
-     2    Quang Van               0.2%
-     2    Glen Mailer             0.2%
-     2    Justin DuJardin         0.2%
-     2    FARKAS Máté           0.2%
-     2    Raynos                  0.2%
-     2    Michael Riley           0.2%
-     2    Michael Schoonmaker     0.2%
-     2    Domenic Denicola        0.2%
-     2    Simon Gaeremynck        0.2%
-     2    Konstantin Käfer      0.2%
-     2    domenic                 0.2%
-     2    Paul Armstrong          0.2%
-     2    fcrisci                 0.2%
-     2    Alexander Early         0.2%
-     2    Shawn Krisman           0.2%
-     2    Brian Beck              0.2%
-     2    Nathan Alderson         0.2%
-     2    David Henderson         0.2%
-     2    Timo Tijhof             0.2%
-     2    Ian Storm Taylor        0.2%
-     2    travis jeffery          0.2%
-     1    Matt Smith              0.1%
-     1    Matthew Shanley         0.1%
-     1    Nathan Black            0.1%
-     1    Phil Sung               0.1%
-     1    R56                     0.1%
-     1    Refael Ackermann        0.1%
-     1    Richard Dingwall        0.1%
-     1    Romain Prieto           0.1%
-     1    Roman Neuhauser         0.1%
-     1    Roman Shtylman          0.1%
-     1    Russ Bradberry          0.1%
-     1    Russell Munson          0.1%
-     1    Rustem Mustafin         0.1%
-     1    Salehen Shovon Rahman   0.1%
-     1    Sasha Koss              0.1%
-     1    Seiya Konno             0.1%
-     1    Simon Goumaz            0.1%
-     1    Standa Opichal          0.1%
-     1    Stephen Mathieson       0.1%
-     1    Steve Mason             0.1%
-     1    Tapiwa Kelvin           0.1%
-     1    Teddy Zeenny            0.1%
-     1    Tim Ehat                0.1%
-     1    Vadim Nikitin           0.1%
-     1    Victor Costan           0.1%
-     1    Will Langstroth         0.1%
-     1    Yanis Wang              0.1%
-     1    Yuest Wang              0.1%
-     1    abrkn                   0.1%
-     1    airportyh               0.1%
-     1    badunk                  0.1%
-     1    fengmk2                 0.1%
-     1    grasGendarme            0.1%
-     1    lodr                    0.1%
-     1    tgautier@yahoo.com      0.1%
-     1    traleig1                0.1%
-     1    vlad                    0.1%
-     1    yuitest                 0.1%
-     1    Adam Crabtree           0.1%
-     1    Andreas Brekken         0.1%
-     1    Andreas Lind Petersen   0.1%
-     1    Andrew Nesbitt          0.1%
-     1    Andrey Popp             0.1%
-     1    Arnaud Brousseau        0.1%
-     1    Atsuya Takagi           0.1%
-     1    Austin Birch            0.1%
-     1    Bjørge Næss           0.1%
-     1    Brian Lalor             0.1%
-     1    Brian M. Carlson        0.1%
-     1    Brian Moore             0.1%
-     1    Bryan Donovan           0.1%
-     1    Casey Foster            0.1%
-     1    ChrisWren               0.1%
-     1    Corey Butler            0.1%
-     1    Daniel Stockman         0.1%
-     1    Dave McKenna            0.1%
-     1    Di Wu                   0.1%
-     1    Dmitry Shirokov         0.1%
-     1    Fedor Indutny           0.1%
-     1    Florian Margaine        0.1%
-     1    Frederico Silva         0.1%
-     1    Fredrik Lindin          0.1%
-     1    Gareth Murphy           0.1%
-     1    Gavin Mogan             0.1%
-     1    Glen Huang              0.1%
-     1    Greg Perkins            0.1%
-     1    Harry Brundage          0.1%
-     1    Herman Junge            0.1%
-     1    Ian Young               0.1%
-     1    Ivan                    0.1%
-     1    JP Bochi                0.1%
-     1    Jaakko Salonen          0.1%
-     1    Jakub NesÌŒetrÌŒil      0.1%
-     1    James Bowes             0.1%
-     1    James Lal               0.1%
-     1    Jason Barry             0.1%
-     1    Javier Aranda           0.1%
-     1    Jeff Kunkle             0.1%
-     1    Jeremy Martin           0.1%
-     1    Jimmy Cuadra            0.1%
-     1    Jonathan Creamer        0.1%
-     1    Jussi Virtanen          0.1%
-     1    Katie Gengler           0.1%
-     1    Kazuhito Hokamura       0.1%
-     1    Kirill Korolyov         0.1%
-     1    Koen Punt               0.1%
-     1    Laszlo Bacsi            0.1%
-     1    Liam Newman             0.1%
-     1    László Bácsi         0.1%
-     1    Maciej Małecki         0.1%
-     1    Mal Graty               0.1%
-     1    Marc Kuo                0.1%
-     1    Matt Robenolt           0.1%
-```
-
-## Links
-
-  - [Google Group](http://groups.google.com/group/mochajs)
-  - [Wiki](https://github.com/visionmedia/mocha/wiki)
-  - Mocha [Extensions and reporters](https://github.com/visionmedia/mocha/wiki)
diff --git a/tests/lib/mocha-1.17.1/bower.json b/tests/lib/mocha-1.17.1/bower.json
deleted file mode 100644
index 84becdabb9..0000000000
--- a/tests/lib/mocha-1.17.1/bower.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "name": "mocha",
-  "version": "1.17.1",
-  "main": "mocha.js",
-  "ignore": [
-    "bin",
-    "editors",
-    "images",
-    "lib",
-    "support",
-    "test",
-    ".gitignore",
-    ".npmignore",
-    ".travis.yml",
-    "component.json",
-    "index.js",
-    "Makefile",
-    "package.json"
-  ]
-}
diff --git a/tests/lib/mocha-1.17.1/lib/utils.js b/tests/lib/mocha-1.17.1/lib/utils.js
deleted file mode 100644
index 37fd5d7e1b..0000000000
--- a/tests/lib/mocha-1.17.1/lib/utils.js
+++ /dev/null
@@ -1,299 +0,0 @@
-/**
- * Module dependencies.
- */
-
-var fs = require('fs')
-  , path = require('path')
-  , join = path.join
-  , debug = require('debug')('mocha:watch');
-
-/**
- * Ignored directories.
- */
-
-var ignore = ['node_modules', '.git'];
-
-/**
- * Escape special characters in the given string of html.
- *
- * @param  {String} html
- * @return {String}
- * @api private
- */
-
-exports.escape = function(html){
-  return String(html)
-    .replace(/&/g, '&amp;')
-    .replace(/"/g, '&quot;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;');
-};
-
-/**
- * Array#forEach (<=IE8)
- *
- * @param {Array} array
- * @param {Function} fn
- * @param {Object} scope
- * @api private
- */
-
-exports.forEach = function(arr, fn, scope){
-  for (var i = 0, l = arr.length; i < l; i++)
-    fn.call(scope, arr[i], i);
-};
-
-/**
- * Array#map (<=IE8)
- *
- * @param {Array} array
- * @param {Function} fn
- * @param {Object} scope
- * @api private
- */
-
-exports.map = function(arr, fn, scope){
-  var result = [];
-  for (var i = 0, l = arr.length; i < l; i++)
-    result.push(fn.call(scope, arr[i], i));
-  return result;
-};
-
-/**
- * Array#indexOf (<=IE8)
- *
- * @parma {Array} arr
- * @param {Object} obj to find index of
- * @param {Number} start
- * @api private
- */
-
-exports.indexOf = function(arr, obj, start){
-  for (var i = start || 0, l = arr.length; i < l; i++) {
-    if (arr[i] === obj)
-      return i;
-  }
-  return -1;
-};
-
-/**
- * Array#reduce (<=IE8)
- *
- * @param {Array} array
- * @param {Function} fn
- * @param {Object} initial value
- * @api private
- */
-
-exports.reduce = function(arr, fn, val){
-  var rval = val;
-
-  for (var i = 0, l = arr.length; i < l; i++) {
-    rval = fn(rval, arr[i], i, arr);
-  }
-
-  return rval;
-};
-
-/**
- * Array#filter (<=IE8)
- *
- * @param {Array} array
- * @param {Function} fn
- * @api private
- */
-
-exports.filter = function(arr, fn){
-  var ret = [];
-
-  for (var i = 0, l = arr.length; i < l; i++) {
-    var val = arr[i];
-    if (fn(val, i, arr)) ret.push(val);
-  }
-
-  return ret;
-};
-
-/**
- * Object.keys (<=IE8)
- *
- * @param {Object} obj
- * @return {Array} keys
- * @api private
- */
-
-exports.keys = Object.keys || function(obj) {
-  var keys = []
-    , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
-
-  for (var key in obj) {
-    if (has.call(obj, key)) {
-      keys.push(key);
-    }
-  }
-
-  return keys;
-};
-
-/**
- * Watch the given `files` for changes
- * and invoke `fn(file)` on modification.
- *
- * @param {Array} files
- * @param {Function} fn
- * @api private
- */
-
-exports.watch = function(files, fn){
-  var options = { interval: 100 };
-  files.forEach(function(file){
-    debug('file %s', file);
-    fs.watchFile(file, options, function(curr, prev){
-      if (prev.mtime < curr.mtime) fn(file);
-    });
-  });
-};
-
-/**
- * Ignored files.
- */
-
-function ignored(path){
-  return !~ignore.indexOf(path);
-}
-
-/**
- * Lookup files in the given `dir`.
- *
- * @return {Array}
- * @api private
- */
-
-exports.files = function(dir, ret){
-  ret = ret || [];
-
-  fs.readdirSync(dir)
-  .filter(ignored)
-  .forEach(function(path){
-    path = join(dir, path);
-    if (fs.statSync(path).isDirectory()) {
-      exports.files(path, ret);
-    } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) {
-      ret.push(path);
-    }
-  });
-
-  return ret;
-};
-
-/**
- * Compute a slug from the given `str`.
- *
- * @param {String} str
- * @return {String}
- * @api private
- */
-
-exports.slug = function(str){
-  return str
-    .toLowerCase()
-    .replace(/ +/g, '-')
-    .replace(/[^-\w]/g, '');
-};
-
-/**
- * Strip the function definition from `str`,
- * and re-indent for pre whitespace.
- */
-
-exports.clean = function(str) {
-  str = str
-    .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '')
-    .replace(/^function *\(.*\) *{/, '')
-    .replace(/\s+\}$/, '');
-
-  var spaces = str.match(/^\n?( *)/)[1].length
-    , tabs = str.match(/^\n?(\t*)/)[1].length
-    , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm');
-
-  str = str.replace(re, '');
-
-  return exports.trim(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
- * @return {String}
- * @api private
- */
-
-exports.trim = function(str){
-  return str.replace(/^\s+|\s+$/g, '');
-};
-
-/**
- * Parse the given `qs`.
- *
- * @param {String} qs
- * @return {Object}
- * @api private
- */
-
-exports.parseQuery = function(qs){
-  return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){
-    var i = pair.indexOf('=')
-      , key = pair.slice(0, i)
-      , val = pair.slice(++i);
-
-    obj[key] = decodeURIComponent(val);
-    return obj;
-  }, {});
-};
-
-/**
- * Highlight the given string of `js`.
- *
- * @param {String} js
- * @return {String}
- * @api private
- */
-
-function highlight(js) {
-  return js
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
-    .replace(/('.*?')/gm, '<span class="string">$1</span>')
-    .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
-    .replace(/(\d+)/gm, '<span class="number">$1</span>')
-    .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
-    .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
-}
-
-/**
- * Highlight the contents of tag `name`.
- *
- * @param {String} name
- * @api private
- */
-
-exports.highlightTags = function(name) {
-  var code = document.getElementsByTagName(name);
-  for (var i = 0, len = code.length; i < len; ++i) {
-    code[i].innerHTML = highlight(code[i].innerHTML);
-  }
-};
diff --git a/tests/lib/mocha-1.17.1/package.json b/tests/lib/mocha-1.17.1/package.json
deleted file mode 100644
index 2f5f07a8dc..0000000000
--- a/tests/lib/mocha-1.17.1/package.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "name": "mocha",
-  "version": "1.17.1",
-  "description": "simple, flexible, fun test framework",
-  "keywords": [
-    "mocha",
-    "test",
-    "bdd",
-    "tdd",
-    "tap"
-  ],
-  "author": "TJ Holowaychuk <tj@vision-media.ca>",
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/visionmedia/mocha.git"
-  },
-  "main": "./index",
-  "bin": {
-    "mocha": "./bin/mocha",
-    "_mocha": "./bin/_mocha"
-  },
-  "engines": {
-    "node": ">= 0.4.x"
-  },
-  "scripts": {
-    "test": "make test-all"
-  },
-  "dependencies": {
-    "commander": "2.0.0",
-    "growl": "1.7.x",
-    "jade": "0.26.3",
-    "diff": "1.0.7",
-    "debug": "*",
-    "mkdirp": "0.3.5",
-    "glob": "3.2.3"
-  },
-  "devDependencies": {
-    "should": ">= 2.0.x",
-    "coffee-script": "1.2"
-  },
-  "files": [
-    "bin",
-    "images",
-    "lib",
-    "index.js",
-    "mocha.css",
-    "mocha.js"
-  ]
-}
diff --git a/tests/lib/mocha-1.17.1/support/foot.js b/tests/lib/mocha-1.17.1/support/foot.js
deleted file mode 100644
index 158693a025..0000000000
--- a/tests/lib/mocha-1.17.1/support/foot.js
+++ /dev/null
@@ -1 +0,0 @@
-})();
\ No newline at end of file
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/context.js b/tests/lib/mocha-1.17.1/test/acceptance/context.js
deleted file mode 100644
index e2af9d5eae..0000000000
--- a/tests/lib/mocha-1.17.1/test/acceptance/context.js
+++ /dev/null
@@ -1,26 +0,0 @@
-
-describe('Context', function(){
-  beforeEach(function(){
-    this.calls = ['before'];
-  })
-
-  describe('nested', function(){
-    beforeEach(function(){
-      this.calls.push('before two');
-    })
-
-    it('should work', function(){
-      this.calls.should.eql(['before', 'before two']);
-      this.calls.push('test');
-    })
-
-    after(function(){
-      this.calls.should.eql(['before', 'before two', 'test']);
-      this.calls.push('after two');
-    })
-  })
-
-  after(function(){
-    this.calls.should.eql(['before', 'before two', 'test', 'after two']);
-  })
-})
\ No newline at end of file
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/timeout.js b/tests/lib/mocha-1.17.1/test/acceptance/timeout.js
deleted file mode 100644
index 109808bf5b..0000000000
--- a/tests/lib/mocha-1.17.1/test/acceptance/timeout.js
+++ /dev/null
@@ -1,21 +0,0 @@
-
-describe('timeouts', function(){
-  beforeEach(function(done){
-    // uncomment
-    // setTimeout(done, 3000);
-    done();
-  })
-
-  it('should error on timeout', function(done){
-    // uncomment
-    // setTimeout(done, 3000);
-    done();
-  })
-
-  it('should allow overriding per-test', function(done){
-    this.timeout(1000);
-    setTimeout(function(){
-      done();
-    }, 300);
-  })
-})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/utils.js b/tests/lib/mocha-1.17.1/test/acceptance/utils.js
deleted file mode 100644
index 97373687a6..0000000000
--- a/tests/lib/mocha-1.17.1/test/acceptance/utils.js
+++ /dev/null
@@ -1,59 +0,0 @@
-var utils = require('../../lib/utils');
-
-describe('lib/utils', function () {
-  describe('clean', function () {
-    it("should format a single line test function", function () {
-      var fn = [
-        "function () {"
-        , "  var a = 1;"
-        , "}"
-      ].join("\n");
-      utils.clean(fn).should.equal("var a = 1;");
-    });
-
-    it("should format a multi line test indented with spaces", function () {
-      // and no new lines after curly braces, shouldn't matter
-      var fn = [
-        "function(){  var a = 1;"
-        , "    var b = 2;" // this one has more spaces
-        , "  var c = 3;  }"
-      ].join("\n");
-      utils.clean(fn).should.equal("var a = 1;\n  var b = 2;\nvar c = 3;");
-    });
-
-    it("should format a multi line test indented with tabs", function () {
-      var fn = [
-        "function (arg1, arg2)   {"
-        , "\tif (true) {"
-        , "\t\tvar a = 1;"
-        , "\t}"
-        , "}"
-      ].join("\n");
-      utils.clean(fn).should.equal("if (true) {\n\tvar a = 1;\n}");
-    });
-
-    it("should format functions saved in windows style - spaces", function () {
-      var fn = [
-        "function (one) {"
-        , "   do {",
-        , '    "nothing";',
-        , "   } while (false);"
-        , ' }'
-      ].join("\r\n");
-      utils.clean(fn).should.equal('do {\n "nothing";\n} while (false);');
-    });
-
-    it("should format functions saved in windows style - tabs", function () {
-      var fn = [
-        "function ( )   {"
-        , "\tif (false) {"
-        , "\t\tvar json = {"
-        , '\t\t\tone : 1'
-        , '\t\t};'
-        , "\t}"
-        , "}"
-      ].join("\r\n");
-      utils.clean(fn).should.equal("if (false) {\n\tvar json = {\n\t\tone : 1\n\t};\n}");
-    });
-  });
-});
\ No newline at end of file
diff --git a/tests/lib/mocha-2.1.0/.editorconfig b/tests/lib/mocha-2.1.0/.editorconfig
new file mode 100644
index 0000000000..e3a4859eeb
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/.editorconfig
@@ -0,0 +1,18 @@
+# This file is for unifying the coding style for different editors and IDEs
+# editorconfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/tests/lib/mocha-1.17.1/.gitignore b/tests/lib/mocha-2.1.0/.gitignore
similarity index 81%
rename from tests/lib/mocha-1.17.1/.gitignore
rename to tests/lib/mocha-2.1.0/.gitignore
index 8df0ed783e..aba55e682e 100644
--- a/tests/lib/mocha-1.17.1/.gitignore
+++ b/tests/lib/mocha-2.1.0/.gitignore
@@ -2,6 +2,7 @@ coverage.html
 lib-cov
 .DS_Store
 node_modules
+test-outputs
 *.sock
 testing
 _mocha.js
@@ -10,3 +11,5 @@ my-reporter.js
 lib/browser/diff.js
 .idea
 *.iml
+*.patch
+*.diff
diff --git a/tests/lib/mocha-2.1.0/.mailmap b/tests/lib/mocha-2.1.0/.mailmap
new file mode 100644
index 0000000000..704013125b
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/.mailmap
@@ -0,0 +1 @@
+TJ Holowaychuk <tj@vision-media.ca>
\ No newline at end of file
diff --git a/tests/lib/mocha-2.1.0/.travis.yml b/tests/lib/mocha-2.1.0/.travis.yml
new file mode 100644
index 0000000000..c33b3fa3a1
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+script: travis_retry npm test
+node_js:
+- '0.11'
+- '0.10'
+- '0.8'
+notifications:
+  slack:
+    secure: Xov4Q/jpmTr6p5E/kYeC0HF1tWm0YqBWvCUbNuJiti3CtFpVmOwXEvxGFcvZNAXApEVrs1uhLZLifuL3oJ/TNdqzM5nT5jDGawPYgf8ly+fTaEiCpsRCdQhFLVqYoN671eyx7QILtre9b51SeaFVVksMrfTmvh4aKJCN01iuJm4=
diff --git a/tests/lib/mocha-2.1.0/CONTRIBUTING.md b/tests/lib/mocha-2.1.0/CONTRIBUTING.md
new file mode 100644
index 0000000000..6d172f0800
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/CONTRIBUTING.md
@@ -0,0 +1,49 @@
+# Contributing to Mocha
+
+Hi!  We could use your help.  Let us help you help us.  Or something.
+
+## General
+
+1. If you are looking for a place to begin, **please send PRs for bugfixes instead of new features**, and/or **look for issues labeled `PR PLEASE`.**
+
+2.  **Help with documentation and the wiki is always appreciated**.
+
+3.  Please **be courteous and constructive** when commenting on issues, commits, and pull requests.
+
+## Bug Reports & Issues
+
+1.  When reporting a bug, please **provide steps to reproduce**.  If possible, show code.
+  
+2.  Please **show all code in JavaScript**.  We don't all read `<insert-language-that-compiles-to-JavaScript-here>`.  If you do not, you will be asked to.
+
+3.  Because Mocha works with many third-party libraries and tools, **ensure the bug you are reporting is actually within Mocha**.
+
+4.  If you report a bug, and it is inactive for a significant amount of time, it may be closed.  **Please respond promptly to requests for more information**.
+
+## Pull Requests
+
+1. Before sending a large PR, it's recommended to **create an issue to propose the change**.  Nobody wants to write a book of code and throw it away.
+
+2.  Because Mocha should be kept as maintainable as possible, its codebase must be kept slim.  Historically, *most PRs for new features are not merged*.  New features inevitably increase the size of the codebase, and thus reduce maintainability.  Only features *deemed essential* are likely to be merged--this is at the discretion of the maintainer(s).  If your PR for a feature is not merged, this doesn't necessarily mean your PR was a bad idea, wouldn't be used, or otherwise sucks.  It just means **only essential PRs for new features are likely to be merged**. 
+
+3.  Due to the above, before creating a PR for a new feature, **create an issue to propose the feature.**
+
+4.  Please **respect existing coding conventions**, whatever those may be.
+
+5.  If your PR has been waiting in limbo for some time, it's very helpful to **rebase against master**, which will make it easier to merge.
+
+6.  Please **add tests for new code**.
+
+7.  **Always run `npm test` before sending a PR.**  If you break the tests, your PR will not be accepted until they are fixed.
+
+## Source Control
+
+1. Please **squash your commits** when sending a pull request.  If you are unfamiliar with this process, see [this guide](https://help.github.com/articles/about-git-rebase/).  If you have already pushed your changesets and are squashing thereafter, this may necessitate the use of a "force push".  Please [read the docs](http://git-scm.com/docs/git-push) before you attempt this. 
+ 
+2. Please **follow the commit message conventions [outlined here](https://medium.com/code-adventures/git-conventions-a940ee20862d).**
+
+## TL;DR
+
+**Be kind, be diligent, look before you leap into a PR, and follow common community conventions**.
+
+*- The Mocha Team*
diff --git a/tests/lib/mocha-1.17.1/History.md b/tests/lib/mocha-2.1.0/HISTORY.md
similarity index 78%
rename from tests/lib/mocha-1.17.1/History.md
rename to tests/lib/mocha-2.1.0/HISTORY.md
index db7c60f508..95f0f0f9db 100644
--- a/tests/lib/mocha-1.17.1/History.md
+++ b/tests/lib/mocha-2.1.0/HISTORY.md
@@ -1,3 +1,150 @@
+
+2.1.0 / 2014-12-23
+==================
+
+ * showDiff: don’t stringify strings
+ * Clean up unused module dependencies.
+ * Filter zero-length strings from mocha.opts
+ * only write to stdout in reporters
+ * Revert "only write to stdout in reporters"
+ * Print colored output only to a tty
+ * update summary in README.md
+ * rename Readme.md/History.md to README.md/HISTORY.md because neurotic
+ * add .mailmap to fix "git shortlog" or "git summary" output
+ * fixes #1461: nyan-reporter now respects Base.useColors, fixed bug where Base.color would not return a string when str wasn't a string.
+ * Use existing test URL builder in failed replay links
+ * modify .travis.yml: use travis_retry; closes #1449
+ * fix -t 0 behavior; closes #1446
+ * fix tests (whoops)
+ * improve diff behavior
+ * Preserve pathname when linking to individual tests
+ * Fix test
+ * Tiny typo in comments fixed
+ * after hooks now being called on failed tests when using bail, fixes #1093
+ * fix throwing undefined/null now makes tests fail, fixes #1395
+ * compiler extensions are added as watched extensions, removed non-standard extensions from watch regex, resolves #1221
+ * prefix/namespace for suite titles in markdown reporter, fixes #554
+ * fix more bad markdown in CONTRIBUTING.md
+ * fix bad markdown in CONTRIBUTING.md
+ * add setImmediate/clearImmediate to globals; closes #1435
+ * Fix buffer diffs (closes #1132, closes #1433)
+ * add a CONTRIBUTING.md.  closes #882
+ * fix intermittent build failures (maybe). closes #1407
+ * add Slack notification to .travis.yml
+ * Fix slack link
+ * Add slack room to readme
+ * Update maintainers
+ * update maintainers and contributors
+ * resolves #1393: kill children with more effort on SIGINT
+ * xunit reporter support for optionally writing to a file
+ * if a reporter has a .done method, call it before exiting
+ * add support for reporter options
+ * only write to stdout in reporters
+
+2.0.0 / 2014-10-21
+==================
+
+ * remove: support for node 0.6.x, 0.4.x
+ * fix: landing reporter with non ansi characters (#211)
+ * fix: html reporter - preserve query params when navigating to suites/tests (#1358)
+ * fix: json stream reporter add error message to failed test
+ * fix: fixes for visionmedia -> mochajs
+ * fix: use stdio, fixes node deprecation warnings (#1391)
+
+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
+==================
+
+  * fix: disabling timeouts with this.timeout(0) (#1301)
+
+1.22.1-3 / 2014-07-27
+==================
+
+  * fix: local uis and reporters (#1288)
+  * fix: building 1.21.0's changes in the browser (#1284)
+
+1.21.0 / 2014-07-23
+==================
+
+  * add: --no-timeouts option (#1262, #1268)
+  * add: --*- deprecation node flags (#1217)
+  * add: --watch-extensions argument (#1247)
+  * change: spec reporter is default (#1228)
+  * fix: diff output showing incorrect +/- (#1182)
+  * fix: diffs of circular structures (#1179)
+  * fix: re-render the progress bar when progress has changed only (#1151)
+  * fix support for environments with global and window (#1159)
+  * fix: reverting to previously defined onerror handler (#1178)
+  * fix: stringify non error objects passed to done() (#1270)
+  * fix: using local ui, reporters (#1267)
+  * fix: cleaning es6 arrows (#1176)
+  * fix: don't include attrs in failure tag for xunit (#1244)
+  * fix: fail tests that return a promise if promise is rejected w/o a reason (#1224)
+  * fix: showing failed tests in doc reporter (#1117)
+  * fix: dot reporter dots being off (#1204)
+  * fix: catch empty throws (#1219)
+  * fix: honoring timeout for sync operations (#1242)
+  * update: growl to 1.8.0
+
+1.20.1 / 2014-06-03
+==================
+
+  * update: should dev dependency to ~4.0.0 (#1231)
+
+1.20.0 / 2014-05-28
+==================
+
+  * add: filenames to suite objects (#1222)
+
+1.19.0 / 2014-05-17
+==================
+
+  * add: browser script option to package.json
+  * add: export file in Mocha.Test objects (#1174)
+  * add: add docs for wrapped node flags
+  * fix: mocha.run() to return error status in browser (#1216)
+  * fix: clean() to show failure details (#1205)
+  * fix: regex that generates html for new keyword (#1201)
+  * fix: sibling suites have inherited but separate contexts (#1164)
+
+
+1.18.2 / 2014-03-18
+==================
+
+  * fix: html runner was prevented from using #mocha as the default root el (#1162)
+
+1.18.1 / 2014-03-18
+==================
+
+  * fix: named before/after hooks in bdd, tdd, qunit interfaces (#1161)
+
+1.18.0 / 2014-03-13
+==================
+
+  * add: promise support (#329)
+  * add: named before/after hooks (#966)
+
 1.17.1 / 2014-01-22
 ==================
 
@@ -15,6 +162,7 @@
   * fix: canonicalize objects before stringifying and diffing them (#1079)
   * fix: make CR call behave like carriage return for non tty (#1087)
 
+
 1.16.2 / 2013-12-23
 ==================
 
@@ -22,11 +170,13 @@
   * fix: issue running the xunit reporter in browsers (#1068)
   * fix: issue with firefox < 3.5 (#725)
 
+
 1.16.1 / 2013-12-19
 ==================
 
   * fix: recompiled for missed changes from the last release
 
+
 1.16.0 / 2013-12-19
 ==================
 
diff --git a/tests/lib/mocha-1.17.1/LICENSE b/tests/lib/mocha-2.1.0/LICENSE
similarity index 94%
rename from tests/lib/mocha-1.17.1/LICENSE
rename to tests/lib/mocha-2.1.0/LICENSE
index 00e9a0c3cc..1c5d7fa873 100644
--- a/tests/lib/mocha-1.17.1/LICENSE
+++ b/tests/lib/mocha-2.1.0/LICENSE
@@ -1,6 +1,6 @@
 (The MIT License)
 
-Copyright (c) 2011-2013 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2011-2014 TJ Holowaychuk <tj@vision-media.ca>
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/tests/lib/mocha-1.17.1/Makefile b/tests/lib/mocha-2.1.0/Makefile
similarity index 74%
rename from tests/lib/mocha-1.17.1/Makefile
rename to tests/lib/mocha-2.1.0/Makefile
index 6c555012f3..72c4814c10 100644
--- a/tests/lib/mocha-1.17.1/Makefile
+++ b/tests/lib/mocha-2.1.0/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-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,17 +48,37 @@ test-unit:
 		--growl \
 		test/*.js
 
+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 \
+			echo 'test-failing:' ; \
+			echo "  expected 2 failing tests but saw $$failures" ; \
+			exit 1 ; \
+		fi
+
 test-compilers:
 	@./bin/mocha \
 		--reporter $(REPORTER) \
-		--compilers coffee:coffee-script,foo:./test/compiler/foo \
+		--compilers coffee:coffee-script/register,foo:./test/compiler/foo \
 		test/acceptance/test.coffee \
 		test/acceptance/test.foo
 
 test-requires:
 	@./bin/mocha \
 		--reporter $(REPORTER) \
-		--compilers coffee:coffee-script \
+		--compilers coffee:coffee-script/register \
 		--require test/acceptance/require/a.js \
 		--require test/acceptance/require/b.coffee \
 		--require test/acceptance/require/c.js \
@@ -165,4 +189,4 @@ non-tty:
 tm:
 	@open editors/$(TM_BUNDLE)
 
-.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit non-tty test-grep tm clean
+.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit non-tty test-grep test-failing tm clean
diff --git a/tests/lib/mocha-2.1.0/README.md b/tests/lib/mocha-2.1.0/README.md
new file mode 100644
index 0000000000..1a3a948936
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/README.md
@@ -0,0 +1,226 @@
+ [![Build Status](https://secure.travis-ci.org/mochajs/mocha.png)](http://travis-ci.org/mochajs/mocha)
+
+  [![Mocha test framework](http://f.cl.ly/items/3l1k0n2A1U3M1I1L210p/Screen%20Shot%202012-02-24%20at%202.21.43%20PM.png)](http://mochajs.org)
+
+  Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://mochajs.org).
+
+## Contributors
+
+```
+ project  : mocha
+ repo age : 3 years, 4 months
+ active   : 509 days
+ commits  : 1575
+ files    : 153
+ authors  :
+   977	TJ Holowaychuk          62.0%
+   132	Travis Jeffery          8.4%
+    63	Christopher Hiller      4.0%
+    31	Guillermo Rauch         2.0%
+    27	Joshua Appelman         1.7%
+    13	Attila Domokos          0.8%
+    10	John Firebaugh          0.6%
+     8	Nathan Rajlich          0.5%
+     8	Jo Liss                 0.5%
+     6	Mike Pennisi            0.4%
+     6	Brendan Nee             0.4%
+     6	James Carr              0.4%
+     5	Aaron Heckmann          0.3%
+     5	Raynos                  0.3%
+     5	Ryunosuke SATO          0.3%
+     4	hokaccha                0.3%
+     4	Jonathan Ong            0.3%
+     4	Joshua Krall            0.3%
+     4	Domenic Denicola        0.3%
+     4	Forbes Lindesay         0.3%
+     4	Xavier Antoviaque       0.3%
+     4	David da Silva          0.3%
+     3	Ariel Mashraki          0.2%
+     3	Ben Bradley             0.2%
+     3	Merrick Christensen     0.2%
+     3	Andreas Lind Petersen   0.2%
+     3	Nathan Bowser           0.2%
+     3	Cory Thomas             0.2%
+     3	Benjie Gillam           0.2%
+     3	Wil Moore III           0.2%
+     3	Ben Lindsey             0.2%
+     3	Tyson Tate              0.2%
+     3	Paul Miller             0.2%
+     3	eiji.ienaga             0.2%
+     3	Mathieu Desvé           0.2%
+     3	Jesse Dailey            0.2%
+     3	fool2fish               0.2%
+     3	Fredrik Enestad         0.2%
+     3	Sindre Sorhus           0.2%
+     3	Valentin Agachi         0.2%
+     2	jsdevel                 0.1%
+     2	Arian Stolwijk          0.1%
+     2	Juzer Ali               0.1%
+     2	David Henderson         0.1%
+     2	Justin DuJardin         0.1%
+     2	Paul Armstrong          0.1%
+     2	Pete Hawkins            0.1%
+     2	Jonas Westerlund        0.1%
+     2	Quang Van               0.1%
+     2	Simon Gaeremynck        0.1%
+     2	travis jeffery          0.1%
+     2	Dominique Quatravaux    0.1%
+     2	Jacob Wejendorp         0.1%
+     2	Shawn Krisman           0.1%
+     2	FARKAS Máté             0.1%
+     2	Konstantin Käfer        0.1%
+     2	Timo Tijhof             0.1%
+     2	Sean Lang               0.1%
+     2	Quanlong He             0.1%
+     2	Glen Mailer             0.1%
+     2	Alexander Early         0.1%
+     2	Ian Storm Taylor        0.1%
+     2	Brian Beck              0.1%
+     2	Michael Riley           0.1%
+     2	Michael Schoonmaker     0.1%
+     2	domenic                 0.1%
+     2	fcrisci                 0.1%
+     2	Buck Doyle              0.1%
+     2	Nathan Alderson         0.1%
+     1	Mal Graty               0.1%
+     1	Marc Kuo                0.1%
+     1	Matija Marohnić         0.1%
+     1	Matt Robenolt           0.1%
+     1	Matt Smith              0.1%
+     1	Matthew Shanley         0.1%
+     1	Mattias Tidlund         0.1%
+     1	Michael Jackson         0.1%
+     1	Michael Olson           0.1%
+     1	Michal Charemza         0.1%
+     1	Nathan Black            0.1%
+     1	Nick Fitzgerald         0.1%
+     1	Noshir Patel            0.1%
+     1	Panu Horsmalahti        0.1%
+     1	Phil Sung               0.1%
+     1	R56                     0.1%
+     1	Refael Ackermann        0.1%
+     1	Richard Dingwall        0.1%
+     1	Richard Knop            0.1%
+     1	Rob Wu                  0.1%
+     1	Romain Prieto           0.1%
+     1	Roman Neuhauser         0.1%
+     1	Roman Shtylman          0.1%
+     1	Russ Bradberry          0.1%
+     1	Russell Munson          0.1%
+     1	Rustem Mustafin         0.1%
+     1	Salehen Shovon Rahman   0.1%
+     1	Sasha Koss              0.1%
+     1	Seiya Konno             0.1%
+     1	Shaine Hatch            0.1%
+     1	Simon Goumaz            0.1%
+     1	Standa Opichal          0.1%
+     1	Stephen Mathieson       0.1%
+     1	Steve Mason             0.1%
+     1	Tapiwa Kelvin           0.1%
+     1	Teddy Zeenny            0.1%
+     1	Tim Ehat                0.1%
+     1	Vadim Nikitin           0.1%
+     1	Victor Costan           0.1%
+     1	Will Langstroth         0.1%
+     1	Yanis Wang              0.1%
+     1	Yuest Wang              0.1%
+     1	Zsolt Takács            0.1%
+     1	abrkn                   0.1%
+     1	airportyh               0.1%
+     1	badunk                  0.1%
+     1	claudyus                0.1%
+     1	dasilvacontin           0.1%
+     1	fengmk2                 0.1%
+     1	gaye                    0.1%
+     1	grasGendarme            0.1%
+     1	lakmeer                 0.1%
+     1	lodr                    0.1%
+     1	mrShturman              0.1%
+     1	nishigori               0.1%
+     1	omardelarosa            0.1%
+     1	qiuzuhui                0.1%
+     1	samuel goldszmidt       0.1%
+     1	sebv                    0.1%
+     1	startswithaj            0.1%
+     1	tgautier@yahoo.com      0.1%
+     1	traleig1                0.1%
+     1	vlad                    0.1%
+     1	yuitest                 0.1%
+     1	zhiyelee                0.1%
+     1	Adam Crabtree           0.1%
+     1	Andreas Brekken         0.1%
+     1	Andrew Nesbitt          0.1%
+     1	Andrey Popp             0.1%
+     1	Arnaud Brousseau        0.1%
+     1	Atsuya Takagi           0.1%
+     1	Austin Birch            0.1%
+     1	Ben Noordhuis           0.1%
+     1	Bjørge Næss             0.1%
+     1	Brian Lalor             0.1%
+     1	Brian M. Carlson        0.1%
+     1	Brian Moore             0.1%
+     1	Bryan Donovan           0.1%
+     1	C. Scott Ananian        0.1%
+     1	Casey Foster            0.1%
+     1	ChrisWren               0.1%
+     1	Connor Dunn             0.1%
+     1	Corey Butler            0.1%
+     1	Daniel Stockman         0.1%
+     1	Dave McKenna            0.1%
+     1	Denis Bardadym          0.1%
+     1	Devin Weaver            0.1%
+     1	Di Wu                   0.1%
+     1	Diogo Monteiro          0.1%
+     1	Dmitry Shirokov         0.1%
+     1	Dr. Travis Jeffery      0.1%
+     1	Fedor Indutny           0.1%
+     1	Florian Margaine        0.1%
+     1	Frederico Silva         0.1%
+     1	Fredrik Lindin          0.1%
+     1	Gareth Aye              0.1%
+     1	Gareth Murphy           0.1%
+     1	Gavin Mogan             0.1%
+     1	Giovanni Bassi          0.1%
+     1	Glen Huang              0.1%
+     1	Greg Perkins            0.1%
+     1	Harish                  0.1%
+     1	Harry Brundage          0.1%
+     1	Herman Junge            0.1%
+     1	Ian Young               0.1%
+     1	Ivan                    0.1%
+     1	JP Bochi                0.1%
+     1	Jaakko Salonen          0.1%
+     1	Jakub Nešetřil          0.1%
+     1	James Bowes             0.1%
+     1	James Lal               0.1%
+     1	Jan Kopriva             0.1%
+     1	Jason Barry             0.1%
+     1	Javier Aranda           0.1%
+     1	Jean Ponchon            0.1%
+     1	Jeff Kunkle             0.1%
+     1	Jeremy Martin           0.1%
+     1	Jimmy Cuadra            0.1%
+     1	John Doty               0.1%
+     1	Jonathan Creamer        0.1%
+     1	Jonathan Park           0.1%
+     1	Jussi Virtanen          0.1%
+     1	Katie Gengler           0.1%
+     1	Kazuhito Hokamura       0.1%
+     1	Kent C. Dodds           0.1%
+     1	Kevin Conway            0.1%
+     1	Kirill Korolyov         0.1%
+     1	Koen Punt               0.1%
+     1	Laszlo Bacsi            0.1%
+     1	Liam Newman             0.1%
+     1	Linus Unnebäck          0.1%
+     1	László Bácsi            0.1%
+     1	Maciej Małecki          0.1%
+```
+
+## Links
+
+  - [Google Group](http://groups.google.com/group/mochajs)
+  - [Wiki](https://github.com/mochajs/mocha/wiki)
+  - Mocha [Extensions and reporters](https://github.com/mochajs/mocha/wiki)
+
+Mocha also has a chat room on [Slack](https://slack.com). If you'd like to join, [shoot us an email](mailto:tj@travisjeffery.com?subject=mocha%20slack%20room%20invite) from the address you want us to invite you under and we'll happily send you an invite!
diff --git a/tests/lib/mocha-1.17.1/bin/_mocha b/tests/lib/mocha-2.1.0/bin/_mocha
similarity index 81%
rename from tests/lib/mocha-1.17.1/bin/_mocha
rename to tests/lib/mocha-2.1.0/bin/_mocha
index bea6df85f7..4948197394 100644
--- a/tests/lib/mocha-1.17.1/bin/_mocha
+++ b/tests/lib/mocha-2.1.0/bin/_mocha
@@ -5,17 +5,13 @@
  */
 
 var program = require('commander')
-  , sprintf = require('util').format
   , path = require('path')
   , fs = require('fs')
-  , glob = require('glob')
   , resolve = path.resolve
   , exists = fs.existsSync || path.existsSync
   , Mocha = require('../')
   , utils = Mocha.utils
-  , interfaces = Mocha.interfaces
   , join = path.join
-  , basename = path.basename
   , cwd = process.cwd()
   , mocha = new Mocha;
 
@@ -61,30 +57,44 @@ var images = {
 program
   .version(JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version)
   .usage('[debug] [options] [files]')
-  .option('-r, --require <name>', 'require the given module')
-  .option('-R, --reporter <name>', 'specify the reporter to use', 'dot')
-  .option('-u, --ui <name>', 'specify user-interface (bdd|tdd|exports)', 'bdd')
-  .option('-g, --grep <pattern>', 'only run tests matching <pattern>')
-  .option('-i, --invert', 'inverts --grep matches')
-  .option('-t, --timeout <ms>', 'set test-case timeout in milliseconds [2000]')
-  .option('-s, --slow <ms>', '"slow" test threshold in milliseconds [75]')
-  .option('-w, --watch', 'watch files for changes')
+  .option('-A, --async-only', "force all tests to take a callback (async)")
   .option('-c, --colors', 'force enabling of colors')
   .option('-C, --no-colors', 'force disabling of colors')
   .option('-G, --growl', 'enable growl notification support')
-  .option('-d, --debug', "enable node's debugger, synonym for node --debug")
-  .option('-b, --bail', "bail after first test failure")
-  .option('-A, --async-only', "force all tests to take a callback (async)")
+  .option('-O, --reporter-options <k=v,k2=v2,...>', 'reporter-specific options')
+  .option('-R, --reporter <name>', 'specify the reporter to use', 'spec')
   .option('-S, --sort', "sort test files")
-  .option('--recursive', 'include sub directories')
-  .option('--debug-brk', "enable node's debugger breaking on the first line")
-  .option('--globals <names>', 'allow the given comma-delimited global [names]', list, [])
+  .option('-b, --bail', "bail after first test failure")
+  .option('-d, --debug', "enable node's debugger, synonym for node --debug")
+  .option('-g, --grep <pattern>', 'only run tests matching <pattern>')
+  .option('-gc', '--expose-gc', 'expose gc extension')
+  .option('-i, --invert', 'inverts --grep matches')
+  .option('-r, --require <name>', 'require the given module')
+  .option('-s, --slow <ms>', '"slow" test threshold in milliseconds [75]')
+  .option('-t, --timeout <ms>', 'set test-case timeout in milliseconds [2000]')
+  .option('-u, --ui <name>', 'specify user-interface (bdd|tdd|exports)', 'bdd')
+  .option('-w, --watch', 'watch files for changes')
   .option('--check-leaks', 'check for global variable leaks')
-  .option('--interfaces', 'display available interfaces')
-  .option('--reporters', 'display available reporters')
   .option('--compilers <ext>:<module>,...', 'use the given module(s) to compile files', list, [])
+  .option('--debug-brk', "enable node's debugger breaking on the first line")
+  .option('--globals <names>', 'allow the given comma-delimited global [names]', list, [])
+  .option('--harmony', 'enable all harmony features (except typeof)')
+  .option('--harmony-collections', 'enable harmony collections (sets, maps, and weak maps)')
+  .option('--harmony-generators', 'enable harmony generators')
+  .option('--harmony-proxies', 'enable harmony proxies')
   .option('--inline-diffs', 'display actual/expected differences inline within each string')
+  .option('--interfaces', 'display available interfaces')
+  .option('--no-deprecation', 'silence deprecation warnings')
   .option('--no-exit', 'require a clean shutdown of the event loop: mocha will not call process.exit')
+  .option('--no-timeouts', 'disables timeouts, given implicitly with --debug')
+  .option('--opts <path>', 'specify opts path', 'test/mocha.opts')
+  .option('--prof', 'log statistical profiling information')
+  .option('--recursive', 'include sub directories')
+  .option('--reporters', 'display available reporters')
+  .option('--throw-deprecation', 'throw an exception anytime a deprecated function is used')
+  .option('--trace', 'trace function calls')
+  .option('--trace-deprecation', 'show stack traces on deprecations')
+  .option('--watch-extensions <ext>,...', 'additional extensions to monitor with --watch', list, [])
 
 program.name = 'mocha';
 
@@ -157,12 +167,19 @@ program.on('require', function(mod){
   requires.push(mod);
 });
 
-// mocha.opts support
+// --opts
+
+var optsPath = process.argv.indexOf('--opts') !== -1
+    ? process.argv[process.argv.indexOf('--opts') + 1]
+    : 'test/mocha.opts';
 
 try {
-  var opts = fs.readFileSync('test/mocha.opts', 'utf8')
+  var opts = fs.readFileSync(optsPath, 'utf8')
     .trim()
-    .split(/\s+/);
+    .split(/\s+/)
+    .filter(function(value) {
+      return value ? true : false;
+    });
 
   process.argv = process.argv
     .slice(0, 2)
@@ -179,9 +196,22 @@ program.parse(process.argv);
 
 Error.stackTraceLimit = Infinity; // TODO: config
 
+// reporter options
+
+var reporterOptions = {};
+if (program.reporterOptions !== undefined) {
+    program.reporterOptions.split(",").forEach(function(opt) {
+        var L = opt.split("=");
+        if (L.length != 2) {
+            throw new Error("invalid reporter option '" + opt + "'");
+        }
+        reporterOptions[L[0]] = L[1];
+    });
+}
+
 // reporter
 
-mocha.reporter(program.reporter);
+mocha.reporter(program.reporter, reporterOptions);
 
 // interface
 
@@ -218,6 +248,10 @@ if (program.inlineDiffs) mocha.useInlineDiffs(true);
 
 if (program.slow) mocha.suite.slow(program.slow);
 
+// --no-timeouts
+
+if (!program.timeouts) mocha.enableTimeouts(false);
+
 // --timeout
 
 if (program.timeout) mocha.suite.timeout(program.timeout);
@@ -261,27 +295,25 @@ program.compilers.forEach(function(c) {
   if (mod[0] == '.') mod = join(process.cwd(), mod);
   require(mod);
   extensions.push(ext);
+  program.watchExtensions.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
@@ -306,7 +338,8 @@ if (program.watch) {
     process.exit();
   });
 
-  var watchFiles = utils.files(cwd);
+
+  var watchFiles = utils.files(cwd, [ 'js' ].concat(program.watchExtensions));
   var runAgain = false;
 
   function loadAndRun() {
@@ -335,6 +368,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);
@@ -417,40 +452,6 @@ function stop() {
   clearInterval(play.timer);
 }
 
-/**
- * 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/tests/lib/mocha-1.17.1/bin/mocha b/tests/lib/mocha-2.1.0/bin/mocha
similarity index 69%
rename from tests/lib/mocha-1.17.1/bin/mocha
rename to tests/lib/mocha-2.1.0/bin/mocha
index 742d60779e..4ab296473c 100644
--- a/tests/lib/mocha-1.17.1/bin/mocha
+++ b/tests/lib/mocha-2.1.0/bin/mocha
@@ -14,11 +14,13 @@ process.argv.slice(2).forEach(function(arg){
   switch (flag) {
     case '-d':
       args.unshift('--debug');
+      args.push('--no-timeouts');
       break;
     case 'debug':
     case '--debug':
     case '--debug-brk':
       args.unshift(arg);
+      args.push('--no-timeouts');
       break;
     case '-gc':
     case '--expose-gc':
@@ -29,7 +31,10 @@ process.argv.slice(2).forEach(function(arg){
     case '--harmony-proxies':
     case '--harmony-collections':
     case '--harmony-generators':
+    case '--no-deprecation':
     case '--prof':
+    case '--throw-deprecation':
+    case '--trace-deprecation':
       args.unshift(arg);
       break;
     default:
@@ -39,7 +44,7 @@ process.argv.slice(2).forEach(function(arg){
   }
 });
 
-var proc = spawn(process.argv[0], args, { customFds: [0,1,2] });
+var proc = spawn(process.argv[0], args, { stdio: 'inherit' });
 proc.on('exit', function (code, signal) {
   process.on('exit', function(){
     if (signal) {
@@ -49,3 +54,10 @@ proc.on('exit', function (code, signal) {
     }
   });
 });
+
+// terminate children.
+process.on('SIGINT', function () {
+  proc.kill('SIGINT'); // calls runner.abort()
+  proc.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die.
+  process.kill(process.pid, 'SIGINT');
+});
diff --git a/tests/lib/mocha-2.1.0/bower.json b/tests/lib/mocha-2.1.0/bower.json
new file mode 100644
index 0000000000..3ec9d01958
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/bower.json
@@ -0,0 +1,47 @@
+{
+  "name": "mocha",
+  "version": "2.1.0",
+  "homepage": "http://mocha.github.io/mocha",
+  "description": "simple, flexible, fun test framework",
+  "authors": [
+    "TJ Holowaychuk <tj@vision-media.ca>",
+    "Joshua Appelman <joshua@jbna.nl>",
+    "Oleg Gaidarenko <markelog@gmail.com>",
+    "Christoffer Hallas <christoffer.hallas@gmail.com>",
+    "Christopher Hiller <chiller@badwing.com>",
+    "Travis Jeffery <tj@travisjeffery.com>",
+    "Johnathan Ong <me@jongleberry.com>",
+    "Guillermo Rauch <rauchg@gmail.com>"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/mochajs/mocha.git"
+  },
+  "main": [
+    "mocha.js",
+    "mocha.css"
+  ],
+  "ignore": [
+    "bin",
+    "editors",
+    "images",
+    "lib",
+    "support",
+    "test",
+    ".gitignore",
+    ".npmignore",
+    ".travis.yml",
+    "component.json",
+    "index.js",
+    "Makefile",
+    "package.json"
+  ],
+  "keywords": [
+    "mocha",
+    "test",
+    "bdd",
+    "tdd",
+    "tap"
+  ],
+  "license": "MIT"
+}
\ No newline at end of file
diff --git a/tests/lib/mocha-1.17.1/component.json b/tests/lib/mocha-2.1.0/component.json
similarity index 59%
rename from tests/lib/mocha-1.17.1/component.json
rename to tests/lib/mocha-2.1.0/component.json
index 1f1cc968c3..e0c07a2664 100644
--- a/tests/lib/mocha-1.17.1/component.json
+++ b/tests/lib/mocha-2.1.0/component.json
@@ -1,7 +1,7 @@
 {
   "name": "mocha",
-  "version": "1.17.1",
-  "repo": "visionmedia/mocha",
+  "version": "2.1.0",
+  "repo": "mochajs/mocha",
   "description": "simple, flexible, fun test framework",
   "keywords": [
     "mocha",
@@ -11,6 +11,10 @@
     "tap"
   ],
   "main": "mocha.js",
-  "scripts": ["mocha.js"],
-  "styles": ["mocha.css"]
-}
+  "scripts": [
+    "mocha.js"
+  ],
+  "styles": [
+    "mocha.css"
+  ]
+}
\ No newline at end of file
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - after each.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - after each.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - after each.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - after each.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - after.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - after.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - after.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - after.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - before each.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - before each.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - before each.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - before each.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - before.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - before.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - before.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - before.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - describe.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - describe.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - describe.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - describe.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - it.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - it.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/bdd - it.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/bdd - it.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_deepEqual.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_deepEqual.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_deepEqual.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_deepEqual.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_equal.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_equal.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_equal.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_equal.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_fail.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_fail.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_fail.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_fail.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_isFunction.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_isFunction.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_isFunction.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - assert_isFunction.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - setup.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - setup.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - setup.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - setup.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - suite.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - suite.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - suite.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - suite.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - teardown.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - teardown.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - teardown.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - teardown.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - test.tmSnippet b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - test.tmSnippet
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/Snippets/tdd - test.tmSnippet
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/Snippets/tdd - test.tmSnippet
diff --git a/tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/info.plist b/tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/info.plist
similarity index 100%
rename from tests/lib/mocha-1.17.1/editors/JavaScript mocha.tmbundle/info.plist
rename to tests/lib/mocha-2.1.0/editors/JavaScript mocha.tmbundle/info.plist
diff --git a/tests/lib/mocha-1.17.1/images/error.png b/tests/lib/mocha-2.1.0/images/error.png
similarity index 100%
rename from tests/lib/mocha-1.17.1/images/error.png
rename to tests/lib/mocha-2.1.0/images/error.png
diff --git a/tests/lib/mocha-1.17.1/images/ok.png b/tests/lib/mocha-2.1.0/images/ok.png
similarity index 100%
rename from tests/lib/mocha-1.17.1/images/ok.png
rename to tests/lib/mocha-2.1.0/images/ok.png
diff --git a/tests/lib/mocha-1.17.1/index.js b/tests/lib/mocha-2.1.0/index.js
similarity index 69%
rename from tests/lib/mocha-1.17.1/index.js
rename to tests/lib/mocha-2.1.0/index.js
index 507566fac2..169b271770 100644
--- a/tests/lib/mocha-1.17.1/index.js
+++ b/tests/lib/mocha-2.1.0/index.js
@@ -1,4 +1,3 @@
-
 module.exports = process.env.COV
   ? require('./lib-cov/mocha')
-  : require('./lib/mocha');
\ No newline at end of file
+  : require('./lib/mocha');
diff --git a/tests/lib/mocha-1.17.1/lib/browser/debug.js b/tests/lib/mocha-2.1.0/lib/browser/debug.js
similarity index 98%
rename from tests/lib/mocha-1.17.1/lib/browser/debug.js
rename to tests/lib/mocha-2.1.0/lib/browser/debug.js
index 03cf59234c..0d939e5c07 100644
--- a/tests/lib/mocha-1.17.1/lib/browser/debug.js
+++ b/tests/lib/mocha-2.1.0/lib/browser/debug.js
@@ -1,4 +1,3 @@
-
 module.exports = function(type){
   return function(){
   }
diff --git a/tests/lib/mocha-2.1.0/lib/browser/escape-string-regexp.js b/tests/lib/mocha-2.1.0/lib/browser/escape-string-regexp.js
new file mode 100644
index 0000000000..21a95663ed
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/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/tests/lib/mocha-1.17.1/lib/browser/events.js b/tests/lib/mocha-2.1.0/lib/browser/events.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/browser/events.js
rename to tests/lib/mocha-2.1.0/lib/browser/events.js
index cfbd072028..f708260896 100644
--- a/tests/lib/mocha-1.17.1/lib/browser/events.js
+++ b/tests/lib/mocha-2.1.0/lib/browser/events.js
@@ -1,4 +1,3 @@
-
 /**
  * Module exports.
  */
@@ -175,4 +174,4 @@ EventEmitter.prototype.emit = function (name) {
   }
 
   return true;
-};
\ No newline at end of file
+};
diff --git a/tests/lib/mocha-1.17.1/lib/browser/fs.js b/tests/lib/mocha-2.1.0/lib/browser/fs.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/browser/fs.js
rename to tests/lib/mocha-2.1.0/lib/browser/fs.js
diff --git a/tests/lib/mocha-1.17.1/lib/browser/path.js b/tests/lib/mocha-2.1.0/lib/browser/glob.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/browser/path.js
rename to tests/lib/mocha-2.1.0/lib/browser/glob.js
diff --git a/tests/lib/mocha-2.1.0/lib/browser/path.js b/tests/lib/mocha-2.1.0/lib/browser/path.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/lib/mocha-1.17.1/lib/browser/progress.js b/tests/lib/mocha-2.1.0/lib/browser/progress.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/browser/progress.js
rename to tests/lib/mocha-2.1.0/lib/browser/progress.js
diff --git a/tests/lib/mocha-1.17.1/lib/browser/tty.js b/tests/lib/mocha-2.1.0/lib/browser/tty.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/browser/tty.js
rename to tests/lib/mocha-2.1.0/lib/browser/tty.js
index 6f5f079a15..eab6388270 100644
--- a/tests/lib/mocha-1.17.1/lib/browser/tty.js
+++ b/tests/lib/mocha-2.1.0/lib/browser/tty.js
@@ -1,4 +1,3 @@
-
 exports.isatty = function(){
   return true;
 };
diff --git a/tests/lib/mocha-1.17.1/lib/context.js b/tests/lib/mocha-2.1.0/lib/context.js
similarity index 78%
rename from tests/lib/mocha-1.17.1/lib/context.js
rename to tests/lib/mocha-2.1.0/lib/context.js
index 6d6422a1ff..c983b6eb6a 100644
--- a/tests/lib/mocha-1.17.1/lib/context.js
+++ b/tests/lib/mocha-2.1.0/lib/context.js
@@ -1,4 +1,3 @@
-
 /**
  * Expose `Context`.
  */
@@ -36,10 +35,25 @@ Context.prototype.runnable = function(runnable){
  */
 
 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`.
  *
diff --git a/tests/lib/mocha-1.17.1/lib/hook.js b/tests/lib/mocha-2.1.0/lib/hook.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/hook.js
rename to tests/lib/mocha-2.1.0/lib/hook.js
index 814e7b6242..c2dc346b44 100644
--- a/tests/lib/mocha-1.17.1/lib/hook.js
+++ b/tests/lib/mocha-2.1.0/lib/hook.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-1.17.1/lib/interfaces/bdd.js b/tests/lib/mocha-2.1.0/lib/interfaces/bdd.js
similarity index 80%
rename from tests/lib/mocha-1.17.1/lib/interfaces/bdd.js
rename to tests/lib/mocha-2.1.0/lib/interfaces/bdd.js
index 3a5b1ed6fc..d212da29fa 100644
--- a/tests/lib/mocha-1.17.1/lib/interfaces/bdd.js
+++ b/tests/lib/mocha-2.1.0/lib/interfaces/bdd.js
@@ -1,11 +1,11 @@
-
 /**
  * Module dependencies.
  */
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');
+  , utils = require('../utils')
+  , escapeRe = require('escape-string-regexp');
 
 /**
  * BDD-style interface:
@@ -33,32 +33,32 @@ module.exports = function(suite){
      * Execute before running tests.
      */
 
-    context.before = function(fn){
-      suites[0].beforeAll(fn);
+    context.before = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after running tests.
      */
 
-    context.after = function(fn){
-      suites[0].afterAll(fn);
+    context.after = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
      * Execute before each test case.
      */
 
-    context.beforeEach = function(fn){
-      suites[0].beforeEach(fn);
+    context.beforeEach = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.afterEach = function(fn){
-      suites[0].afterEach(fn);
+    context.afterEach = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
@@ -69,6 +69,7 @@ module.exports = function(suite){
 
     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();
@@ -107,8 +108,9 @@ 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);
       return test;
     };
@@ -119,7 +121,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/tests/lib/mocha-1.17.1/lib/interfaces/exports.js b/tests/lib/mocha-2.1.0/lib/interfaces/exports.js
similarity index 85%
rename from tests/lib/mocha-1.17.1/lib/interfaces/exports.js
rename to tests/lib/mocha-2.1.0/lib/interfaces/exports.js
index 6b229c0ff5..95e8a07012 100644
--- a/tests/lib/mocha-1.17.1/lib/interfaces/exports.js
+++ b/tests/lib/mocha-2.1.0/lib/interfaces/exports.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -28,7 +27,7 @@ module.exports = function(suite){
 
   suite.on('require', visit);
 
-  function visit(obj) {
+  function visit(obj, file) {
     var suite;
     for (var key in obj) {
       if ('function' == typeof obj[key]) {
@@ -47,10 +46,12 @@ module.exports = function(suite){
             suites[0].afterEach(fn);
             break;
           default:
-            suites[0].addTest(new Test(key, fn));
+            var test = new Test(key, fn);
+            test.file = file;
+            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/tests/lib/mocha-1.17.1/lib/interfaces/index.js b/tests/lib/mocha-2.1.0/lib/interfaces/index.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/interfaces/index.js
rename to tests/lib/mocha-2.1.0/lib/interfaces/index.js
index f7b2655e37..4f825d15b2 100644
--- a/tests/lib/mocha-1.17.1/lib/interfaces/index.js
+++ b/tests/lib/mocha-2.1.0/lib/interfaces/index.js
@@ -1,4 +1,3 @@
-
 exports.bdd = require('./bdd');
 exports.tdd = require('./tdd');
 exports.qunit = require('./qunit');
diff --git a/tests/lib/mocha-1.17.1/lib/interfaces/qunit.js b/tests/lib/mocha-2.1.0/lib/interfaces/qunit.js
similarity index 80%
rename from tests/lib/mocha-1.17.1/lib/interfaces/qunit.js
rename to tests/lib/mocha-2.1.0/lib/interfaces/qunit.js
index 30f6748fbc..fee8ac4499 100644
--- a/tests/lib/mocha-1.17.1/lib/interfaces/qunit.js
+++ b/tests/lib/mocha-2.1.0/lib/interfaces/qunit.js
@@ -1,10 +1,10 @@
-
 /**
  * Module dependencies.
  */
 
 var Suite = require('../suite')
   , Test = require('../test')
+  , escapeRe = require('escape-string-regexp')
   , utils = require('../utils');
 
 /**
@@ -41,32 +41,32 @@ module.exports = function(suite){
      * Execute before running tests.
      */
 
-    context.before = function(fn){
-      suites[0].beforeAll(fn);
+    context.before = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after running tests.
      */
 
-    context.after = function(fn){
-      suites[0].afterAll(fn);
+    context.after = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
      * Execute before each test case.
      */
 
-    context.beforeEach = function(fn){
-      suites[0].beforeEach(fn);
+    context.beforeEach = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.afterEach = function(fn){
-      suites[0].afterEach(fn);
+    context.afterEach = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
@@ -76,6 +76,7 @@ module.exports = function(suite){
     context.suite = function(title){
       if (suites.length > 1) suites.shift();
       var suite = Suite.create(suites[0], title);
+      suite.file = file;
       suites.unshift(suite);
       return suite;
     };
@@ -97,6 +98,7 @@ module.exports = function(suite){
 
     context.test = function(title, fn){
       var test = new Test(title, fn);
+      test.file = file;
       suites[0].addTest(test);
       return test;
     };
@@ -107,7 +109,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/tests/lib/mocha-1.17.1/lib/interfaces/tdd.js b/tests/lib/mocha-2.1.0/lib/interfaces/tdd.js
similarity index 80%
rename from tests/lib/mocha-1.17.1/lib/interfaces/tdd.js
rename to tests/lib/mocha-2.1.0/lib/interfaces/tdd.js
index da5ca2c554..951fc9e1ac 100644
--- a/tests/lib/mocha-1.17.1/lib/interfaces/tdd.js
+++ b/tests/lib/mocha-2.1.0/lib/interfaces/tdd.js
@@ -1,11 +1,11 @@
-
 /**
  * Module dependencies.
  */
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');;
+  , escapeRe = require('escape-string-regexp')
+  , utils = require('../utils');
 
 /**
  * TDD-style interface:
@@ -41,32 +41,32 @@ module.exports = function(suite){
      * Execute before each test case.
      */
 
-    context.setup = function(fn){
-      suites[0].beforeEach(fn);
+    context.setup = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.teardown = function(fn){
-      suites[0].afterEach(fn);
+    context.teardown = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
      * Execute before the suite.
      */
 
-    context.suiteSetup = function(fn){
-      suites[0].beforeAll(fn);
+    context.suiteSetup = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after the suite.
      */
 
-    context.suiteTeardown = function(fn){
-      suites[0].afterAll(fn);
+    context.suiteTeardown = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
@@ -77,6 +77,7 @@ module.exports = function(suite){
 
     context.suite = function(title, fn){
       var suite = Suite.create(suites[0], title);
+      suite.file = file;
       suites.unshift(suite);
       fn.call(suite);
       suites.shift();
@@ -111,8 +112,9 @@ 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);
       return test;
     };
@@ -123,7 +125,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/tests/lib/mocha-1.17.1/lib/mocha.js b/tests/lib/mocha-2.1.0/lib/mocha.js
similarity index 82%
rename from tests/lib/mocha-1.17.1/lib/mocha.js
rename to tests/lib/mocha-2.1.0/lib/mocha.js
index 3bc9bd5450..27b45021df 100644
--- a/tests/lib/mocha-1.17.1/lib/mocha.js
+++ b/tests/lib/mocha-2.1.0/lib/mocha.js
@@ -9,6 +9,7 @@
  */
 
 var path = require('path')
+  , escapeRe = require('escape-string-regexp')
   , utils = require('./utils');
 
 /**
@@ -17,6 +18,16 @@ var path = require('path')
 
 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.
  */
@@ -49,7 +60,7 @@ function image(name) {
  * Options:
  *
  *   - `ui` name "bdd", "tdd", "exports" etc
- *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
+ *   - `reporter` reporter instance, defaults to `mocha.reporters.spec`
  *   - `globals` array of accepted globals
  *   - `timeout` timeout in milliseconds
  *   - `bail` bail on the first test failure
@@ -69,9 +80,10 @@ function Mocha(options) {
   this.suite = new exports.Suite('', new exports.Context);
   this.ui(options.ui);
   this.bail(options.bail);
-  this.reporter(options.reporter);
+  this.reporter(options.reporter, options.reporterOptions);
   if (null != options.timeout) this.timeout(options.timeout);
   this.useColors(options.useColors)
+  if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
   if (options.slow) this.slow(options.slow);
 
   this.suite.on('pre-require', function (context) {
@@ -116,17 +128,17 @@ Mocha.prototype.addFile = function(file){
 };
 
 /**
- * Set reporter to `reporter`, defaults to "dot".
+ * Set reporter to `reporter`, defaults to "spec".
  *
  * @param {String|Function} reporter name or constructor
+ * @param {Object} reporterOptions optional options
  * @api public
  */
-
-Mocha.prototype.reporter = function(reporter){
+Mocha.prototype.reporter = function(reporter, reporterOptions){
   if ('function' == typeof reporter) {
     this._reporter = reporter;
   } else {
-    reporter = reporter || 'dot';
+    reporter = reporter || 'spec';
     var _reporter;
     try { _reporter = require('./reporters/' + reporter); } catch (err) {};
     if (!_reporter) try { _reporter = require(reporter); } catch (err) {};
@@ -137,6 +149,7 @@ Mocha.prototype.reporter = function(reporter){
     if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
     this._reporter = _reporter;
   }
+  this.options.reporterOptions = reporterOptions;
   return this;
 };
 
@@ -209,7 +222,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;
 };
@@ -285,9 +298,9 @@ Mocha.prototype.globals = function(globals){
  */
 
 Mocha.prototype.useColors = function(colors){
-  this.options.useColors = arguments.length && colors != undefined
-    ? colors
-    : true;
+  if (colors !== undefined) {
+    this.options.useColors = colors;
+  }
   return this;
 };
 
@@ -332,6 +345,21 @@ Mocha.prototype.slow = function(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)
  *
@@ -344,6 +372,16 @@ Mocha.prototype.asyncOnly = function(){
   return this;
 };
 
+/**
+ * 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.
  *
@@ -356,14 +394,26 @@ Mocha.prototype.run = function(fn){
   if (this.files.length) this.loadFiles();
   var suite = this.suite;
   var options = this.options;
+  options.files = this.files;
   var runner = new exports.Runner(suite);
-  var reporter = new this._reporter(runner);
+  var reporter = new this._reporter(runner, options);
   runner.ignoreLeaks = false !== options.ignoreLeaks;
   runner.asyncOnly = options.asyncOnly;
   if (options.grep) runner.grep(options.grep, options.invert);
   if (options.globals) runner.globals(options.globals);
   if (options.growl) this._growl(runner, reporter);
-  exports.reporters.Base.useColors = options.useColors;
+  if (options.useColors !== undefined) {
+    exports.reporters.Base.useColors = options.useColors;
+  }
   exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
-  return runner.run(fn);
+
+  function done(failures) {
+      if (reporter.done) {
+          reporter.done(failures, fn);
+      } else {
+          fn(failures);
+      }
+  }
+
+  return runner.run(done);
 };
diff --git a/tests/lib/mocha-1.17.1/lib/ms.js b/tests/lib/mocha-2.1.0/lib/ms.js
similarity index 96%
rename from tests/lib/mocha-1.17.1/lib/ms.js
rename to tests/lib/mocha-2.1.0/lib/ms.js
index 4096637431..ba451fab6c 100644
--- a/tests/lib/mocha-1.17.1/lib/ms.js
+++ b/tests/lib/mocha-2.1.0/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/tests/lib/mocha-1.17.1/lib/reporters/base.js b/tests/lib/mocha-2.1.0/lib/reporters/base.js
similarity index 86%
rename from tests/lib/mocha-1.17.1/lib/reporters/base.js
rename to tests/lib/mocha-2.1.0/lib/reporters/base.js
index a0b83a648e..97b12ba5c5 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/base.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/base.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -98,7 +97,7 @@ if ('win32' == process.platform) {
  */
 
 var color = exports.color = function(type, str) {
-  if (!exports.useColors) return str;
+  if (!exports.useColors) return String(str);
   return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
 };
 
@@ -155,7 +154,7 @@ exports.cursor = {
  */
 
 exports.list = function(failures){
-  console.error();
+  console.log();
   failures.forEach(function(test, i){
     // format
     var fmt = color('error title', '  %s) %s:\n')
@@ -179,13 +178,13 @@ exports.list = function(failures){
 
     // explicitly show diff
     if (err.showDiff && sameType(actual, expected)) {
-      escape = false;
-      err.actual = actual = stringify(canonicalize(actual));
-      err.expected = expected = stringify(canonicalize(expected));
-    }
 
-    // actual / expected diff
-    if ('string' == typeof actual && 'string' == typeof expected) {
+      if ('string' !== typeof actual) {
+        escape = false;
+        err.actual = actual = utils.stringify(actual);
+        err.expected = expected = utils.stringify(expected);
+      }
+
       fmt = color('error title', '  %s) %s:\n%s') + color('error stack', '\n%s\n');
       var match = message.match(/^([^:]+): expected/);
       msg = '\n      ' + color('error message', match ? match[1] : msg);
@@ -201,7 +200,7 @@ exports.list = function(failures){
     stack = stack.slice(index ? index + 1 : index)
       .replace(/^/gm, '  ');
 
-    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+    console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
   });
 };
 
@@ -306,11 +305,10 @@ Base.prototype.epilogue = function(){
   if (stats.failures) {
     fmt = color('fail', '  %d failing');
 
-    console.error(fmt,
-      stats.failures);
+    console.log(fmt, stats.failures);
 
     Base.list(this.failures);
-    console.error();
+    console.log();
   }
 
   console.log();
@@ -330,6 +328,7 @@ function pad(str, len) {
   return Array(len - str.length + 1).join(' ') + str;
 }
 
+
 /**
  * Returns an inline diff between 2 strings with coloured ANSI output
  *
@@ -442,53 +441,6 @@ function colorLines(name, str) {
   }).join('\n');
 }
 
-/**
- * Stringify `obj`.
- *
- * @param {Object} obj
- * @return {String}
- * @api private
- */
-
-function stringify(obj) {
-  if (obj instanceof RegExp) return obj.toString();
-  return JSON.stringify(obj, null, 2);
-}
-
-/**
- * Return a new object that has the keys in sorted order.
- * @param {Object} obj
- * @return {Object}
- * @api private
- */
-
- function canonicalize(obj, stack) {
-   stack = stack || [];
-
-   if (utils.indexOf(stack, obj) !== -1) return obj;
-
-   var canonicalizedObj;
-
-   if ('[object Array]' == {}.toString.call(obj)) {
-     stack.push(obj);
-     canonicalizedObj = utils.map(obj, function(item) {
-       return canonicalize(item, stack);
-     });
-     stack.pop();
-   } else if (typeof obj === 'object' && obj !== null) {
-     stack.push(obj);
-     canonicalizedObj = {};
-     utils.forEach(utils.keys(obj).sort(), function(key) {
-       canonicalizedObj[key] = canonicalize(obj[key], stack);
-     });
-     stack.pop();
-   } else {
-     canonicalizedObj = obj;
-   }
-
-   return canonicalizedObj;
- }
-
 /**
  * Check that a / b have the same type.
  *
@@ -503,4 +455,3 @@ function sameType(a, b) {
   b = Object.prototype.toString.call(b);
   return a == b;
 }
-
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/doc.js b/tests/lib/mocha-2.1.0/lib/reporters/doc.js
similarity index 76%
rename from tests/lib/mocha-1.17.1/lib/reporters/doc.js
rename to tests/lib/mocha-2.1.0/lib/reporters/doc.js
index 2e5bf57fc4..d194eb0e69 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/doc.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/doc.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -53,4 +52,11 @@ function Doc(runner) {
     var code = utils.escape(utils.clean(test.fn.toString()));
     console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);
   });
+
+  runner.on('fail', function(test, err){
+    console.log('%s  <dt class="error">%s</dt>', indent(), utils.escape(test.title));
+    var code = utils.escape(utils.clean(test.fn.toString()));
+    console.log('%s  <dd class="error"><pre><code>%s</code></pre></dd>', indent(), code);
+    console.log('%s  <dd class="error">%s</dd>', indent(), utils.escape(err));
+  });
 }
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/dot.js b/tests/lib/mocha-2.1.0/lib/reporters/dot.js
similarity index 91%
rename from tests/lib/mocha-1.17.1/lib/reporters/dot.js
rename to tests/lib/mocha-2.1.0/lib/reporters/dot.js
index 0c298ba71d..3c7445760d 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/dot.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/dot.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -25,13 +24,14 @@ function Dot(runner) {
   var self = this
     , stats = this.stats
     , width = Base.window.width * .75 | 0
-    , n = 0;
+    , n = -1;
 
   runner.on('start', function(){
     process.stdout.write('\n  ');
   });
 
   runner.on('pending', function(test){
+    if (++n % width == 0) process.stdout.write('\n  ');
     process.stdout.write(color('pending', Base.symbols.dot));
   });
 
@@ -59,4 +59,4 @@ function Dot(runner) {
  * Inherit from `Base.prototype`.
  */
 
-Dot.prototype.__proto__ = Base.prototype;
\ No newline at end of file
+Dot.prototype.__proto__ = Base.prototype;
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/html-cov.js b/tests/lib/mocha-2.1.0/lib/reporters/html-cov.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/html-cov.js
rename to tests/lib/mocha-2.1.0/lib/reporters/html-cov.js
index bfb27ffdf6..74b46adcd9 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/html-cov.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/html-cov.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -48,4 +47,4 @@ function coverageClass(n) {
   if (n >= 50) return 'medium';
   if (n >= 25) return 'low';
   return 'terrible';
-}
\ No newline at end of file
+}
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/html.js b/tests/lib/mocha-2.1.0/lib/reporters/html.js
similarity index 92%
rename from tests/lib/mocha-1.17.1/lib/reporters/html.js
rename to tests/lib/mocha-2.1.0/lib/reporters/html.js
index 873f024d7c..31ec106106 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/html.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/html.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -42,7 +41,7 @@ var statsTemplate = '<ul id="mocha-stats">'
  * @api public
  */
 
-function HTML(runner, root) {
+function HTML(runner) {
   Base.call(this, runner);
 
   var self = this
@@ -60,8 +59,7 @@ function HTML(runner, root) {
     , stack = [report]
     , progress
     , ctx
-
-  root = root || document.getElementById('mocha');
+    , root = document.getElementById('mocha');
 
   if (canvas.getContext) {
     var ratio = window.devicePixelRatio || 1;
@@ -137,7 +135,7 @@ function HTML(runner, root) {
     } else if (test.pending) {
       var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
     } else {
-      var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
+      var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
       var str = test.err.stack || test.err.toString();
 
       // FF / Opera do not add the message
@@ -178,14 +176,23 @@ function HTML(runner, root) {
   });
 }
 
+/**
+ * Makes a URL, preserving querystring ("search") parameters.
+ * @param {string} s
+ * @returns {string} your new URL
+ */
+var makeUrl = function makeUrl(s) {
+  var search = window.location.search;
+  return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
+};
+
 /**
  * Provide suite URL
  *
  * @param {Object} [suite]
  */
-
 HTML.prototype.suiteURL = function(suite){
-  return '?grep=' + encodeURIComponent(suite.fullTitle());
+  return makeUrl(suite.fullTitle());
 };
 
 /**
@@ -195,7 +202,7 @@ HTML.prototype.suiteURL = function(suite){
  */
 
 HTML.prototype.testURL = function(test){
-  return '?grep=' + encodeURIComponent(test.fullTitle());
+  return makeUrl(test.fullTitle());
 };
 
 /**
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/index.js b/tests/lib/mocha-2.1.0/lib/reporters/index.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/index.js
rename to tests/lib/mocha-2.1.0/lib/reporters/index.js
index 1c4fccf060..87b76d904f 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/index.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/index.js
@@ -1,4 +1,3 @@
-
 exports.Base = require('./base');
 exports.Dot = require('./dot');
 exports.Doc = require('./doc');
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/json-cov.js b/tests/lib/mocha-2.1.0/lib/reporters/json-cov.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/json-cov.js
rename to tests/lib/mocha-2.1.0/lib/reporters/json-cov.js
index 73d0009377..309c0ef54a 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/json-cov.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/json-cov.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -89,7 +88,7 @@ function map(cov) {
   }
 
   return ret;
-};
+}
 
 /**
  * Map jscoverage data for a single source file
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/json-stream.js b/tests/lib/mocha-2.1.0/lib/reporters/json-stream.js
similarity index 90%
rename from tests/lib/mocha-1.17.1/lib/reporters/json-stream.js
rename to tests/lib/mocha-2.1.0/lib/reporters/json-stream.js
index 7cb8fbede7..f7c05a89c2 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/json-stream.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/json-stream.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -35,7 +34,9 @@ function List(runner) {
   });
 
   runner.on('fail', function(test, err){
-    console.log(JSON.stringify(['fail', clean(test)]));
+    test = clean(test);
+    test.err = err.message;
+    console.log(JSON.stringify(['fail', test]));
   });
 
   runner.on('end', function(){
@@ -58,4 +59,4 @@ function clean(test) {
     , fullTitle: test.fullTitle()
     , duration: test.duration
   }
-}
\ No newline at end of file
+}
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/json.js b/tests/lib/mocha-2.1.0/lib/reporters/json.js
similarity index 58%
rename from tests/lib/mocha-1.17.1/lib/reporters/json.js
rename to tests/lib/mocha-2.1.0/lib/reporters/json.js
index a699f5014a..f565506c6e 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/json.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/json.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -25,6 +24,7 @@ function JSONReporter(runner) {
   Base.call(this, runner);
 
   var tests = []
+    , pending = []
     , failures = []
     , passes = [];
 
@@ -40,14 +40,21 @@ 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)
-      , failures: failures.map(clean)
-      , passes: passes.map(clean)
+      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));
   });
 }
@@ -63,8 +70,23 @@ function JSONReporter(runner) {
 
 function clean(test) {
   return {
-      title: test.title
-    , fullTitle: test.fullTitle()
-    , duration: test.duration
+    title: test.title,
+    fullTitle: test.fullTitle(),
+    duration: test.duration,
+    err: errorJSON(test.err || {})
   }
-}
\ No newline at end of file
+}
+
+/**
+ * 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;
+}
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/landing.js b/tests/lib/mocha-2.1.0/lib/reporters/landing.js
similarity index 92%
rename from tests/lib/mocha-1.17.1/lib/reporters/landing.js
rename to tests/lib/mocha-2.1.0/lib/reporters/landing.js
index bf064f64b2..ee004a20aa 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/landing.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/landing.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -56,7 +55,7 @@ function Landing(runner) {
   }
 
   runner.on('start', function(){
-    stream.write('\n  ');
+    stream.write('\n\n\n  ');
     cursor.hide();
   });
 
@@ -73,7 +72,7 @@ function Landing(runner) {
     }
 
     // render landing strip
-    stream.write('\u001b[4F\n\n');
+    stream.write('\u001b['+(width+1)+'D\u001b[2A');
     stream.write(runway());
     stream.write('\n  ');
     stream.write(color('runway', Array(col).join('â‹…')));
@@ -94,4 +93,4 @@ function Landing(runner) {
  * Inherit from `Base.prototype`.
  */
 
-Landing.prototype.__proto__ = Base.prototype;
\ No newline at end of file
+Landing.prototype.__proto__ = Base.prototype;
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/list.js b/tests/lib/mocha-2.1.0/lib/reporters/list.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/list.js
rename to tests/lib/mocha-2.1.0/lib/reporters/list.js
index 3328e157a8..f64367a410 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/list.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/list.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/markdown.js b/tests/lib/mocha-2.1.0/lib/reporters/markdown.js
similarity index 81%
rename from tests/lib/mocha-1.17.1/lib/reporters/markdown.js
rename to tests/lib/mocha-2.1.0/lib/reporters/markdown.js
index 6383a64248..e14174c30e 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/markdown.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/markdown.js
@@ -5,6 +5,12 @@
 var Base = require('./base')
   , utils = require('../utils');
 
+/**
+ * Constants
+ */
+
+var SUITE_PREFIX = '$';
+
 /**
  * Expose `Markdown`.
  */
@@ -35,8 +41,9 @@ function Markdown(runner) {
   }
 
   function mapTOC(suite, obj) {
-    var ret = obj;
-    obj = obj[suite.title] = obj[suite.title] || { suite: suite };
+    var ret = obj,
+        key = SUITE_PREFIX + suite.title;
+    obj = obj[key] = obj[key] || { suite: suite };
     suite.suites.forEach(function(suite){
       mapTOC(suite, obj);
     });
@@ -49,11 +56,13 @@ function Markdown(runner) {
     var link;
     for (var key in obj) {
       if ('suite' == key) continue;
-      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
-      if (key) buf += Array(level).join('  ') + link;
+      if (key !== SUITE_PREFIX) {
+        link = ' - [' + key.substring(1) + ']';
+        link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+        buf += Array(level).join('  ') + link;
+      }
       buf += stringifyTOC(obj[key], level);
     }
-    --level;
     return buf;
   }
 
@@ -88,4 +97,4 @@ function Markdown(runner) {
     process.stdout.write(generateTOC(runner.suite));
     process.stdout.write(buf);
   });
-}
\ No newline at end of file
+}
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/min.js b/tests/lib/mocha-2.1.0/lib/reporters/min.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/min.js
rename to tests/lib/mocha-2.1.0/lib/reporters/min.js
index 1b6117d065..ce1a3fef12 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/min.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/min.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/nyan.js b/tests/lib/mocha-2.1.0/lib/reporters/nyan.js
similarity index 92%
rename from tests/lib/mocha-1.17.1/lib/reporters/nyan.js
rename to tests/lib/mocha-2.1.0/lib/reporters/nyan.js
index 4501f6b264..63056b1777 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/nyan.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/nyan.js
@@ -2,8 +2,7 @@
  * Module dependencies.
  */
 
-var Base = require('./base')
-  , color = Base.color;
+var Base = require('./base');
 
 /**
  * Expose `Dot`.
@@ -80,17 +79,16 @@ NyanCat.prototype.draw = function(){
 
 NyanCat.prototype.drawScoreboard = function(){
   var stats = this.stats;
-  var colors = Base.colors;
 
-  function draw(color, n) {
+  function draw(type, n) {
     write(' ');
-    write('\u001b[' + color + 'm' + n + '\u001b[0m');
+    write(Base.color(type, n));
     write('\n');
   }
 
-  draw(colors.green, stats.passes);
-  draw(colors.fail, stats.failures);
-  draw(colors.pending, stats.pending);
+  draw('green', stats.passes);
+  draw('fail', stats.failures);
+  draw('pending', stats.pending);
   write('\n');
 
   this.cursorUp(this.numberOfLines);
@@ -140,26 +138,26 @@ NyanCat.prototype.drawRainbow = function(){
 NyanCat.prototype.drawNyanCat = function() {
   var self = this;
   var startWidth = this.scoreboardWidth + this.trajectories[0].length;
-  var color = '\u001b[' + startWidth + 'C';
+  var dist = '\u001b[' + startWidth + 'C';
   var padding = '';
 
-  write(color);
+  write(dist);
   write('_,------,');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? '  ' : '   ';
   write('_|' + padding + '/\\_/\\ ');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? '_' : '__';
   var tail = self.tick ? '~' : '^';
   var face;
   write(tail + '|' + padding + this.face() + ' ');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? ' ' : '  ';
   write(padding + '""  "" ');
   write('\n');
@@ -185,7 +183,7 @@ NyanCat.prototype.face = function() {
   } else {
     return '( - .-)';
   }
-}
+};
 
 /**
  * Move cursor up `n`.
@@ -240,6 +238,8 @@ NyanCat.prototype.generateColors = function(){
  */
 
 NyanCat.prototype.rainbowify = function(str){
+  if (!Base.useColors)
+    return str;
   var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
   this.colorIndex += 1;
   return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/progress.js b/tests/lib/mocha-2.1.0/lib/reporters/progress.js
similarity index 91%
rename from tests/lib/mocha-1.17.1/lib/reporters/progress.js
rename to tests/lib/mocha-2.1.0/lib/reporters/progress.js
index 59536386cb..2debb94541 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/progress.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/progress.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -36,7 +35,8 @@ function Progress(runner, options) {
     , width = Base.window.width * .50 | 0
     , total = runner.total
     , complete = 0
-    , max = Math.max;
+    , max = Math.max
+    , lastN = -1;
 
   // default chars
   options.open = options.open || '[';
@@ -59,6 +59,12 @@ function Progress(runner, options) {
       , n = width * percent | 0
       , i = width - n;
 
+    if (lastN === n && !options.verbose) {
+      // Don't re-render the line if it hasn't changed
+      return;
+    }
+    lastN = n;
+
     cursor.CR();
     process.stdout.write('\u001b[J');
     process.stdout.write(color('progress', '  ' + options.open));
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/spec.js b/tests/lib/mocha-2.1.0/lib/reporters/spec.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/spec.js
rename to tests/lib/mocha-2.1.0/lib/reporters/spec.js
index ada25c3eae..e74f4ace7c 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/spec.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/spec.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/tap.js b/tests/lib/mocha-2.1.0/lib/reporters/tap.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/tap.js
rename to tests/lib/mocha-2.1.0/lib/reporters/tap.js
index 2bcd995baa..01a92eb076 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/tap.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/tap.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/templates/coverage.jade b/tests/lib/mocha-2.1.0/lib/reporters/templates/coverage.jade
similarity index 97%
rename from tests/lib/mocha-1.17.1/lib/reporters/templates/coverage.jade
rename to tests/lib/mocha-2.1.0/lib/reporters/templates/coverage.jade
index b78119fbc1..edd59d8864 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/templates/coverage.jade
+++ b/tests/lib/mocha-2.1.0/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/tests/lib/mocha-1.17.1/lib/reporters/templates/menu.jade b/tests/lib/mocha-2.1.0/lib/reporters/templates/menu.jade
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/reporters/templates/menu.jade
rename to tests/lib/mocha-2.1.0/lib/reporters/templates/menu.jade
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/templates/script.html b/tests/lib/mocha-2.1.0/lib/reporters/templates/script.html
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/reporters/templates/script.html
rename to tests/lib/mocha-2.1.0/lib/reporters/templates/script.html
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/templates/style.html b/tests/lib/mocha-2.1.0/lib/reporters/templates/style.html
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/reporters/templates/style.html
rename to tests/lib/mocha-2.1.0/lib/reporters/templates/style.html
index 643c0ab7b8..4b1f6826c6 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/templates/style.html
+++ b/tests/lib/mocha-2.1.0/lib/reporters/templates/style.html
@@ -317,4 +317,4 @@ code .init { color: #2F6FAD }
 code .string { color: #5890AD }
 code .keyword { color: #8A6343 }
 code .number { color: #2F6FAD }
-</style>
\ No newline at end of file
+</style>
diff --git a/tests/lib/mocha-1.17.1/lib/reporters/xunit.js b/tests/lib/mocha-2.1.0/lib/reporters/xunit.js
similarity index 62%
rename from tests/lib/mocha-1.17.1/lib/reporters/xunit.js
rename to tests/lib/mocha-2.1.0/lib/reporters/xunit.js
index e956380d8e..77cd347094 100644
--- a/tests/lib/mocha-1.17.1/lib/reporters/xunit.js
+++ b/tests/lib/mocha-2.1.0/lib/reporters/xunit.js
@@ -1,10 +1,10 @@
-
 /**
  * Module dependencies.
  */
 
 var Base = require('./base')
   , utils = require('../utils')
+  , fs = require('fs')
   , escape = utils.escape;
 
 /**
@@ -30,12 +30,19 @@ exports = module.exports = XUnit;
  * @api public
  */
 
-function XUnit(runner) {
+function XUnit(runner, options) {
   Base.call(this, runner);
   var stats = this.stats
     , tests = []
     , self = this;
 
+  if (options.reporterOptions && options.reporterOptions.output) {
+      if (! fs.createWriteStream) {
+          throw new Error('file output not supported in browser');
+      }
+      self.fileStream = fs.createWriteStream(options.reporterOptions.output);
+  }
+
   runner.on('pending', function(test){
     tests.push(test);
   });
@@ -49,7 +56,7 @@ function XUnit(runner) {
   });
 
   runner.on('end', function(){
-    console.log(tag('testsuite', {
+    self.write(tag('testsuite', {
         name: 'Mocha Tests'
       , tests: stats.tests
       , failures: stats.failures
@@ -59,22 +66,46 @@ function XUnit(runner) {
       , time: (stats.duration / 1000) || 0
     }, false));
 
-    tests.forEach(test);
-    console.log('</testsuite>');
+    tests.forEach(function(t) { self.test(t); });
+    self.write('</testsuite>');
   });
 }
 
+/**
+ * Override done to close the stream (if it's a file).
+ */
+XUnit.prototype.done = function(failures, fn) {
+    if (this.fileStream) {
+        this.fileStream.end(function() {
+            fn(failures);
+        });
+    } else {
+        fn(failures);
+    }
+};
+
 /**
  * Inherit from `Base.prototype`.
  */
 
 XUnit.prototype.__proto__ = Base.prototype;
 
+/**
+ * Write out the given line
+ */
+XUnit.prototype.write = function(line) {
+    if (this.fileStream) {
+        this.fileStream.write(line + '\n');
+    } else {
+        console.log(line);
+    }
+};
+
 /**
  * Output tag for the given `test.`
  */
 
-function test(test) {
+XUnit.prototype.test = function(test, ostream) {
   var attrs = {
       classname: test.parent.fullTitle()
     , name: test.title
@@ -83,14 +114,13 @@ function test(test) {
 
   if ('failed' == test.state) {
     var err = test.err;
-    attrs.message = escape(err.message);
-    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
+    this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
   } else if (test.pending) {
-    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
+    this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
   } else {
-    console.log(tag('testcase', attrs, true) );
+    this.write(tag('testcase', attrs, true) );
   }
-}
+};
 
 /**
  * HTML tag helper.
diff --git a/tests/lib/mocha-1.17.1/lib/runnable.js b/tests/lib/mocha-2.1.0/lib/runnable.js
similarity index 67%
rename from tests/lib/mocha-1.17.1/lib/runnable.js
rename to tests/lib/mocha-2.1.0/lib/runnable.js
index 03b8792b10..cad9dc78b2 100644
--- a/tests/lib/mocha-1.17.1/lib/runnable.js
+++ b/tests/lib/mocha-2.1.0/lib/runnable.js
@@ -1,11 +1,11 @@
-
 /**
  * Module dependencies.
  */
 
 var EventEmitter = require('events').EventEmitter
   , debug = require('debug')('mocha:runnable')
-  , milliseconds = require('./ms');
+  , milliseconds = require('./ms')
+  , utils = require('./utils');
 
 /**
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -44,7 +44,9 @@ function Runnable(title, fn) {
   this.sync = ! this.async;
   this._timeout = 2000;
   this._slow = 75;
+  this._enableTimeouts = true;
   this.timedOut = false;
+  this._trace = new Error('done() called multiple times')
 }
 
 /**
@@ -63,6 +65,7 @@ Runnable.prototype.__proto__ = EventEmitter.prototype;
 
 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;
@@ -86,6 +89,21 @@ Runnable.prototype.slow = function(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.
@@ -134,8 +152,10 @@ Runnable.prototype.resetTimeout = function(){
   var self = this;
   var ms = this.timeout() || 1e9;
 
+  if (!this._enableTimeouts) return;
   this.clearTimeout();
   this.timer = setTimeout(function(){
+    if (!self._enableTimeouts) return;
     self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
     self.timedOut = true;
   }, ms);
@@ -160,54 +180,54 @@ Runnable.prototype.globals = function(arr){
 
 Runnable.prototype.run = function(fn){
   var self = this
-    , ms = this.timeout()
     , start = new Date
     , ctx = this.ctx
     , finished
     , emitted;
 
-  if (ctx) ctx.runnable(this);
-
-  // timeout
-  if (this.async) {
-    if (ms) {
-      this.timer = setTimeout(function(){
-        done(new Error('timeout of ' + ms + 'ms exceeded'));
-        self.timedOut = true;
-      }, ms);
-    }
-  }
+  // 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'));
+    self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
   }
 
   // finished
   function done(err) {
+    var ms = self.timeout();
     if (self.timedOut) return;
-    if (finished) return multiple(err);
+    if (finished) return multiple(err || self._trace);
     self.clearTimeout();
     self.duration = new Date - start;
     finished = true;
+    if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded');
     fn(err);
   }
 
   // for .resetTimeout()
   this.callback = done;
 
-  // async
+  // 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) return done(new Error('done() invoked with non-Error: ' + 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);
+      done(utils.getError(err));
     }
     return;
   }
@@ -216,12 +236,30 @@ Runnable.prototype.run = function(fn){
     return done(new Error('--async-only option in use without declaring `done()`'));
   }
 
-  // sync
+  // sync or promise-returning
   try {
-    if (!this.pending) this.fn.call(ctx);
-    this.duration = new Date - start;
-    fn();
+    if (this.pending) {
+      done();
+    } else {
+      callFn(this.fn);
+    }
   } catch (err) {
-    fn(err);
+    done(utils.getError(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();
+    }
   }
 };
diff --git a/tests/lib/mocha-1.17.1/lib/runner.js b/tests/lib/mocha-2.1.0/lib/runner.js
similarity index 97%
rename from tests/lib/mocha-1.17.1/lib/runner.js
rename to tests/lib/mocha-2.1.0/lib/runner.js
index a604aeb582..ba02d9a53e 100644
--- a/tests/lib/mocha-1.17.1/lib/runner.js
+++ b/tests/lib/mocha-2.1.0/lib/runner.js
@@ -19,7 +19,9 @@ var globals = [
   'setInterval',
   'clearInterval',
   'XMLHttpRequest',
-  'Date'
+  'Date',
+  'setImmediate',
+  'clearImmediate'
 ];
 
 /**
@@ -161,7 +163,6 @@ Runner.prototype.checkGlobals = function(test){
   var ok = this._globals;
 
   var globals = this.globalProps();
-  var isNode = process.kill;
   var leaks;
 
   if (test) {
@@ -245,7 +246,6 @@ Runner.prototype.hook = function(name, fn){
   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;
@@ -391,6 +391,7 @@ Runner.prototype.runTests = function(suite, fn){
     , tests = suite.tests.slice()
     , test;
 
+
   function hookErr(err, errSuite, after) {
     // before/after Each hook for errSuite failed:
     var orig = self.suite;
@@ -532,13 +533,26 @@ Runner.prototype.runSuite = function(suite, fn){
  */
 
 Runner.prototype.uncaught = function(err){
-  debug('uncaught exception %s', err.message);
-  var runnable = this.currentRunnable;
-  if (!runnable || 'failed' == runnable.state) return;
-  runnable.clearTimeout();
+  if (err) {
+    debug('uncaught exception %s', err !== function () {
+      return this;
+    }.call(err) ? err : ( err.message || err ));
+  } else {
+    debug('uncaught undefined exception');
+    err = utils.undefinedError();
+  }
   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);
@@ -598,7 +612,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/tests/lib/mocha-1.17.1/lib/suite.js b/tests/lib/mocha-2.1.0/lib/suite.js
similarity index 75%
rename from tests/lib/mocha-1.17.1/lib/suite.js
rename to tests/lib/mocha-2.1.0/lib/suite.js
index 869bb88d52..65cdbffc0e 100644
--- a/tests/lib/mocha-1.17.1/lib/suite.js
+++ b/tests/lib/mocha-2.1.0/lib/suite.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -46,9 +45,11 @@ exports.create = function(parent, title){
  * @api private
  */
 
-function Suite(title, ctx) {
+function Suite(title, parentContext) {
   this.title = title;
-  this.ctx = ctx;
+  var context = function() {};
+  context.prototype = parentContext;
+  this.ctx = new context();
   this.suites = [];
   this.tests = [];
   this.pending = false;
@@ -58,6 +59,7 @@ function Suite(title, ctx) {
   this._afterAll = [];
   this.root = !title;
   this._timeout = 2000;
+  this._enableTimeouts = true;
   this._slow = 75;
   this._bail = false;
 }
@@ -80,6 +82,7 @@ Suite.prototype.clone = function(){
   debug('clone');
   suite.ctx = this.ctx;
   suite.timeout(this.timeout());
+  suite.enableTimeouts(this.enableTimeouts());
   suite.slow(this.slow());
   suite.bail(this.bail());
   return suite;
@@ -95,12 +98,28 @@ Suite.prototype.clone = function(){
 
 Suite.prototype.timeout = function(ms){
   if (0 == arguments.length) return this._timeout;
+  if (ms.toString() === '0') this._enableTimeouts = false;
   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".
  *
@@ -120,7 +139,7 @@ Suite.prototype.slow = function(ms){
 /**
  * Sets whether to bail after first error.
  *
- * @parma {Boolean} bail
+ * @param {Boolean} bail
  * @return {Suite|Number} for chaining
  * @api private
  */
@@ -140,11 +159,18 @@ Suite.prototype.bail = function(bail){
  * @api private
  */
 
-Suite.prototype.beforeAll = function(fn){
+Suite.prototype.beforeAll = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"before all" hook', fn);
+  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);
@@ -160,11 +186,18 @@ Suite.prototype.beforeAll = function(fn){
  * @api private
  */
 
-Suite.prototype.afterAll = function(fn){
+Suite.prototype.afterAll = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"after all" hook', fn);
+  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);
@@ -180,11 +213,18 @@ Suite.prototype.afterAll = function(fn){
  * @api private
  */
 
-Suite.prototype.beforeEach = function(fn){
+Suite.prototype.beforeEach = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"before each" hook', fn);
+  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);
@@ -200,11 +240,18 @@ Suite.prototype.beforeEach = function(fn){
  * @api private
  */
 
-Suite.prototype.afterEach = function(fn){
+Suite.prototype.afterEach = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"after each" hook', fn);
+  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);
@@ -223,6 +270,7 @@ Suite.prototype.afterEach = function(fn){
 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);
@@ -241,6 +289,7 @@ Suite.prototype.addSuite = function(suite){
 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);
diff --git a/tests/lib/mocha-1.17.1/lib/template.html b/tests/lib/mocha-2.1.0/lib/template.html
similarity index 100%
rename from tests/lib/mocha-1.17.1/lib/template.html
rename to tests/lib/mocha-2.1.0/lib/template.html
diff --git a/tests/lib/mocha-1.17.1/lib/test.js b/tests/lib/mocha-2.1.0/lib/test.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/lib/test.js
rename to tests/lib/mocha-2.1.0/lib/test.js
index 11773e0cc9..4a4cf63cce 100644
--- a/tests/lib/mocha-1.17.1/lib/test.js
+++ b/tests/lib/mocha-2.1.0/lib/test.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
diff --git a/tests/lib/mocha-2.1.0/lib/utils.js b/tests/lib/mocha-2.1.0/lib/utils.js
new file mode 100644
index 0000000000..c624375025
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/lib/utils.js
@@ -0,0 +1,548 @@
+/**
+ * Module dependencies.
+ */
+
+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');
+
+/**
+ * Ignored directories.
+ */
+
+var ignore = ['node_modules', '.git'];
+
+/**
+ * Escape special characters in the given string of html.
+ *
+ * @param  {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function(html){
+  return String(html)
+    .replace(/&/g, '&amp;')
+    .replace(/"/g, '&quot;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;');
+};
+
+/**
+ * Array#forEach (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @param {Object} scope
+ * @api private
+ */
+
+exports.forEach = function(arr, fn, scope){
+  for (var i = 0, l = arr.length; i < l; i++)
+    fn.call(scope, arr[i], i);
+};
+
+/**
+ * Array#map (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @param {Object} scope
+ * @api private
+ */
+
+exports.map = function(arr, fn, scope){
+  var result = [];
+  for (var i = 0, l = arr.length; i < l; i++)
+    result.push(fn.call(scope, arr[i], i));
+  return result;
+};
+
+/**
+ * Array#indexOf (<=IE8)
+ *
+ * @parma {Array} arr
+ * @param {Object} obj to find index of
+ * @param {Number} start
+ * @api private
+ */
+
+exports.indexOf = function(arr, obj, start){
+  for (var i = start || 0, l = arr.length; i < l; i++) {
+    if (arr[i] === obj)
+      return i;
+  }
+  return -1;
+};
+
+/**
+ * Array#reduce (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @param {Object} initial value
+ * @api private
+ */
+
+exports.reduce = function(arr, fn, val){
+  var rval = val;
+
+  for (var i = 0, l = arr.length; i < l; i++) {
+    rval = fn(rval, arr[i], i, arr);
+  }
+
+  return rval;
+};
+
+/**
+ * Array#filter (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.filter = function(arr, fn){
+  var ret = [];
+
+  for (var i = 0, l = arr.length; i < l; i++) {
+    var val = arr[i];
+    if (fn(val, i, arr)) ret.push(val);
+  }
+
+  return ret;
+};
+
+/**
+ * Object.keys (<=IE8)
+ *
+ * @param {Object} obj
+ * @return {Array} keys
+ * @api private
+ */
+
+exports.keys = Object.keys || function(obj) {
+  var keys = []
+    , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
+
+  for (var key in obj) {
+    if (has.call(obj, key)) {
+      keys.push(key);
+    }
+  }
+
+  return keys;
+};
+
+/**
+ * Watch the given `files` for changes
+ * and invoke `fn(file)` on modification.
+ *
+ * @param {Array} files
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.watch = function(files, fn){
+  var options = { interval: 100 };
+  files.forEach(function(file){
+    debug('file %s', file);
+    fs.watchFile(file, options, function(curr, prev){
+      if (prev.mtime < curr.mtime) fn(file);
+    });
+  });
+};
+
+/**
+ * Ignored files.
+ */
+
+function ignored(path){
+  return !~ignore.indexOf(path);
+}
+
+/**
+ * Lookup files in the given `dir`.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+exports.files = function(dir, ext, ret){
+  ret = ret || [];
+  ext = ext || ['js'];
+
+  var re = new RegExp('\\.(' + ext.join('|') + ')$');
+
+  fs.readdirSync(dir)
+  .filter(ignored)
+  .forEach(function(path){
+    path = join(dir, path);
+    if (fs.statSync(path).isDirectory()) {
+      exports.files(path, ext, ret);
+    } else if (path.match(re)) {
+      ret.push(path);
+    }
+  });
+
+  return ret;
+};
+
+/**
+ * Compute a slug from the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.slug = function(str){
+  return str
+    .toLowerCase()
+    .replace(/ +/g, '-')
+    .replace(/[^-\w]/g, '');
+};
+
+/**
+ * Strip the function definition from `str`,
+ * and re-indent for pre whitespace.
+ */
+
+exports.clean = function(str) {
+  str = str
+    .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '')
+    .replace(/^function *\(.*\) *{|\(.*\) *=> *{?/, '')
+    .replace(/\s+\}$/, '');
+
+  var spaces = str.match(/^\n?( *)/)[1].length
+    , tabs = str.match(/^\n?(\t*)/)[1].length
+    , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm');
+
+  str = str.replace(re, '');
+
+  return exports.trim(str);
+};
+
+/**
+ * Trim the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.trim = function(str){
+  return str.replace(/^\s+|\s+$/g, '');
+};
+
+/**
+ * Parse the given `qs`.
+ *
+ * @param {String} qs
+ * @return {Object}
+ * @api private
+ */
+
+exports.parseQuery = function(qs){
+  return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){
+    var i = pair.indexOf('=')
+      , key = pair.slice(0, i)
+      , val = pair.slice(++i);
+
+    obj[key] = decodeURIComponent(val);
+    return obj;
+  }, {});
+};
+
+/**
+ * Highlight the given string of `js`.
+ *
+ * @param {String} js
+ * @return {String}
+ * @api private
+ */
+
+function highlight(js) {
+  return js
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
+    .replace(/('.*?')/gm, '<span class="string">$1</span>')
+    .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
+    .replace(/(\d+)/gm, '<span class="number">$1</span>')
+    .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
+    .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
+}
+
+/**
+ * Highlight the contents of tag `name`.
+ *
+ * @param {String} name
+ * @api private
+ */
+
+exports.highlightTags = function(name) {
+  var code = document.getElementById('mocha').getElementsByTagName(name);
+  for (var i = 0, len = code.length; i < len; ++i) {
+    code[i].innerHTML = highlight(code[i].innerHTML);
+  }
+};
+
+/**
+ * If a value could have properties, and has none, this function is called, which returns
+ * a string representation of the empty value.
+ *
+ * Functions w/ no properties return `'[Function]'`
+ * Arrays w/ length === 0 return `'[]'`
+ * Objects w/ no properties return `'{}'`
+ * All else: return result of `value.toString()`
+ *
+ * @param {*} value Value to inspect
+ * @param {string} [type] The type of the value, if known.
+ * @returns {string}
+ */
+var emptyRepresentation = function emptyRepresentation(value, type) {
+  type = type || exports.type(value);
+
+  switch(type) {
+    case 'function':
+      return '[Function]';
+    case 'object':
+      return '{}';
+    case 'array':
+      return '[]';
+    default:
+      return value.toString();
+  }
+};
+
+/**
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
+ * @param {*} value Anything
+ * @example
+ * type({}) // 'object'
+ * type([]) // 'array'
+ * type(1) // 'number'
+ * type(false) // 'boolean'
+ * type(Infinity) // 'number'
+ * type(null) // 'null'
+ * type(new Date()) // 'date'
+ * type(/foo/) // 'regexp'
+ * type('type') // 'string'
+ * type(global) // 'global'
+ * @api private
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
+ * @returns {string}
+ */
+exports.type = function type(value) {
+  if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
+    return 'buffer';
+  }
+  return Object.prototype.toString.call(value)
+    .replace(/^\[.+\s(.+?)\]$/, '$1')
+    .toLowerCase();
+};
+
+/**
+ * @summary Stringify `value`.
+ * @description Different behavior depending on type of value.
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
+ * - If `value` is an *empty* object, function, or array, return result of function
+ *   {@link emptyRepresentation}.
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
+ *   JSON.stringify().
+ *
+ * @see exports.type
+ * @param {*} value
+ * @return {string}
+ * @api private
+ */
+
+exports.stringify = function(value) {
+  var prop,
+    type = exports.type(value);
+
+  if (type === 'null' || type === 'undefined') {
+    return '[' + type + ']';
+  }
+
+  if (type === 'date') {
+    return '[Date: ' + value.toISOString() + ']';
+  }
+
+  if (!~exports.indexOf(['object', 'array', 'function'], type)) {
+    return value.toString();
+  }
+
+  for (prop in value) {
+    if (value.hasOwnProperty(prop)) {
+      return JSON.stringify(exports.canonicalize(value), null, 2).replace(/,(\n|$)/g, '$1');
+    }
+  }
+
+  return emptyRepresentation(value, type);
+};
+
+/**
+ * Return if obj is a Buffer
+ * @param {Object} arg
+ * @return {Boolean}
+ * @api private
+ */
+exports.isBuffer = function (arg) {
+  return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
+};
+
+/**
+ * @summary Return a new Thing that has the keys in sorted order.  Recursive.
+ * @description If the Thing...
+ * - has already been seen, return string `'[Circular]'`
+ * - is `undefined`, return string `'[undefined]'`
+ * - is `null`, return value `null`
+ * - is some other primitive, return the value
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
+ *
+ * @param {*} value Thing to inspect.  May or may not have properties.
+ * @param {Array} [stack=[]] Stack of seen values
+ * @return {(Object|Array|Function|string|undefined)}
+ * @see {@link exports.stringify}
+ * @api private
+ */
+
+exports.canonicalize = function(value, stack) {
+  var canonicalizedObj,
+    type = exports.type(value),
+    prop,
+    withStack = function withStack(value, fn) {
+      stack.push(value);
+      fn();
+      stack.pop();
+    };
+
+  stack = stack || [];
+
+  if (exports.indexOf(stack, value) !== -1) {
+    return '[Circular]';
+  }
+
+  switch(type) {
+    case 'undefined':
+      canonicalizedObj = '[undefined]';
+      break;
+    case 'buffer':
+    case 'null':
+      canonicalizedObj = value;
+      break;
+    case 'array':
+      withStack(value, function () {
+        canonicalizedObj = exports.map(value, function (item) {
+          return exports.canonicalize(item, stack);
+        });
+      });
+      break;
+    case 'date':
+      canonicalizedObj = '[Date: ' + value.toISOString() + ']';
+      break;
+    case 'function':
+      for (prop in value) {
+        canonicalizedObj = {};
+        break;
+      }
+      if (!canonicalizedObj) {
+        canonicalizedObj = emptyRepresentation(value, type);
+        break;
+      }
+    /* falls through */
+    case 'object':
+      canonicalizedObj = canonicalizedObj || {};
+      withStack(value, function () {
+        exports.forEach(exports.keys(value).sort(), function (key) {
+          canonicalizedObj[key] = exports.canonicalize(value[key], stack);
+        });
+      });
+      break;
+    case 'number':
+    case 'boolean':
+      canonicalizedObj = value;
+      break;
+    default:
+      canonicalizedObj = value.toString();
+  }
+
+  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;
+};
+
+/**
+ * Generate an undefined error with a message warning the user.
+ *
+ * @return {Error}
+ */
+
+exports.undefinedError = function(){
+  return new Error('Caught undefined error, did you throw without specifying what?');
+};
+
+/**
+ * Generate an undefined error if `err` is not defined.
+ *
+ * @param {Error} err
+ * @return {Error}
+ */
+
+exports.getError = function(err){
+  return err || exports.undefinedError();
+};
+
diff --git a/tests/lib/mocha-1.17.1/media/logo.svg b/tests/lib/mocha-2.1.0/media/logo.svg
similarity index 72%
rename from tests/lib/mocha-1.17.1/media/logo.svg
rename to tests/lib/mocha-2.1.0/media/logo.svg
index 88d3713080..bc3cb4b5df 100644
--- a/tests/lib/mocha-1.17.1/media/logo.svg
+++ b/tests/lib/mocha-2.1.0/media/logo.svg
@@ -1,8 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 width="612px" height="792px" viewBox="0 0 612 792" enable-background="new 0 0 612 792" xml:space="preserve">
-<circle fill="#8A6343" cx="306" cy="396" r="306"/>
-<text transform="matrix(1 0 0 1 72.1431 424.7633)" fill="#FFFFFF" font-family="'HelveticaNeue'" font-size="153">mocha</text>
-</svg>
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="792px" viewBox="0 0 612 792" enable-background="new 0 0 612 792" xml:space="preserve">
+<circle fill="#8A6343" cx="306" cy="396" r="306"/>
+<text transform="matrix(1 0 0 1 72.1431 424.7633)" fill="#FFFFFF" font-family="'HelveticaNeue'" font-size="153">mocha</text>
+</svg>
diff --git a/tests/lib/mocha-1.17.1/mocha.css b/tests/lib/mocha-2.1.0/mocha.css
similarity index 100%
rename from tests/lib/mocha-1.17.1/mocha.css
rename to tests/lib/mocha-2.1.0/mocha.css
diff --git a/tests/lib/mocha-1.17.1/mocha.js b/tests/lib/mocha-2.1.0/mocha.js
similarity index 85%
rename from tests/lib/mocha-1.17.1/mocha.js
rename to tests/lib/mocha-2.1.0/mocha.js
index 5fafaa8f5a..22d1a9f324 100644
--- a/tests/lib/mocha-1.17.1/mocha.js
+++ b/tests/lib/mocha-2.1.0/mocha.js
@@ -46,8 +46,8 @@ require.relative = function (parent) {
     };
   };
 
-require.register("browser/debug.js", function(module, exports, require){
 
+require.register("browser/debug.js", function(module, exports, require){
 module.exports = function(type){
   return function(){
   }
@@ -223,7 +223,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 {
@@ -413,8 +428,22 @@ if (typeof module !== 'undefined') {
 
 }); // module: browser/diff.js
 
-require.register("browser/events.js", function(module, exports, require){
+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){
 /**
  * Module exports.
  */
@@ -592,12 +621,17 @@ EventEmitter.prototype.emit = function (name) {
 
   return true;
 };
+
 }); // module: browser/events.js
 
 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
@@ -732,7 +766,6 @@ Progress.prototype.draw = function(ctx){
 }); // module: browser/progress.js
 
 require.register("browser/tty.js", function(module, exports, require){
-
 exports.isatty = function(){
   return true;
 };
@@ -749,7 +782,6 @@ exports.getWindowSize = function(){
 }); // module: browser/tty.js
 
 require.register("context.js", function(module, exports, require){
-
 /**
  * Expose `Context`.
  */
@@ -787,10 +819,25 @@ Context.prototype.runnable = function(runnable){
  */
 
 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`.
  *
@@ -822,7 +869,6 @@ Context.prototype.inspect = function(){
 }); // module: context.js
 
 require.register("hook.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -857,6 +903,7 @@ F.prototype = Runnable.prototype;
 Hook.prototype = new F;
 Hook.prototype.constructor = Hook;
 
+
 /**
  * Get or set the test `err`.
  *
@@ -878,14 +925,14 @@ Hook.prototype.error = function(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');
+  , utils = require('../utils')
+  , escapeRe = require('browser/escape-string-regexp');
 
 /**
  * BDD-style interface:
@@ -913,32 +960,32 @@ module.exports = function(suite){
      * Execute before running tests.
      */
 
-    context.before = function(fn){
-      suites[0].beforeAll(fn);
+    context.before = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after running tests.
      */
 
-    context.after = function(fn){
-      suites[0].afterAll(fn);
+    context.after = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
      * Execute before each test case.
      */
 
-    context.beforeEach = function(fn){
-      suites[0].beforeEach(fn);
+    context.beforeEach = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.afterEach = function(fn){
-      suites[0].afterEach(fn);
+    context.afterEach = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
@@ -949,6 +996,7 @@ module.exports = function(suite){
 
     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();
@@ -987,8 +1035,9 @@ 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);
       return test;
     };
@@ -999,7 +1048,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;
     };
@@ -1019,7 +1068,6 @@ module.exports = function(suite){
 }); // module: interfaces/bdd.js
 
 require.register("interfaces/exports.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -1049,7 +1097,7 @@ module.exports = function(suite){
 
   suite.on('require', visit);
 
-  function visit(obj) {
+  function visit(obj, file) {
     var suite;
     for (var key in obj) {
       if ('function' == typeof obj[key]) {
@@ -1068,10 +1116,12 @@ module.exports = function(suite){
             suites[0].afterEach(fn);
             break;
           default:
-            suites[0].addTest(new Test(key, fn));
+            var test = new Test(key, fn);
+            test.file = file;
+            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();
@@ -1083,7 +1133,6 @@ module.exports = function(suite){
 }); // module: interfaces/exports.js
 
 require.register("interfaces/index.js", function(module, exports, require){
-
 exports.bdd = require('./bdd');
 exports.tdd = require('./tdd');
 exports.qunit = require('./qunit');
@@ -1092,13 +1141,13 @@ exports.exports = require('./exports');
 }); // module: interfaces/index.js
 
 require.register("interfaces/qunit.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
 
 var Suite = require('../suite')
   , Test = require('../test')
+  , escapeRe = require('browser/escape-string-regexp')
   , utils = require('../utils');
 
 /**
@@ -1135,32 +1184,32 @@ module.exports = function(suite){
      * Execute before running tests.
      */
 
-    context.before = function(fn){
-      suites[0].beforeAll(fn);
+    context.before = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after running tests.
      */
 
-    context.after = function(fn){
-      suites[0].afterAll(fn);
+    context.after = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
      * Execute before each test case.
      */
 
-    context.beforeEach = function(fn){
-      suites[0].beforeEach(fn);
+    context.beforeEach = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.afterEach = function(fn){
-      suites[0].afterEach(fn);
+    context.afterEach = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
@@ -1170,6 +1219,7 @@ module.exports = function(suite){
     context.suite = function(title){
       if (suites.length > 1) suites.shift();
       var suite = Suite.create(suites[0], title);
+      suite.file = file;
       suites.unshift(suite);
       return suite;
     };
@@ -1191,6 +1241,7 @@ module.exports = function(suite){
 
     context.test = function(title, fn){
       var test = new Test(title, fn);
+      test.file = file;
       suites[0].addTest(test);
       return test;
     };
@@ -1201,7 +1252,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));
     };
 
@@ -1218,14 +1269,14 @@ module.exports = function(suite){
 }); // module: interfaces/qunit.js
 
 require.register("interfaces/tdd.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
 
 var Suite = require('../suite')
   , Test = require('../test')
-  , utils = require('../utils');;
+  , escapeRe = require('browser/escape-string-regexp')
+  , utils = require('../utils');
 
 /**
  * TDD-style interface:
@@ -1261,32 +1312,32 @@ module.exports = function(suite){
      * Execute before each test case.
      */
 
-    context.setup = function(fn){
-      suites[0].beforeEach(fn);
+    context.setup = function(name, fn){
+      suites[0].beforeEach(name, fn);
     };
 
     /**
      * Execute after each test case.
      */
 
-    context.teardown = function(fn){
-      suites[0].afterEach(fn);
+    context.teardown = function(name, fn){
+      suites[0].afterEach(name, fn);
     };
 
     /**
      * Execute before the suite.
      */
 
-    context.suiteSetup = function(fn){
-      suites[0].beforeAll(fn);
+    context.suiteSetup = function(name, fn){
+      suites[0].beforeAll(name, fn);
     };
 
     /**
      * Execute after the suite.
      */
 
-    context.suiteTeardown = function(fn){
-      suites[0].afterAll(fn);
+    context.suiteTeardown = function(name, fn){
+      suites[0].afterAll(name, fn);
     };
 
     /**
@@ -1297,6 +1348,7 @@ module.exports = function(suite){
 
     context.suite = function(title, fn){
       var suite = Suite.create(suites[0], title);
+      suite.file = file;
       suites.unshift(suite);
       fn.call(suite);
       suites.shift();
@@ -1331,8 +1383,9 @@ 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);
       return test;
     };
@@ -1343,7 +1396,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));
     };
 
@@ -1371,6 +1424,7 @@ require.register("mocha.js", function(module, exports, require){
  */
 
 var path = require('browser/path')
+  , escapeRe = require('browser/escape-string-regexp')
   , utils = require('./utils');
 
 /**
@@ -1379,6 +1433,16 @@ var path = require('browser/path')
 
 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.
  */
@@ -1411,7 +1475,7 @@ function image(name) {
  * Options:
  *
  *   - `ui` name "bdd", "tdd", "exports" etc
- *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
+ *   - `reporter` reporter instance, defaults to `mocha.reporters.spec`
  *   - `globals` array of accepted globals
  *   - `timeout` timeout in milliseconds
  *   - `bail` bail on the first test failure
@@ -1431,9 +1495,10 @@ function Mocha(options) {
   this.suite = new exports.Suite('', new exports.Context);
   this.ui(options.ui);
   this.bail(options.bail);
-  this.reporter(options.reporter);
+  this.reporter(options.reporter, options.reporterOptions);
   if (null != options.timeout) this.timeout(options.timeout);
   this.useColors(options.useColors)
+  if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
   if (options.slow) this.slow(options.slow);
 
   this.suite.on('pre-require', function (context) {
@@ -1478,17 +1543,17 @@ Mocha.prototype.addFile = function(file){
 };
 
 /**
- * Set reporter to `reporter`, defaults to "dot".
+ * Set reporter to `reporter`, defaults to "spec".
  *
  * @param {String|Function} reporter name or constructor
+ * @param {Object} reporterOptions optional options
  * @api public
  */
-
-Mocha.prototype.reporter = function(reporter){
+Mocha.prototype.reporter = function(reporter, reporterOptions){
   if ('function' == typeof reporter) {
     this._reporter = reporter;
   } else {
-    reporter = reporter || 'dot';
+    reporter = reporter || 'spec';
     var _reporter;
     try { _reporter = require('./reporters/' + reporter); } catch (err) {};
     if (!_reporter) try { _reporter = require(reporter); } catch (err) {};
@@ -1499,6 +1564,7 @@ Mocha.prototype.reporter = function(reporter){
     if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
     this._reporter = _reporter;
   }
+  this.options.reporterOptions = reporterOptions;
   return this;
 };
 
@@ -1571,7 +1637,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;
 };
@@ -1647,9 +1713,9 @@ Mocha.prototype.globals = function(globals){
  */
 
 Mocha.prototype.useColors = function(colors){
-  this.options.useColors = arguments.length && colors != undefined
-    ? colors
-    : true;
+  if (colors !== undefined) {
+    this.options.useColors = colors;
+  }
   return this;
 };
 
@@ -1694,6 +1760,21 @@ Mocha.prototype.slow = function(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)
  *
@@ -1706,6 +1787,16 @@ Mocha.prototype.asyncOnly = function(){
   return this;
 };
 
+/**
+ * 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.
  *
@@ -1718,16 +1809,28 @@ Mocha.prototype.run = function(fn){
   if (this.files.length) this.loadFiles();
   var suite = this.suite;
   var options = this.options;
+  options.files = this.files;
   var runner = new exports.Runner(suite);
-  var reporter = new this._reporter(runner);
+  var reporter = new this._reporter(runner, options);
   runner.ignoreLeaks = false !== options.ignoreLeaks;
   runner.asyncOnly = options.asyncOnly;
   if (options.grep) runner.grep(options.grep, options.invert);
   if (options.globals) runner.globals(options.globals);
   if (options.growl) this._growl(runner, reporter);
-  exports.reporters.Base.useColors = options.useColors;
+  if (options.useColors !== undefined) {
+    exports.reporters.Base.useColors = options.useColors;
+  }
   exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
-  return runner.run(fn);
+
+  function done(failures) {
+      if (reporter.done) {
+          reporter.done(failures, fn);
+      } else {
+          fn(failures);
+      }
+  }
+
+  return runner.run(done);
 };
 
 }); // module: mocha.js
@@ -1759,7 +1862,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);
 };
 
 /**
@@ -1846,7 +1949,6 @@ function plural(ms, n, name) {
 }); // module: ms.js
 
 require.register("reporters/base.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -1946,7 +2048,7 @@ if ('win32' == process.platform) {
  */
 
 var color = exports.color = function(type, str) {
-  if (!exports.useColors) return str;
+  if (!exports.useColors) return String(str);
   return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
 };
 
@@ -2003,7 +2105,7 @@ exports.cursor = {
  */
 
 exports.list = function(failures){
-  console.error();
+  console.log();
   failures.forEach(function(test, i){
     // format
     var fmt = color('error title', '  %s) %s:\n')
@@ -2027,13 +2129,13 @@ exports.list = function(failures){
 
     // explicitly show diff
     if (err.showDiff && sameType(actual, expected)) {
-      escape = false;
-      err.actual = actual = stringify(canonicalize(actual));
-      err.expected = expected = stringify(canonicalize(expected));
-    }
 
-    // actual / expected diff
-    if ('string' == typeof actual && 'string' == typeof expected) {
+      if ('string' !== typeof actual) {
+        escape = false;
+        err.actual = actual = utils.stringify(actual);
+        err.expected = expected = utils.stringify(expected);
+      }
+
       fmt = color('error title', '  %s) %s:\n%s') + color('error stack', '\n%s\n');
       var match = message.match(/^([^:]+): expected/);
       msg = '\n      ' + color('error message', match ? match[1] : msg);
@@ -2049,7 +2151,7 @@ exports.list = function(failures){
     stack = stack.slice(index ? index + 1 : index)
       .replace(/^/gm, '  ');
 
-    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+    console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
   });
 };
 
@@ -2154,11 +2256,10 @@ Base.prototype.epilogue = function(){
   if (stats.failures) {
     fmt = color('fail', '  %d failing');
 
-    console.error(fmt,
-      stats.failures);
+    console.log(fmt, stats.failures);
 
     Base.list(this.failures);
-    console.error();
+    console.log();
   }
 
   console.log();
@@ -2178,6 +2279,7 @@ function pad(str, len) {
   return Array(len - str.length + 1).join(' ') + str;
 }
 
+
 /**
  * Returns an inline diff between 2 strings with coloured ANSI output
  *
@@ -2290,53 +2392,6 @@ function colorLines(name, str) {
   }).join('\n');
 }
 
-/**
- * Stringify `obj`.
- *
- * @param {Object} obj
- * @return {String}
- * @api private
- */
-
-function stringify(obj) {
-  if (obj instanceof RegExp) return obj.toString();
-  return JSON.stringify(obj, null, 2);
-}
-
-/**
- * Return a new object that has the keys in sorted order.
- * @param {Object} obj
- * @return {Object}
- * @api private
- */
-
- function canonicalize(obj, stack) {
-   stack = stack || [];
-
-   if (utils.indexOf(stack, obj) !== -1) return obj;
-
-   var canonicalizedObj;
-
-   if ('[object Array]' == {}.toString.call(obj)) {
-     stack.push(obj);
-     canonicalizedObj = utils.map(obj, function(item) {
-       return canonicalize(item, stack);
-     });
-     stack.pop();
-   } else if (typeof obj === 'object' && obj !== null) {
-     stack.push(obj);
-     canonicalizedObj = {};
-     utils.forEach(utils.keys(obj).sort(), function(key) {
-       canonicalizedObj[key] = canonicalize(obj[key], stack);
-     });
-     stack.pop();
-   } else {
-     canonicalizedObj = obj;
-   }
-
-   return canonicalizedObj;
- }
-
 /**
  * Check that a / b have the same type.
  *
@@ -2355,7 +2410,6 @@ function sameType(a, b) {
 }); // module: reporters/base.js
 
 require.register("reporters/doc.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -2410,12 +2464,18 @@ function Doc(runner) {
     var code = utils.escape(utils.clean(test.fn.toString()));
     console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);
   });
+
+  runner.on('fail', function(test, err){
+    console.log('%s  <dt class="error">%s</dt>', indent(), utils.escape(test.title));
+    var code = utils.escape(utils.clean(test.fn.toString()));
+    console.log('%s  <dd class="error"><pre><code>%s</code></pre></dd>', indent(), code);
+    console.log('%s  <dd class="error">%s</dd>', indent(), utils.escape(err));
+  });
 }
 
 }); // module: reporters/doc.js
 
 require.register("reporters/dot.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -2442,13 +2502,14 @@ function Dot(runner) {
   var self = this
     , stats = this.stats
     , width = Base.window.width * .75 | 0
-    , n = 0;
+    , n = -1;
 
   runner.on('start', function(){
     process.stdout.write('\n  ');
   });
 
   runner.on('pending', function(test){
+    if (++n % width == 0) process.stdout.write('\n  ');
     process.stdout.write(color('pending', Base.symbols.dot));
   });
 
@@ -2481,10 +2542,10 @@ F.prototype = Base.prototype;
 Dot.prototype = new F;
 Dot.prototype.constructor = Dot;
 
+
 }); // module: reporters/dot.js
 
 require.register("reporters/html-cov.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -2535,10 +2596,10 @@ function coverageClass(n) {
   if (n >= 25) return 'low';
   return 'terrible';
 }
+
 }); // module: reporters/html-cov.js
 
 require.register("reporters/html.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -2582,7 +2643,7 @@ var statsTemplate = '<ul id="mocha-stats">'
  * @api public
  */
 
-function HTML(runner, root) {
+function HTML(runner) {
   Base.call(this, runner);
 
   var self = this
@@ -2600,8 +2661,7 @@ function HTML(runner, root) {
     , stack = [report]
     , progress
     , ctx
-
-  root = root || document.getElementById('mocha');
+    , root = document.getElementById('mocha');
 
   if (canvas.getContext) {
     var ratio = window.devicePixelRatio || 1;
@@ -2677,7 +2737,7 @@ function HTML(runner, root) {
     } else if (test.pending) {
       var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
     } else {
-      var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
+      var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
       var str = test.err.stack || test.err.toString();
 
       // FF / Opera do not add the message
@@ -2718,14 +2778,23 @@ function HTML(runner, root) {
   });
 }
 
+/**
+ * Makes a URL, preserving querystring ("search") parameters.
+ * @param {string} s
+ * @returns {string} your new URL
+ */
+var makeUrl = function makeUrl(s) {
+  var search = window.location.search;
+  return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
+};
+
 /**
  * Provide suite URL
  *
  * @param {Object} [suite]
  */
-
 HTML.prototype.suiteURL = function(suite){
-  return '?grep=' + encodeURIComponent(suite.fullTitle());
+  return makeUrl(suite.fullTitle());
 };
 
 /**
@@ -2735,7 +2804,7 @@ HTML.prototype.suiteURL = function(suite){
  */
 
 HTML.prototype.testURL = function(test){
-  return '?grep=' + encodeURIComponent(test.fullTitle());
+  return makeUrl(test.fullTitle());
 };
 
 /**
@@ -2816,7 +2885,6 @@ function on(el, event, fn) {
 }); // module: reporters/html.js
 
 require.register("reporters/index.js", function(module, exports, require){
-
 exports.Base = require('./base');
 exports.Dot = require('./dot');
 exports.Doc = require('./doc');
@@ -2838,7 +2906,6 @@ exports.JSONStream = require('./json-stream');
 }); // module: reporters/index.js
 
 require.register("reporters/json-cov.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -2929,7 +2996,7 @@ function map(cov) {
   }
 
   return ret;
-};
+}
 
 /**
  * Map jscoverage data for a single source file
@@ -2995,7 +3062,6 @@ function clean(test) {
 }); // module: reporters/json-cov.js
 
 require.register("reporters/json-stream.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3032,7 +3098,9 @@ function List(runner) {
   });
 
   runner.on('fail', function(test, err){
-    console.log(JSON.stringify(['fail', clean(test)]));
+    test = clean(test);
+    test.err = err.message;
+    console.log(JSON.stringify(['fail', test]));
   });
 
   runner.on('end', function(){
@@ -3056,10 +3124,10 @@ function clean(test) {
     , duration: test.duration
   }
 }
+
 }); // module: reporters/json-stream.js
 
 require.register("reporters/json.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3086,6 +3154,7 @@ function JSONReporter(runner) {
   Base.call(this, runner);
 
   var tests = []
+    , pending = []
     , failures = []
     , passes = [];
 
@@ -3101,14 +3170,21 @@ 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)
-      , failures: failures.map(clean)
-      , passes: passes.map(clean)
+      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));
   });
 }
@@ -3124,15 +3200,30 @@ function JSONReporter(runner) {
 
 function clean(test) {
   return {
-      title: test.title
-    , fullTitle: test.fullTitle()
-    , duration: test.duration
+    title: test.title,
+    fullTitle: test.fullTitle(),
+    duration: test.duration,
+    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){
-
 /**
  * Module dependencies.
  */
@@ -3190,7 +3281,7 @@ function Landing(runner) {
   }
 
   runner.on('start', function(){
-    stream.write('\n  ');
+    stream.write('\n\n\n  ');
     cursor.hide();
   });
 
@@ -3207,7 +3298,7 @@ function Landing(runner) {
     }
 
     // render landing strip
-    stream.write('\u001b[4F\n\n');
+    stream.write('\u001b['+(width+1)+'D\u001b[2A');
     stream.write(runway());
     stream.write('\n  ');
     stream.write(color('runway', Array(col).join('â‹…')));
@@ -3233,10 +3324,10 @@ F.prototype = Base.prototype;
 Landing.prototype = new F;
 Landing.prototype.constructor = Landing;
 
+
 }); // module: reporters/landing.js
 
 require.register("reporters/list.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3304,6 +3395,7 @@ F.prototype = Base.prototype;
 List.prototype = new F;
 List.prototype.constructor = List;
 
+
 }); // module: reporters/list.js
 
 require.register("reporters/markdown.js", function(module, exports, require){
@@ -3314,6 +3406,12 @@ require.register("reporters/markdown.js", function(module, exports, require){
 var Base = require('./base')
   , utils = require('../utils');
 
+/**
+ * Constants
+ */
+
+var SUITE_PREFIX = '$';
+
 /**
  * Expose `Markdown`.
  */
@@ -3344,8 +3442,9 @@ function Markdown(runner) {
   }
 
   function mapTOC(suite, obj) {
-    var ret = obj;
-    obj = obj[suite.title] = obj[suite.title] || { suite: suite };
+    var ret = obj,
+        key = SUITE_PREFIX + suite.title;
+    obj = obj[key] = obj[key] || { suite: suite };
     suite.suites.forEach(function(suite){
       mapTOC(suite, obj);
     });
@@ -3358,11 +3457,13 @@ function Markdown(runner) {
     var link;
     for (var key in obj) {
       if ('suite' == key) continue;
-      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
-      if (key) buf += Array(level).join('  ') + link;
+      if (key !== SUITE_PREFIX) {
+        link = ' - [' + key.substring(1) + ']';
+        link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+        buf += Array(level).join('  ') + link;
+      }
       buf += stringifyTOC(obj[key], level);
     }
-    --level;
     return buf;
   }
 
@@ -3398,10 +3499,10 @@ function Markdown(runner) {
     process.stdout.write(buf);
   });
 }
+
 }); // module: reporters/markdown.js
 
 require.register("reporters/min.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3443,6 +3544,7 @@ F.prototype = Base.prototype;
 Min.prototype = new F;
 Min.prototype.constructor = Min;
 
+
 }); // module: reporters/min.js
 
 require.register("reporters/nyan.js", function(module, exports, require){
@@ -3450,8 +3552,7 @@ require.register("reporters/nyan.js", function(module, exports, require){
  * Module dependencies.
  */
 
-var Base = require('./base')
-  , color = Base.color;
+var Base = require('./base');
 
 /**
  * Expose `Dot`.
@@ -3528,17 +3629,16 @@ NyanCat.prototype.draw = function(){
 
 NyanCat.prototype.drawScoreboard = function(){
   var stats = this.stats;
-  var colors = Base.colors;
 
-  function draw(color, n) {
+  function draw(type, n) {
     write(' ');
-    write('\u001b[' + color + 'm' + n + '\u001b[0m');
+    write(Base.color(type, n));
     write('\n');
   }
 
-  draw(colors.green, stats.passes);
-  draw(colors.fail, stats.failures);
-  draw(colors.pending, stats.pending);
+  draw('green', stats.passes);
+  draw('fail', stats.failures);
+  draw('pending', stats.pending);
   write('\n');
 
   this.cursorUp(this.numberOfLines);
@@ -3588,26 +3688,26 @@ NyanCat.prototype.drawRainbow = function(){
 NyanCat.prototype.drawNyanCat = function() {
   var self = this;
   var startWidth = this.scoreboardWidth + this.trajectories[0].length;
-  var color = '\u001b[' + startWidth + 'C';
+  var dist = '\u001b[' + startWidth + 'C';
   var padding = '';
 
-  write(color);
+  write(dist);
   write('_,------,');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? '  ' : '   ';
   write('_|' + padding + '/\\_/\\ ');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? '_' : '__';
   var tail = self.tick ? '~' : '^';
   var face;
   write(tail + '|' + padding + this.face() + ' ');
   write('\n');
 
-  write(color);
+  write(dist);
   padding = self.tick ? ' ' : '  ';
   write(padding + '""  "" ');
   write('\n');
@@ -3633,7 +3733,7 @@ NyanCat.prototype.face = function() {
   } else {
     return '( - .-)';
   }
-}
+};
 
 /**
  * Move cursor up `n`.
@@ -3688,6 +3788,8 @@ NyanCat.prototype.generateColors = function(){
  */
 
 NyanCat.prototype.rainbowify = function(str){
+  if (!Base.useColors)
+    return str;
   var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
   this.colorIndex += 1;
   return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
@@ -3710,10 +3812,10 @@ F.prototype = Base.prototype;
 NyanCat.prototype = new F;
 NyanCat.prototype.constructor = NyanCat;
 
+
 }); // module: reporters/nyan.js
 
 require.register("reporters/progress.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3751,7 +3853,8 @@ function Progress(runner, options) {
     , width = Base.window.width * .50 | 0
     , total = runner.total
     , complete = 0
-    , max = Math.max;
+    , max = Math.max
+    , lastN = -1;
 
   // default chars
   options.open = options.open || '[';
@@ -3774,6 +3877,12 @@ function Progress(runner, options) {
       , n = width * percent | 0
       , i = width - n;
 
+    if (lastN === n && !options.verbose) {
+      // Don't re-render the line if it hasn't changed
+      return;
+    }
+    lastN = n;
+
     cursor.CR();
     process.stdout.write('\u001b[J');
     process.stdout.write(color('progress', '  ' + options.open));
@@ -3803,10 +3912,10 @@ F.prototype = Base.prototype;
 Progress.prototype = new F;
 Progress.prototype.constructor = Progress;
 
+
 }); // module: reporters/progress.js
 
 require.register("reporters/spec.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3893,10 +4002,10 @@ F.prototype = Base.prototype;
 Spec.prototype = new F;
 Spec.prototype.constructor = Spec;
 
+
 }); // module: reporters/spec.js
 
 require.register("reporters/tap.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -3973,13 +4082,13 @@ function title(test) {
 }); // module: reporters/tap.js
 
 require.register("reporters/xunit.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
 
 var Base = require('./base')
   , utils = require('../utils')
+  , fs = require('browser/fs')
   , escape = utils.escape;
 
 /**
@@ -4005,12 +4114,19 @@ exports = module.exports = XUnit;
  * @api public
  */
 
-function XUnit(runner) {
+function XUnit(runner, options) {
   Base.call(this, runner);
   var stats = this.stats
     , tests = []
     , self = this;
 
+  if (options.reporterOptions && options.reporterOptions.output) {
+      if (! fs.createWriteStream) {
+          throw new Error('file output not supported in browser');
+      }
+      self.fileStream = fs.createWriteStream(options.reporterOptions.output);
+  }
+
   runner.on('pending', function(test){
     tests.push(test);
   });
@@ -4024,7 +4140,7 @@ function XUnit(runner) {
   });
 
   runner.on('end', function(){
-    console.log(tag('testsuite', {
+    self.write(tag('testsuite', {
         name: 'Mocha Tests'
       , tests: stats.tests
       , failures: stats.failures
@@ -4034,11 +4150,24 @@ function XUnit(runner) {
       , time: (stats.duration / 1000) || 0
     }, false));
 
-    tests.forEach(test);
-    console.log('</testsuite>');
+    tests.forEach(function(t) { self.test(t); });
+    self.write('</testsuite>');
   });
 }
 
+/**
+ * Override done to close the stream (if it's a file).
+ */
+XUnit.prototype.done = function(failures, fn) {
+    if (this.fileStream) {
+        this.fileStream.end(function() {
+            fn(failures);
+        });
+    } else {
+        fn(failures);
+    }
+};
+
 /**
  * Inherit from `Base.prototype`.
  */
@@ -4048,11 +4177,23 @@ F.prototype = Base.prototype;
 XUnit.prototype = new F;
 XUnit.prototype.constructor = XUnit;
 
+
+/**
+ * Write out the given line
+ */
+XUnit.prototype.write = function(line) {
+    if (this.fileStream) {
+        this.fileStream.write(line + '\n');
+    } else {
+        console.log(line);
+    }
+};
+
 /**
  * Output tag for the given `test.`
  */
 
-function test(test) {
+XUnit.prototype.test = function(test, ostream) {
   var attrs = {
       classname: test.parent.fullTitle()
     , name: test.title
@@ -4061,14 +4202,13 @@ function test(test) {
 
   if ('failed' == test.state) {
     var err = test.err;
-    attrs.message = escape(err.message);
-    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
+    this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
   } else if (test.pending) {
-    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
+    this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
   } else {
-    console.log(tag('testcase', attrs, true) );
+    this.write(tag('testcase', attrs, true) );
   }
-}
+};
 
 /**
  * HTML tag helper.
@@ -4099,14 +4239,14 @@ function cdata(str) {
 }); // module: reporters/xunit.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');
+  , milliseconds = require('./ms')
+  , utils = require('./utils');
 
 /**
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -4145,7 +4285,9 @@ function Runnable(title, fn) {
   this.sync = ! this.async;
   this._timeout = 2000;
   this._slow = 75;
+  this._enableTimeouts = true;
   this.timedOut = false;
+  this._trace = new Error('done() called multiple times')
 }
 
 /**
@@ -4157,6 +4299,7 @@ F.prototype = EventEmitter.prototype;
 Runnable.prototype = new F;
 Runnable.prototype.constructor = Runnable;
 
+
 /**
  * Set & get timeout `ms`.
  *
@@ -4167,6 +4310,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;
@@ -4190,6 +4334,21 @@ Runnable.prototype.slow = function(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.
@@ -4238,8 +4397,10 @@ Runnable.prototype.resetTimeout = function(){
   var self = this;
   var ms = this.timeout() || 1e9;
 
+  if (!this._enableTimeouts) return;
   this.clearTimeout();
   this.timer = setTimeout(function(){
+    if (!self._enableTimeouts) return;
     self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
     self.timedOut = true;
   }, ms);
@@ -4264,54 +4425,54 @@ Runnable.prototype.globals = function(arr){
 
 Runnable.prototype.run = function(fn){
   var self = this
-    , ms = this.timeout()
     , start = new Date
     , ctx = this.ctx
     , finished
     , emitted;
 
-  if (ctx) ctx.runnable(this);
-
-  // timeout
-  if (this.async) {
-    if (ms) {
-      this.timer = setTimeout(function(){
-        done(new Error('timeout of ' + ms + 'ms exceeded'));
-        self.timedOut = true;
-      }, ms);
-    }
-  }
+  // 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'));
+    self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
   }
 
   // finished
   function done(err) {
+    var ms = self.timeout();
     if (self.timedOut) return;
-    if (finished) return multiple(err);
+    if (finished) return multiple(err || self._trace);
     self.clearTimeout();
     self.duration = new Date - start;
     finished = true;
+    if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded');
     fn(err);
   }
 
   // for .resetTimeout()
   this.callback = done;
 
-  // async
+  // 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) return done(new Error('done() invoked with non-Error: ' + 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);
+      done(utils.getError(err));
     }
     return;
   }
@@ -4320,13 +4481,31 @@ Runnable.prototype.run = function(fn){
     return done(new Error('--async-only option in use without declaring `done()`'));
   }
 
-  // sync
+  // sync or promise-returning
   try {
-    if (!this.pending) this.fn.call(ctx);
-    this.duration = new Date - start;
-    fn();
+    if (this.pending) {
+      done();
+    } else {
+      callFn(this.fn);
+    }
   } catch (err) {
-    fn(err);
+    done(utils.getError(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();
+    }
   }
 };
 
@@ -4354,7 +4533,9 @@ var globals = [
   'setInterval',
   'clearInterval',
   'XMLHttpRequest',
-  'Date'
+  'Date',
+  'setImmediate',
+  'clearImmediate'
 ];
 
 /**
@@ -4414,6 +4595,7 @@ 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.
@@ -4499,7 +4681,6 @@ Runner.prototype.checkGlobals = function(test){
   var ok = this._globals;
 
   var globals = this.globalProps();
-  var isNode = process.kill;
   var leaks;
 
   if (test) {
@@ -4583,7 +4764,6 @@ Runner.prototype.hook = function(name, fn){
   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;
@@ -4729,6 +4909,7 @@ Runner.prototype.runTests = function(suite, fn){
     , tests = suite.tests.slice()
     , test;
 
+
   function hookErr(err, errSuite, after) {
     // before/after Each hook for errSuite failed:
     var orig = self.suite;
@@ -4870,13 +5051,26 @@ Runner.prototype.runSuite = function(suite, fn){
  */
 
 Runner.prototype.uncaught = function(err){
-  debug('uncaught exception %s', err.message);
-  var runnable = this.currentRunnable;
-  if (!runnable || 'failed' == runnable.state) return;
-  runnable.clearTimeout();
+  if (err) {
+    debug('uncaught exception %s', err !== function () {
+      return this;
+    }.call(err) ? err : ( err.message || err ));
+  } else {
+    debug('uncaught undefined exception');
+    err = utils.undefinedError();
+  }
   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);
@@ -4936,7 +5130,7 @@ Runner.prototype.run = function(fn){
 Runner.prototype.abort = function(){
   debug('aborting');
   this._abort = true;
-}
+};
 
 /**
  * Filter leaks with the given globals flagged as `ok`.
@@ -5000,7 +5194,6 @@ function filterLeaks(ok, globals) {
 }); // module: runner.js
 
 require.register("suite.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -5048,9 +5241,11 @@ exports.create = function(parent, title){
  * @api private
  */
 
-function Suite(title, ctx) {
+function Suite(title, parentContext) {
   this.title = title;
-  this.ctx = ctx;
+  var context = function() {};
+  context.prototype = parentContext;
+  this.ctx = new context();
   this.suites = [];
   this.tests = [];
   this.pending = false;
@@ -5060,6 +5255,7 @@ function Suite(title, ctx) {
   this._afterAll = [];
   this.root = !title;
   this._timeout = 2000;
+  this._enableTimeouts = true;
   this._slow = 75;
   this._bail = false;
 }
@@ -5073,6 +5269,7 @@ F.prototype = EventEmitter.prototype;
 Suite.prototype = new F;
 Suite.prototype.constructor = Suite;
 
+
 /**
  * Return a clone of this `Suite`.
  *
@@ -5085,6 +5282,7 @@ Suite.prototype.clone = function(){
   debug('clone');
   suite.ctx = this.ctx;
   suite.timeout(this.timeout());
+  suite.enableTimeouts(this.enableTimeouts());
   suite.slow(this.slow());
   suite.bail(this.bail());
   return suite;
@@ -5100,12 +5298,28 @@ Suite.prototype.clone = function(){
 
 Suite.prototype.timeout = function(ms){
   if (0 == arguments.length) return this._timeout;
+  if (ms.toString() === '0') this._enableTimeouts = false;
   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".
  *
@@ -5125,7 +5339,7 @@ Suite.prototype.slow = function(ms){
 /**
  * Sets whether to bail after first error.
  *
- * @parma {Boolean} bail
+ * @param {Boolean} bail
  * @return {Suite|Number} for chaining
  * @api private
  */
@@ -5145,11 +5359,18 @@ Suite.prototype.bail = function(bail){
  * @api private
  */
 
-Suite.prototype.beforeAll = function(fn){
+Suite.prototype.beforeAll = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"before all" hook', fn);
+  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);
@@ -5165,11 +5386,18 @@ Suite.prototype.beforeAll = function(fn){
  * @api private
  */
 
-Suite.prototype.afterAll = function(fn){
+Suite.prototype.afterAll = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"after all" hook', fn);
+  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);
@@ -5185,11 +5413,18 @@ Suite.prototype.afterAll = function(fn){
  * @api private
  */
 
-Suite.prototype.beforeEach = function(fn){
+Suite.prototype.beforeEach = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"before each" hook', fn);
+  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);
@@ -5205,11 +5440,18 @@ Suite.prototype.beforeEach = function(fn){
  * @api private
  */
 
-Suite.prototype.afterEach = function(fn){
+Suite.prototype.afterEach = function(title, fn){
   if (this.pending) return this;
-  var hook = new Hook('"after each" hook', fn);
+  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);
@@ -5228,6 +5470,7 @@ Suite.prototype.afterEach = function(fn){
 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);
@@ -5246,6 +5489,7 @@ Suite.prototype.addSuite = function(suite){
 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);
@@ -5303,7 +5547,6 @@ Suite.prototype.eachTest = function(fn){
 }); // module: suite.js
 
 require.register("test.js", function(module, exports, require){
-
 /**
  * Module dependencies.
  */
@@ -5339,6 +5582,7 @@ F.prototype = Runnable.prototype;
 Test.prototype = new F;
 Test.prototype.constructor = Test;
 
+
 }); // module: test.js
 
 require.register("utils.js", function(module, exports, require){
@@ -5348,6 +5592,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');
 
@@ -5513,16 +5760,19 @@ function ignored(path){
  * @api private
  */
 
-exports.files = function(dir, ret){
+exports.files = function(dir, ext, ret){
   ret = ret || [];
+  ext = ext || ['js'];
+
+  var re = new RegExp('\\.(' + ext.join('|') + ')$');
 
   fs.readdirSync(dir)
   .filter(ignored)
   .forEach(function(path){
     path = join(dir, path);
     if (fs.statSync(path).isDirectory()) {
-      exports.files(path, ret);
-    } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) {
+      exports.files(path, ext, ret);
+    } else if (path.match(re)) {
       ret.push(path);
     }
   });
@@ -5553,7 +5803,7 @@ exports.slug = function(str){
 exports.clean = function(str) {
   str = str
     .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '')
-    .replace(/^function *\(.*\) *{/, '')
+    .replace(/^function *\(.*\) *{|\(.*\) *=> *{?/, '')
     .replace(/\s+\}$/, '');
 
   var spaces = str.match(/^\n?( *)/)[1].length
@@ -5565,18 +5815,6 @@ exports.clean = function(str) {
   return exports.trim(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`.
  *
@@ -5624,7 +5862,7 @@ function highlight(js) {
     .replace(/('.*?')/gm, '<span class="string">$1</span>')
     .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
     .replace(/(\d+)/gm, '<span class="number">$1</span>')
-    .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
+    .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
     .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
 }
 
@@ -5636,15 +5874,270 @@ 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);
   }
 };
 
+/**
+ * If a value could have properties, and has none, this function is called, which returns
+ * a string representation of the empty value.
+ *
+ * Functions w/ no properties return `'[Function]'`
+ * Arrays w/ length === 0 return `'[]'`
+ * Objects w/ no properties return `'{}'`
+ * All else: return result of `value.toString()`
+ *
+ * @param {*} value Value to inspect
+ * @param {string} [type] The type of the value, if known.
+ * @returns {string}
+ */
+var emptyRepresentation = function emptyRepresentation(value, type) {
+  type = type || exports.type(value);
+
+  switch(type) {
+    case 'function':
+      return '[Function]';
+    case 'object':
+      return '{}';
+    case 'array':
+      return '[]';
+    default:
+      return value.toString();
+  }
+};
+
+/**
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
+ * @param {*} value Anything
+ * @example
+ * type({}) // 'object'
+ * type([]) // 'array'
+ * type(1) // 'number'
+ * type(false) // 'boolean'
+ * type(Infinity) // 'number'
+ * type(null) // 'null'
+ * type(new Date()) // 'date'
+ * type(/foo/) // 'regexp'
+ * type('type') // 'string'
+ * type(global) // 'global'
+ * @api private
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
+ * @returns {string}
+ */
+exports.type = function type(value) {
+  if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
+    return 'buffer';
+  }
+  return Object.prototype.toString.call(value)
+    .replace(/^\[.+\s(.+?)\]$/, '$1')
+    .toLowerCase();
+};
+
+/**
+ * @summary Stringify `value`.
+ * @description Different behavior depending on type of value.
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
+ * - If `value` is an *empty* object, function, or array, return result of function
+ *   {@link emptyRepresentation}.
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
+ *   JSON.stringify().
+ *
+ * @see exports.type
+ * @param {*} value
+ * @return {string}
+ * @api private
+ */
+
+exports.stringify = function(value) {
+  var prop,
+    type = exports.type(value);
+
+  if (type === 'null' || type === 'undefined') {
+    return '[' + type + ']';
+  }
+
+  if (type === 'date') {
+    return '[Date: ' + value.toISOString() + ']';
+  }
+
+  if (!~exports.indexOf(['object', 'array', 'function'], type)) {
+    return value.toString();
+  }
+
+  for (prop in value) {
+    if (value.hasOwnProperty(prop)) {
+      return JSON.stringify(exports.canonicalize(value), null, 2).replace(/,(\n|$)/g, '$1');
+    }
+  }
+
+  return emptyRepresentation(value, type);
+};
+
+/**
+ * Return if obj is a Buffer
+ * @param {Object} arg
+ * @return {Boolean}
+ * @api private
+ */
+exports.isBuffer = function (arg) {
+  return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
+};
+
+/**
+ * @summary Return a new Thing that has the keys in sorted order.  Recursive.
+ * @description If the Thing...
+ * - has already been seen, return string `'[Circular]'`
+ * - is `undefined`, return string `'[undefined]'`
+ * - is `null`, return value `null`
+ * - is some other primitive, return the value
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
+ *
+ * @param {*} value Thing to inspect.  May or may not have properties.
+ * @param {Array} [stack=[]] Stack of seen values
+ * @return {(Object|Array|Function|string|undefined)}
+ * @see {@link exports.stringify}
+ * @api private
+ */
+
+exports.canonicalize = function(value, stack) {
+  var canonicalizedObj,
+    type = exports.type(value),
+    prop,
+    withStack = function withStack(value, fn) {
+      stack.push(value);
+      fn();
+      stack.pop();
+    };
+
+  stack = stack || [];
+
+  if (exports.indexOf(stack, value) !== -1) {
+    return '[Circular]';
+  }
+
+  switch(type) {
+    case 'undefined':
+      canonicalizedObj = '[undefined]';
+      break;
+    case 'buffer':
+    case 'null':
+      canonicalizedObj = value;
+      break;
+    case 'array':
+      withStack(value, function () {
+        canonicalizedObj = exports.map(value, function (item) {
+          return exports.canonicalize(item, stack);
+        });
+      });
+      break;
+    case 'date':
+      canonicalizedObj = '[Date: ' + value.toISOString() + ']';
+      break;
+    case 'function':
+      for (prop in value) {
+        canonicalizedObj = {};
+        break;
+      }
+      if (!canonicalizedObj) {
+        canonicalizedObj = emptyRepresentation(value, type);
+        break;
+      }
+    /* falls through */
+    case 'object':
+      canonicalizedObj = canonicalizedObj || {};
+      withStack(value, function () {
+        exports.forEach(exports.keys(value).sort(), function (key) {
+          canonicalizedObj[key] = exports.canonicalize(value[key], stack);
+        });
+      });
+      break;
+    case 'number':
+    case 'boolean':
+      canonicalizedObj = value;
+      break;
+    default:
+      canonicalizedObj = value.toString();
+  }
+
+  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;
+};
+
+/**
+ * Generate an undefined error with a message warning the user.
+ *
+ * @return {Error}
+ */
+
+exports.undefinedError = function(){
+  return new Error('Caught undefined error, did you throw without specifying what?');
+};
+
+/**
+ * Generate an undefined error if `err` is not defined.
+ *
+ * @param {Error} err
+ * @return {Error}
+ */
+
+exports.getError = function(err){
+  return err || exports.undefinedError();
+};
+
+
 }); // module: utils.js
 // The global object is "self" in Web Workers.
-global = (function() { return this; })();
+var global = (function() { return this; })();
 
 /**
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -5671,13 +6164,20 @@ process.stdout = {};
 
 var uncaughtExceptionHandlers = [];
 
+var originalOnerrorHandler = global.onerror;
+
 /**
  * Remove uncaughtException listener.
+ * Revert to original onerror handler if previously defined.
  */
 
 process.removeListener = function(e, fn){
   if ('uncaughtException' == e) {
-    global.onerror = function() {};
+    if (originalOnerrorHandler) {
+      global.onerror = originalOnerrorHandler;
+    } else {
+      global.onerror = function() {};
+    }
     var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn);
     if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); }
   }
@@ -5780,12 +6280,13 @@ mocha.run = function(fn){
   if (query.grep) mocha.grep(query.grep);
   if (query.invert) mocha.invert();
 
-  return Mocha.prototype.run.call(mocha, function(){
+  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();
+    if (fn) fn(err);
   });
 };
 
@@ -5794,4 +6295,4 @@ mocha.run = function(fn){
  */
 
 Mocha.process = process;
-})();
\ No newline at end of file
+})();
diff --git a/tests/lib/mocha-2.1.0/package.json b/tests/lib/mocha-2.1.0/package.json
new file mode 100644
index 0000000000..8c4a148b47
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/package.json
@@ -0,0 +1,73 @@
+{
+  "name": "mocha",
+  "version": "2.1.0",
+  "description": "simple, flexible, fun test framework",
+  "keywords": [
+    "mocha",
+    "test",
+    "bdd",
+    "tdd",
+    "tap"
+  ],
+  "author": "TJ Holowaychuk <tj@vision-media.ca>",
+  "contributors": [
+    "Joshua Appelman <joshua@jbna.nl>",
+    "Oleg Gaidarenko <markelog@gmail.com>",
+    "Christoffer Hallas <christoffer.hallas@gmail.com>",
+    "Christopher Hiller <chiller@badwing.com>",
+    "Travis Jeffery <tj@travisjeffery.com>",
+    "Johnathan Ong <me@jongleberry.com>",
+    "Guillermo Rauch <rauchg@gmail.com>",
+    "Nathan Rajlich <nathan@tootallnate.net>"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/mochajs/mocha.git"
+  },
+  "maintainers": [
+    "travisjeffery <tj@travisjeffery.com>",
+    "jbnicolai <joshua@jbna.nl>",
+    "boneskull <chiller@badwing.com>"
+  ],
+  "main": "./index",
+  "browser": "./mocha.js",
+  "bin": {
+    "mocha": "./bin/mocha",
+    "_mocha": "./bin/_mocha"
+  },
+  "engines": {
+    "node": ">= 0.8.x"
+  },
+  "scripts": {
+    "test": "make test-all"
+  },
+  "dependencies": {
+    "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",
+    "mkdirp": "0.5.0"
+  },
+  "devDependencies": {
+    "coffee-script": "~1.8.0",
+    "should": "~4.0.0"
+  },
+  "files": [
+    "bin",
+    "images",
+    "lib",
+    "index.js",
+    "mocha.css",
+    "mocha.js",
+    "LICENSE"
+  ],
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://raw.github.com/mochajs/mocha/master/LICENSE"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/lib/mocha-1.17.1/support/compile.js b/tests/lib/mocha-2.1.0/support/compile.js
similarity index 82%
rename from tests/lib/mocha-1.17.1/support/compile.js
rename to tests/lib/mocha-2.1.0/support/compile.js
index 39a53222e9..bea017ab51 100644
--- a/tests/lib/mocha-1.17.1/support/compile.js
+++ b/tests/lib/mocha-2.1.0/support/compile.js
@@ -1,4 +1,3 @@
-
 /**
  * Module dependencies.
  */
@@ -43,12 +42,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/tests/lib/mocha-2.1.0/support/foot.js b/tests/lib/mocha-2.1.0/support/foot.js
new file mode 100644
index 0000000000..0319a0fe5f
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/support/foot.js
@@ -0,0 +1 @@
+})();
diff --git a/tests/lib/mocha-1.17.1/support/head.js b/tests/lib/mocha-2.1.0/support/head.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/support/head.js
rename to tests/lib/mocha-2.1.0/support/head.js
diff --git a/tests/lib/mocha-1.17.1/support/tail.js b/tests/lib/mocha-2.1.0/support/tail.js
similarity index 87%
rename from tests/lib/mocha-1.17.1/support/tail.js
rename to tests/lib/mocha-2.1.0/support/tail.js
index 018add8d0c..e9c0c0d22f 100644
--- a/tests/lib/mocha-1.17.1/support/tail.js
+++ b/tests/lib/mocha-2.1.0/support/tail.js
@@ -1,5 +1,5 @@
 // The global object is "self" in Web Workers.
-global = (function() { return this; })();
+var global = (function() { return this; })();
 
 /**
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -26,13 +26,20 @@ process.stdout = {};
 
 var uncaughtExceptionHandlers = [];
 
+var originalOnerrorHandler = global.onerror;
+
 /**
  * Remove uncaughtException listener.
+ * Revert to original onerror handler if previously defined.
  */
 
 process.removeListener = function(e, fn){
   if ('uncaughtException' == e) {
-    global.onerror = function() {};
+    if (originalOnerrorHandler) {
+      global.onerror = originalOnerrorHandler;
+    } else {
+      global.onerror = function() {};
+    }
     var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn);
     if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); }
   }
@@ -135,12 +142,13 @@ mocha.run = function(fn){
   if (query.grep) mocha.grep(query.grep);
   if (query.invert) mocha.invert();
 
-  return Mocha.prototype.run.call(mocha, function(){
+  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();
+    if (fn) fn(err);
   });
 };
 
diff --git a/tests/lib/mocha-2.1.0/test/acceptance/context.js b/tests/lib/mocha-2.1.0/test/acceptance/context.js
new file mode 100644
index 0000000000..47c2db7083
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/acceptance/context.js
@@ -0,0 +1,72 @@
+describe('Context', function(){
+  beforeEach(function(){
+    this.calls = ['before'];
+  })
+
+  describe('nested', function(){
+    beforeEach(function(){
+      this.calls.push('before two');
+    })
+
+    it('should work', function(){
+      this.calls.should.eql(['before', 'before two']);
+      this.calls.push('test');
+    })
+
+    after(function(){
+      this.calls.should.eql(['before', 'before two', 'test']);
+      this.calls.push('after two');
+    })
+  })
+
+  after(function(){
+    this.calls.should.eql(['before', 'before two', 'test', 'after two']);
+  })
+})
+
+describe('Context Siblings', function(){
+  beforeEach(function(){
+    this.calls = ['before'];
+  })
+
+  describe('sequestered sibling', function(){
+    beforeEach(function(){
+      this.calls.push('before two');
+      this.hiddenFromSibling = 'This should be hidden';
+    })
+
+    it('should work', function(){
+      this.hiddenFromSibling.should.eql('This should be hidden')
+    })
+  })
+
+  describe('sibling verifiction', function(){
+    beforeEach(function(){
+      this.calls.push('before sibling');
+    })
+
+    it('should not have value set within a sibling describe', function(){
+      'This should be hidden'.should.not.eql(this.hiddenFromSibling);
+      this.visibleFromTestSibling = 'Visible from test sibling';
+    })
+
+    it('should allow test siblings to modify shared context', function(){
+      'Visible from test sibling'.should.eql(this.visibleFromTestSibling);
+    })
+
+    it('should have reset this.calls before describe', function(){
+      this.calls.should.eql(['before', 'before sibling']);
+    })
+  })
+
+  after(function(){
+    this.calls.should.eql(['before', 'before sibling']);
+  })
+
+})
+
+describe('timeout()', function(){
+  it('should return the timeout', function(){
+    this.timeout().should.equal(200);
+  });
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/diffs.js b/tests/lib/mocha-2.1.0/test/acceptance/diffs.js
similarity index 86%
rename from tests/lib/mocha-1.17.1/test/acceptance/diffs.js
rename to tests/lib/mocha-2.1.0/test/acceptance/diffs.js
index 17c3dfa470..c87ffe0cce 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/diffs.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/diffs.js
@@ -1,4 +1,3 @@
-
 var fs = require('fs')
   , cssin = fs.readFileSync('test/acceptance/fixtures/css.in', 'ascii')
   , cssout = fs.readFileSync('test/acceptance/fixtures/css.out', 'ascii');
@@ -77,4 +76,18 @@ describe('diffs', function(){
 
     // tobi.should.eql(loki);
   });
+
+  it('should show value diffs and not be affected by commas', function(){
+    var obj1 = { a: 123 };
+    var obj2 = { a: 123, b: 456 };
+
+    // obj1.should.equal(obj2);
+  });
+
+  it('should display diff by data and not like an objects', function(){
+    var buf1 = new Buffer([0x01]);
+    var buf2 = new Buffer([0x02]);
+
+//    buf1.should.equal(buf2);
+  });
 });
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/duration.js b/tests/lib/mocha-2.1.0/test/acceptance/duration.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/duration.js
rename to tests/lib/mocha-2.1.0/test/acceptance/duration.js
index 1f4c5c86f4..4f319b8a3c 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/duration.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/duration.js
@@ -1,4 +1,3 @@
-
 describe('durations', function(){
   describe('when slow', function(){
     it('should highlight in red', function(done){
diff --git a/tests/lib/mocha-2.1.0/test/acceptance/failing/timeout.js b/tests/lib/mocha-2.1.0/test/acceptance/failing/timeout.js
new file mode 100644
index 0000000000..e52dde4c24
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/acceptance/failing/timeout.js
@@ -0,0 +1,17 @@
+describe('timeout', function(){
+  this.timeout(1);
+
+  it('should be honored with sync suites', function(){
+    sleep(2);
+  });
+
+  it('should be honored with async suites', function(done){
+    sleep(2);
+    done();
+  });
+
+  function sleep(ms){
+    var start = Date.now();
+    while(start + ms > Date.now())continue;
+  }
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.in b/tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.in
similarity index 98%
rename from tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.in
rename to tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.in
index 29fb2746e7..09a3ca5363 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.in
+++ b/tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.in
@@ -6,4 +6,4 @@ body {
 
 a {
   color: blue
-}
\ No newline at end of file
+}
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.out b/tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.out
similarity index 98%
rename from tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.out
rename to tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.out
index 643692a4fc..53b3ec906e 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/fixtures/css.out
+++ b/tests/lib/mocha-2.1.0/test/acceptance/fixtures/css.out
@@ -10,4 +10,4 @@ a {
 
 foo {
   bar: 'baz';
-}
\ No newline at end of file
+}
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/fs.js b/tests/lib/mocha-2.1.0/test/acceptance/fs.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/fs.js
rename to tests/lib/mocha-2.1.0/test/acceptance/fs.js
index 102b8e1eac..cdd32166d5 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/fs.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/fs.js
@@ -1,4 +1,3 @@
-
 var fs = require('fs');
 
 describe('fs.readFile()', function(){
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/glob/glob.js b/tests/lib/mocha-2.1.0/test/acceptance/glob/glob.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/glob/glob.js
rename to tests/lib/mocha-2.1.0/test/acceptance/glob/glob.js
index b1127a2a11..3029ae82ee 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/glob/glob.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/glob/glob.js
@@ -1,4 +1,3 @@
-
 describe('globbing test', function(){
   it('should find this test', function(){
     // see glob.sh for details
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/glob/glob.sh b/tests/lib/mocha-2.1.0/test/acceptance/glob/glob.sh
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/glob/glob.sh
rename to tests/lib/mocha-2.1.0/test/acceptance/glob/glob.sh
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/globals.js b/tests/lib/mocha-2.1.0/test/acceptance/globals.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/globals.js
rename to tests/lib/mocha-2.1.0/test/acceptance/globals.js
index 815eaee5c7..f8ef804b23 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/globals.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/globals.js
@@ -1,4 +1,3 @@
-
 describe('global leaks', function(){
   before(function(){
     // uncomment to test
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/http.js b/tests/lib/mocha-2.1.0/test/acceptance/http.js
similarity index 84%
rename from tests/lib/mocha-1.17.1/test/acceptance/http.js
rename to tests/lib/mocha-2.1.0/test/acceptance/http.js
index 750d1084f2..1dfa9146a4 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/http.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/http.js
@@ -1,4 +1,3 @@
-
 var http = require('http');
 
 var server = http.createServer(function(req, res){
@@ -10,8 +9,8 @@ server.listen(8888);
 describe('http', function(){
   it('should provide an example', function(done){
     http.get({ path: '/', port: 8888 }, function(res){
-      res.should.have.status(200);
+      res.should.have.property('statusCode', 200);
       done();
     })
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/bdd.js b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/bdd.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/interfaces/bdd.js
rename to tests/lib/mocha-2.1.0/test/acceptance/interfaces/bdd.js
index f536aa019a..bea1db2295 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/bdd.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/bdd.js
@@ -1,4 +1,3 @@
-
 describe('Array', function(){
   describe('#indexOf()', function(){
     it('should return -1 when the value is not present', function(){
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/exports.js b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/exports.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/interfaces/exports.js
rename to tests/lib/mocha-2.1.0/test/acceptance/interfaces/exports.js
index c93bf28239..38093d50ea 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/exports.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/exports.js
@@ -1,4 +1,3 @@
-
 var calls = [];
 
 exports.Array = {
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/qunit.js b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/qunit.js
similarity index 98%
rename from tests/lib/mocha-1.17.1/test/acceptance/interfaces/qunit.js
rename to tests/lib/mocha-2.1.0/test/acceptance/interfaces/qunit.js
index dbdc5bb774..48aa21d602 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/qunit.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/qunit.js
@@ -1,4 +1,3 @@
-
 function ok(expr, msg) {
   if (!expr) throw new Error(msg);
 }
@@ -21,4 +20,4 @@ suite('String');
 
 test('#length', function(){
   ok('foo'.length == 3);
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/tdd.js b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/tdd.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/interfaces/tdd.js
rename to tests/lib/mocha-2.1.0/test/acceptance/interfaces/tdd.js
index 33311dd6fb..1c6885ed42 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/interfaces/tdd.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/interfaces/tdd.js
@@ -1,4 +1,3 @@
-
 suite('Array', function(){
   suite('#indexOf()', function(){
     var initialValue = 32;
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/asyncOnly.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/asyncOnly.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/asyncOnly.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/asyncOnly.js
index e03251f315..7b7086a7ea 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/asyncOnly.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/asyncOnly.js
@@ -1,4 +1,3 @@
-
 describe('asyncOnly', function(){
   it('should display an error', function(){
 
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/bail.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/bail.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/bail.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/bail.js
index 0628b2fbe2..a2c0c1396f 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/bail.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/bail.js
@@ -1,4 +1,3 @@
-
 describe('bail', function(){
   it('should only display this error', function(done){
     throw new Error('this should be displayed');
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/cascade.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/cascade.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/cascade.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/cascade.js
index 0f884a0031..b2dda4df11 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/cascade.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/cascade.js
@@ -1,4 +1,3 @@
-
 describe('one', function(){
   before(function(){
     console.log('before one');
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/exit.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/exit.js
similarity index 77%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/exit.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/exit.js
index 4cace0b060..113e392300 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/exit.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/exit.js
@@ -10,4 +10,9 @@ describe('exit', function(){
       console.log('all done');
     }, 2500)
   })
+
+  it('should kill all processes when SIGINT received', function () {
+    // uncomment to test
+    //while (true) {}
+  });
 })
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/grep.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/grep.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/grep.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/grep.js
index 9bfe0c5f66..ec9f78f3cd 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/grep.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/grep.js
@@ -1,4 +1,3 @@
-
 describe('grep', function(){
   describe('fast', function(){
     it('should run fast', function(){
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/many.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/many.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/many.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/many.js
index c479ae43ee..26538bc66e 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/many.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/many.js
@@ -24,4 +24,4 @@ describe('a load of tests', function(){
     addTest();
   }
 
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/nontty.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/nontty.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/nontty.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/nontty.js
index cd96f1fc63..2372a660b9 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/nontty.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/nontty.js
@@ -1,4 +1,3 @@
-
 describe('tests for non-tty', function(){
   it('should pass', function(){
 
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/bdd.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/bdd.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/only/bdd.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/only/bdd.js
index 56627ab367..ff14dcdfe3 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/bdd.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/bdd.js
@@ -1,4 +1,3 @@
-
 describe('should only run .only test in this bdd suite', function() {
   it('should not run this test', function() {
     var zero = 0;
@@ -12,4 +11,4 @@ describe('should only run .only test in this bdd suite', function() {
     var zero = 0;
     zero.should.equal(1, 'this test should have been skipped');
   });
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/qunit.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/qunit.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/only/qunit.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/only/qunit.js
index e1d9ac1abb..07c240f617 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/qunit.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/qunit.js
@@ -1,4 +1,3 @@
-
 function ok(expr, msg) {
   if (!expr) throw new Error(msg);
 }
@@ -13,4 +12,4 @@ test.only('should run this test', function() {
 });
 test('should run this test, not (includes the title of the .only test)', function() {
   ok(0 === 1, 'this test should have been skipped');
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/tdd.js b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/tdd.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/misc/only/tdd.js
rename to tests/lib/mocha-2.1.0/test/acceptance/misc/only/tdd.js
index ed7e90637e..cb6429a3d6 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/misc/only/tdd.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/misc/only/tdd.js
@@ -1,4 +1,3 @@
-
 suite('should only run .only test in this tdd suite', function() {
   test('should not run this test', function() {
     var zero = 0;
@@ -12,4 +11,4 @@ suite('should only run .only test in this tdd suite', function() {
     var zero = 0;
     zero.should.equal(1, 'this test should have been skipped');
   });
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/multiple.done.js b/tests/lib/mocha-2.1.0/test/acceptance/multiple.done.js
similarity index 63%
rename from tests/lib/mocha-1.17.1/test/acceptance/multiple.done.js
rename to tests/lib/mocha-2.1.0/test/acceptance/multiple.done.js
index aeb88455e1..79874995f5 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/multiple.done.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/multiple.done.js
@@ -1,4 +1,3 @@
-
 describe('multiple calls to done()', function(){
   beforeEach(function(done){
     done()
@@ -13,4 +12,12 @@ describe('multiple calls to done()', function(){
       // done();
     });
   })
-})
\ No newline at end of file
+
+  it('should produce a reasonable trace', function (done) {
+    process.nextTick(function() {
+      done();
+      // uncomment
+      // done()
+    })
+  });
+})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/pending.js b/tests/lib/mocha-2.1.0/test/acceptance/pending.js
similarity index 95%
rename from tests/lib/mocha-1.17.1/test/acceptance/pending.js
rename to tests/lib/mocha-2.1.0/test/acceptance/pending.js
index cf738b27ba..4ef963709c 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/pending.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/pending.js
@@ -1,4 +1,3 @@
-
 describe('pending', function(){
   it('should be allowed')
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/require/a.js b/tests/lib/mocha-2.1.0/test/acceptance/require/a.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/require/a.js
rename to tests/lib/mocha-2.1.0/test/acceptance/require/a.js
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/require/b.coffee b/tests/lib/mocha-2.1.0/test/acceptance/require/b.coffee
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/require/b.coffee
rename to tests/lib/mocha-2.1.0/test/acceptance/require/b.coffee
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/require/c.js b/tests/lib/mocha-2.1.0/test/acceptance/require/c.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/require/c.js
rename to tests/lib/mocha-2.1.0/test/acceptance/require/c.js
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/require/d.coffee b/tests/lib/mocha-2.1.0/test/acceptance/require/d.coffee
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/require/d.coffee
rename to tests/lib/mocha-2.1.0/test/acceptance/require/d.coffee
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/require/require.js b/tests/lib/mocha-2.1.0/test/acceptance/require/require.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/require/require.js
rename to tests/lib/mocha-2.1.0/test/acceptance/require/require.js
index 74dd0eb597..20f3e6d6ef 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/require/require.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/require/require.js
@@ -1,4 +1,3 @@
-
 describe('require test', function(){
   it('should require args in order', function(){
     var req = global.required;
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/required-tokens.js b/tests/lib/mocha-2.1.0/test/acceptance/required-tokens.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/required-tokens.js
rename to tests/lib/mocha-2.1.0/test/acceptance/required-tokens.js
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/root.js b/tests/lib/mocha-2.1.0/test/acceptance/root.js
similarity index 98%
rename from tests/lib/mocha-1.17.1/test/acceptance/root.js
rename to tests/lib/mocha-2.1.0/test/acceptance/root.js
index 49a1e7feb4..17738302da 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/root.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/root.js
@@ -1,4 +1,3 @@
-
 var calls = [];
 
 before(function(){
@@ -9,4 +8,4 @@ describe('root', function(){
   it('should be a valid suite', function(){
     calls.should.eql(['before']);
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/sort/alpha.js b/tests/lib/mocha-2.1.0/test/acceptance/sort/alpha.js
similarity index 97%
rename from tests/lib/mocha-1.17.1/test/acceptance/sort/alpha.js
rename to tests/lib/mocha-2.1.0/test/acceptance/sort/alpha.js
index 365f39cd19..7a5302994f 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/sort/alpha.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/sort/alpha.js
@@ -4,4 +4,4 @@ describe('alpha', function(){
       throw new Error('alpha was not executed first');
     }
   });
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/sort/beta.js b/tests/lib/mocha-2.1.0/test/acceptance/sort/beta.js
similarity index 96%
rename from tests/lib/mocha-1.17.1/test/acceptance/sort/beta.js
rename to tests/lib/mocha-2.1.0/test/acceptance/sort/beta.js
index 3de3e0ccad..0951f49038 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/sort/beta.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/sort/beta.js
@@ -2,4 +2,4 @@ describe('beta', function(){
   it('should be executed second', function(){
     global.beta = 1;
   });
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/test.coffee b/tests/lib/mocha-2.1.0/test/acceptance/test.coffee
similarity index 70%
rename from tests/lib/mocha-1.17.1/test/acceptance/test.coffee
rename to tests/lib/mocha-2.1.0/test/acceptance/test.coffee
index b1c470a69e..8260940a1e 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/test.coffee
+++ b/tests/lib/mocha-2.1.0/test/acceptance/test.coffee
@@ -3,4 +3,4 @@ obj = foo: 'bar'
 
 describe 'coffeescript', ->
   it 'should work', ->
-    obj.should.eql foo: 'bar'
\ No newline at end of file
+    obj.should.eql foo: 'bar'
diff --git a/tests/lib/mocha-1.17.1/test/acceptance/test.foo b/tests/lib/mocha-2.1.0/test/acceptance/test.foo
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/acceptance/test.foo
rename to tests/lib/mocha-2.1.0/test/acceptance/test.foo
diff --git a/tests/lib/mocha-2.1.0/test/acceptance/throw.js b/tests/lib/mocha-2.1.0/test/acceptance/throw.js
new file mode 100644
index 0000000000..ac74f22c4a
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/acceptance/throw.js
@@ -0,0 +1,111 @@
+var mocha = require('../../')
+  , Suite = mocha.Suite
+  , Runner = mocha.Runner
+  , Test = mocha.Test;
+
+describe('a test that throws', function () {
+  var suite, runner;
+
+  beforeEach(function(){
+    suite = new Suite(null, 'root');
+    runner = new Runner(suite);
+  })
+
+  this.timeout(50);
+
+  describe('undefined', function (){
+    it('should not pass if throwing sync and test is sync', function(done) {
+      var test = new Test('im sync and throw undefined sync', function(){
+        throw undefined;
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    })
+
+    it('should not pass if throwing sync and test is async', function(done){
+      var test = new Test('im async and throw undefined sync', function(done2){
+        throw undefined;
+        process.nexTick(done2);
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    });
+
+    it('should not pass if throwing async and test is async', function(done){
+      var test = new Test('im async and throw undefined async', function(done2){
+        process.nexTick(function(){
+          throw undefined;
+          done2();
+        });
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    })
+  })
+
+  describe('null', function (){
+    it('should not pass if throwing sync and test is sync', function(done) {
+      var test = new Test('im sync and throw null sync', function(){
+        throw null;
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    })
+
+    it('should not pass if throwing sync and test is async', function(done){
+      var test = new Test('im async and throw null sync', function(done2){
+        throw null;
+        process.nexTick(done2);
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    });
+
+    it('should not pass if throwing async and test is async', function(done){
+      var test = new Test('im async and throw null async', function(done2){
+        process.nexTick(function(){
+          throw null;
+          done2();
+        });
+      });
+      suite.addTest(test);
+      runner = new Runner(suite);
+      runner.on('end', function(){
+        runner.failures.should.equal(1);
+        test.state.should.equal('failed');
+        done();
+      });
+      runner.run();
+    })
+  })
+})
\ No newline at end of file
diff --git a/tests/lib/mocha-2.1.0/test/acceptance/timeout.js b/tests/lib/mocha-2.1.0/test/acceptance/timeout.js
new file mode 100644
index 0000000000..f61c3ba566
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/acceptance/timeout.js
@@ -0,0 +1,79 @@
+describe('timeouts', function(){
+  beforeEach(function(done){
+    // uncomment
+    // setTimeout(done, 3000);
+    done();
+  })
+
+  it('should error on timeout', function(done){
+    // uncomment
+    // setTimeout(done, 3000);
+    done();
+  })
+
+  it('should allow overriding per-test', function(done){
+    this.timeout(1000);
+    setTimeout(function(){
+      done();
+    }, 300);
+  })
+
+  describe('disabling', function(){
+    it('should allow overriding per-test', function(done){
+      this.enableTimeouts(false);
+      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/tests/lib/mocha-1.17.1/test/acceptance/uncaught.js b/tests/lib/mocha-2.1.0/test/acceptance/uncaught.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/acceptance/uncaught.js
rename to tests/lib/mocha-2.1.0/test/acceptance/uncaught.js
index 7349595df2..f228266e45 100644
--- a/tests/lib/mocha-1.17.1/test/acceptance/uncaught.js
+++ b/tests/lib/mocha-2.1.0/test/acceptance/uncaught.js
@@ -1,4 +1,3 @@
-
 describe('uncaught', function(){
   beforeEach(function(done){
     process.nextTick(function(){
@@ -14,4 +13,4 @@ describe('uncaught', function(){
       done();
     })
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-2.1.0/test/acceptance/utils.js b/tests/lib/mocha-2.1.0/test/acceptance/utils.js
new file mode 100644
index 0000000000..4442c59213
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/acceptance/utils.js
@@ -0,0 +1,263 @@
+var utils = require('../../lib/utils');
+
+describe('lib/utils', function () {
+  describe('clean', function () {
+    it("should format a single line test function", function () {
+      var fn = [
+        "function () {"
+        , "  var a = 1;"
+        , "}"
+      ].join("\n");
+      utils.clean(fn).should.equal("var a = 1;");
+    });
+
+    it("should format a multi line test indented with spaces", function () {
+      // and no new lines after curly braces, shouldn't matter
+      var fn = [
+        "function(){  var a = 1;"
+        , "    var b = 2;" // this one has more spaces
+        , "  var c = 3;  }"
+      ].join("\n");
+      utils.clean(fn).should.equal("var a = 1;\n  var b = 2;\nvar c = 3;");
+    });
+
+    it("should format a multi line test indented with tabs", function () {
+      var fn = [
+        "function (arg1, arg2)   {"
+        , "\tif (true) {"
+        , "\t\tvar a = 1;"
+        , "\t}"
+        , "}"
+      ].join("\n");
+      utils.clean(fn).should.equal("if (true) {\n\tvar a = 1;\n}");
+    });
+
+    it("should format functions saved in windows style - spaces", function () {
+      var fn = [
+        "function (one) {"
+        , "   do {",
+        , '    "nothing";',
+        , "   } while (false);"
+        , ' }'
+      ].join("\r\n");
+      utils.clean(fn).should.equal('do {\n "nothing";\n} while (false);');
+    });
+
+    it("should format functions saved in windows style - tabs", function () {
+      var fn = [
+        "function ( )   {"
+        , "\tif (false) {"
+        , "\t\tvar json = {"
+        , '\t\t\tone : 1'
+        , '\t\t};'
+        , "\t}"
+        , "}"
+      ].join("\r\n");
+      utils.clean(fn).should.equal("if (false) {\n\tvar json = {\n\t\tone : 1\n\t};\n}");
+    });
+
+    it("should format es6 arrow functions", function () {
+      var fn = [
+        "() => {",
+        "  var a = 1;",
+        "}"
+      ].join("\n");
+      utils.clean(fn).should.equal("var a = 1;");
+    });
+
+    it("should format es6 arrow functions with implicit return", function () {
+      var fn = "() => foo()";
+      utils.clean(fn).should.equal("foo()");
+    });
+  });
+
+  describe('stringify', function(){
+
+    var stringify = utils.stringify;
+
+    it('should canonicalize the object', function(){
+      var travis = { name: 'travis', age: 24 };
+      var travis2 = { age: 24, name: 'travis' };
+
+      stringify(travis).should.equal(stringify(travis2));
+    });
+
+    it('should handle circular structures in objects', function(){
+      var travis = { name: 'travis' };
+      travis.whoami = travis;
+
+      stringify(travis).should.equal('{\n  "name": "travis"\n  "whoami": "[Circular]"\n}');
+    });
+
+    it('should handle circular structures in arrays', function(){
+      var travis = ['travis'];
+      travis.push(travis);
+
+      stringify(travis).should.equal('[\n  "travis"\n  "[Circular]"\n]');
+    });
+
+    it('should handle circular structures in functions', function(){
+      var travis = function () {};
+      travis.fn = travis;
+
+      stringify(travis).should.equal('{\n  "fn": "[Circular]"\n}');
+    });
+
+
+    it('should handle various non-undefined, non-null, non-object, non-array, non-date, and non-function values', function () {
+      var regexp = new RegExp("(?:)"),
+        regExpObj = { regexp: regexp },
+        regexpString = '/(?:)/';
+
+      stringify(regExpObj).should.equal('{\n  "regexp": "' + regexpString + '"\n}');
+      stringify(regexp).should.equal(regexpString);
+
+      var number = 1,
+        numberObj = { number: number },
+        numberString = '1';
+
+      stringify(numberObj).should.equal('{\n  "number": ' + number + '\n}');
+      stringify(number).should.equal(numberString);
+
+      var boolean = false,
+        booleanObj = { boolean: boolean },
+        booleanString = 'false';
+
+      stringify(booleanObj).should.equal('{\n  "boolean": ' + boolean + '\n}');
+      stringify(boolean).should.equal(booleanString);
+
+      var string = 'sneepy',
+        stringObj = { string: string };
+
+      stringify(stringObj).should.equal('{\n  "string": "' + string + '"\n}');
+      stringify(string).should.equal(string);
+
+      var nullValue = null,
+        nullObj = { 'null': null },
+        nullString = '[null]';
+
+      stringify(nullObj).should.equal('{\n  "null": null\n}');
+      stringify(nullValue).should.equal(nullString);
+
+    });
+
+    it('should handle arrays', function () {
+      var array = ['dave', 'dave', 'dave', 'dave'],
+        arrayObj = {array: array},
+        arrayString = array.map(function () {
+          return '    "dave"';
+        }).join('\n');
+
+      stringify(arrayObj).should.equal('{\n  "array": [\n' + arrayString + '\n  ]\n}');
+      stringify(array).should.equal('[' + arrayString.replace(/\s+/g, '\n  ') + '\n]');
+    });
+
+    it('should handle functions', function () {
+      var fn = function() {},
+        fnObj = {fn: fn},
+        fnString = '[Function]';
+
+      stringify(fnObj).should.equal('{\n  "fn": "' + fnString + '"\n}');
+      stringify(fn).should.equal('[Function]');
+    });
+
+    it('should handle empty objects', function () {
+      stringify({}).should.equal('{}');
+      stringify({foo: {}}).should.equal('{\n  "foo": {}\n}');
+    });
+
+    it('should handle empty arrays', function () {
+      stringify([]).should.equal('[]');
+      stringify({foo: []}).should.equal('{\n  "foo": []\n}');
+    });
+
+    it('should handle non-empty arrays', function () {
+      stringify(['a', 'b', 'c']).should.equal('[\n  "a"\n  "b"\n  "c"\n]')
+    });
+
+    it('should handle empty functions (with no properties)', function () {
+      stringify(function(){}).should.equal('[Function]');
+      stringify({foo: function() {}}).should.equal('{\n  "foo": "[Function]"\n}');
+      stringify({foo: function() {}, bar: 'baz'}).should.equal('{\n  "bar": "baz"\n  "foo": "[Function]"\n}');
+    });
+
+    it('should handle functions w/ properties', function () {
+      var fn = function(){};
+      fn.bar = 'baz';
+      stringify(fn).should.equal('{\n  "bar": "baz"\n}');
+      stringify({foo: fn}).should.equal('{\n  "foo": {\n    "bar": "baz"\n  }\n}');
+    });
+
+    it('should handle undefined values', function () {
+      stringify({foo: undefined}).should.equal('{\n  "foo": "[undefined]"\n}');
+      stringify({foo: 'bar', baz: undefined}).should.equal('{\n  "baz": "[undefined]"\n  "foo": "bar"\n}');
+      stringify().should.equal('[undefined]');
+    });
+
+    it('should recurse', function () {
+stringify({foo: {bar: {baz: {quux: {herp: 'derp'}}}}}).should.equal('{\n  "foo": {\n    "bar": {\n      "baz": {\n        "quux": {\n          "herp": "derp"\n        }\n      }\n    }\n  }\n}');
+    });
+
+    it('might get confusing', function () {
+      stringify(null).should.equal(stringify('[null]'));
+    });
+
+    it('should not freak out if it sees a primitive twice', function () {
+      stringify({foo: null, bar: null}).should.equal('{\n  "bar": null\n  "foo": null\n}');
+      stringify({foo: 1, bar: 1}).should.equal('{\n  "bar": 1\n  "foo": 1\n}');
+    });
+
+    it('should stringify dates', function () {
+      var date = new Date(0);
+      stringify(date).should.equal('[Date: 1970-01-01T00:00:00.000Z]');
+      stringify({date: date}).should.equal('{\n  "date": "[Date: 1970-01-01T00:00:00.000Z]"\n}');
+    });
+  });
+
+  describe('type', function () {
+    var type = utils.type;
+    it('should recognize various types', function () {
+      type({}).should.equal('object');
+      type([]).should.equal('array');
+      type(1).should.equal('number');
+      type(Infinity).should.equal('number');
+      type(null).should.equal('null');
+      type(new Date()).should.equal('date');
+      type(/foo/).should.equal('regexp');
+      type('type').should.equal('string');
+      type(global).should.equal('global');
+      type(true).should.equal('boolean');
+    });
+  });
+
+  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.renameSync('/tmp/mocha-utils.js', '/tmp/bob');
+      existsSync('/tmp/mocha-utils-link.js').should.be.false;
+      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/tests/lib/mocha-1.17.1/test/browser/array.js b/tests/lib/mocha-2.1.0/test/browser/array.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/browser/array.js
rename to tests/lib/mocha-2.1.0/test/browser/array.js
diff --git a/tests/lib/mocha-1.17.1/test/browser/index.html b/tests/lib/mocha-2.1.0/test/browser/index.html
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/browser/index.html
rename to tests/lib/mocha-2.1.0/test/browser/index.html
diff --git a/tests/lib/mocha-1.17.1/test/browser/large.html b/tests/lib/mocha-2.1.0/test/browser/large.html
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/browser/large.html
rename to tests/lib/mocha-2.1.0/test/browser/large.html
diff --git a/tests/lib/mocha-1.17.1/test/browser/large.js b/tests/lib/mocha-2.1.0/test/browser/large.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/browser/large.js
rename to tests/lib/mocha-2.1.0/test/browser/large.js
index 1250abaef4..56757eae27 100644
--- a/tests/lib/mocha-1.17.1/test/browser/large.js
+++ b/tests/lib/mocha-2.1.0/test/browser/large.js
@@ -1,4 +1,3 @@
-
 var n = 30;
 while (n--) {
   describe('Array ' + n, function(){
@@ -46,4 +45,4 @@ describe('something', function(){
       done();
     }, 1);
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/browser/opts.html b/tests/lib/mocha-2.1.0/test/browser/opts.html
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/browser/opts.html
rename to tests/lib/mocha-2.1.0/test/browser/opts.html
diff --git a/tests/lib/mocha-1.17.1/test/browser/opts.js b/tests/lib/mocha-2.1.0/test/browser/opts.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/browser/opts.js
rename to tests/lib/mocha-2.1.0/test/browser/opts.js
diff --git a/tests/lib/mocha-2.1.0/test/color.js b/tests/lib/mocha-2.1.0/test/color.js
new file mode 100644
index 0000000000..8c7167b0fa
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/color.js
@@ -0,0 +1,17 @@
+var assert = require('assert');
+var child_process = require('child_process');
+
+describe('Mocha', function() {
+  this.timeout(1000);
+
+  it('should not output colors to pipe', function(cb) {
+    var command = 'bin/mocha --grep missing-test';
+    child_process.exec(command, function(err, stdout, stderr) {
+      if (err) return cb(err);
+
+      assert(stdout.indexOf('[90m') === -1);
+
+      cb(null);
+    });
+  });
+});
diff --git a/tests/lib/mocha-1.17.1/test/compiler/foo.js b/tests/lib/mocha-2.1.0/test/compiler/foo.js
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/compiler/foo.js
rename to tests/lib/mocha-2.1.0/test/compiler/foo.js
diff --git a/tests/lib/mocha-1.17.1/test/grep.js b/tests/lib/mocha-2.1.0/test/grep.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/grep.js
rename to tests/lib/mocha-2.1.0/test/grep.js
index b4be3715f1..c2a88217f0 100644
--- a/tests/lib/mocha-1.17.1/test/grep.js
+++ b/tests/lib/mocha-2.1.0/test/grep.js
@@ -1,4 +1,3 @@
-
 var Mocha = require('../');
 
 describe('Mocha', function(){
diff --git a/tests/lib/mocha-1.17.1/test/hook.async.js b/tests/lib/mocha-2.1.0/test/hook.async.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/hook.async.js
rename to tests/lib/mocha-2.1.0/test/hook.async.js
index fd62932c4b..ae6e642d24 100644
--- a/tests/lib/mocha-1.17.1/test/hook.async.js
+++ b/tests/lib/mocha-2.1.0/test/hook.async.js
@@ -1,4 +1,3 @@
-
 describe('async', function(){
   var calls = [];
 
diff --git a/tests/lib/mocha-1.17.1/test/hook.err.js b/tests/lib/mocha-2.1.0/test/hook.err.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/hook.err.js
rename to tests/lib/mocha-2.1.0/test/hook.err.js
index 873147ac02..d7e6c2e460 100644
--- a/tests/lib/mocha-1.17.1/test/hook.err.js
+++ b/tests/lib/mocha-2.1.0/test/hook.err.js
@@ -293,4 +293,4 @@ describe('hook error handling', function(){
     });
   })
 
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/hook.sync.js b/tests/lib/mocha-2.1.0/test/hook.sync.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/hook.sync.js
rename to tests/lib/mocha-2.1.0/test/hook.sync.js
index c446c6aac7..1d40f5d0c0 100644
--- a/tests/lib/mocha-1.17.1/test/hook.sync.js
+++ b/tests/lib/mocha-2.1.0/test/hook.sync.js
@@ -1,4 +1,3 @@
-
 describe('serial', function(){
   var calls = [];
 
@@ -95,4 +94,4 @@ describe('serial', function(){
         , 'parent after']);
     })
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/hook.sync.nested.js b/tests/lib/mocha-2.1.0/test/hook.sync.nested.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/hook.sync.nested.js
rename to tests/lib/mocha-2.1.0/test/hook.sync.nested.js
index 94c00da5f7..b87c22298f 100644
--- a/tests/lib/mocha-1.17.1/test/hook.sync.nested.js
+++ b/tests/lib/mocha-2.1.0/test/hook.sync.nested.js
@@ -1,4 +1,3 @@
-
 describe('serial', function(){
   describe('nested', function(){
     var calls = [];
diff --git a/tests/lib/mocha-1.17.1/test/hook.timeout.js b/tests/lib/mocha-2.1.0/test/hook.timeout.js
similarity index 96%
rename from tests/lib/mocha-1.17.1/test/hook.timeout.js
rename to tests/lib/mocha-2.1.0/test/hook.timeout.js
index 5b158e27e6..155c1e95a6 100644
--- a/tests/lib/mocha-1.17.1/test/hook.timeout.js
+++ b/tests/lib/mocha-2.1.0/test/hook.timeout.js
@@ -1,4 +1,3 @@
-
 before(function(done){
   this.timeout(100);
   setTimeout(done, 50);
@@ -6,4 +5,4 @@ before(function(done){
 
 it('should work', function(done) {
   done();
-});
\ No newline at end of file
+});
diff --git a/tests/lib/mocha-1.17.1/test/http.meta.2.js b/tests/lib/mocha-2.1.0/test/http.meta.2.js
similarity index 95%
rename from tests/lib/mocha-1.17.1/test/http.meta.2.js
rename to tests/lib/mocha-2.1.0/test/http.meta.2.js
index c0568ff349..31b779322f 100644
--- a/tests/lib/mocha-1.17.1/test/http.meta.2.js
+++ b/tests/lib/mocha-2.1.0/test/http.meta.2.js
@@ -1,4 +1,3 @@
-
 var http = require('http');
 
 var server = http.createServer(function(req, res){
@@ -29,7 +28,7 @@ function get(url) {
   function request(done) {
     http.get({ path: url, port: 8899, headers: header }, function(res){
       var buf = '';
-      res.should.have.status(200);
+      res.should.have.property('statusCode', 200);
       res.setEncoding('utf8');
       res.on('data', function(chunk){ buf += chunk });
       res.on('end', function(){
@@ -53,6 +52,7 @@ function get(url) {
 
         expected = body;
         describe('GET ' + url, function(){
+          this.timeout(500);
           if (fields) {
             describe('when given ' + fields, function(){
               it('should respond with "' + body + '"', request);
@@ -79,4 +79,4 @@ describe('http server', function(){
     .set('Accept', 'application/json')
     .should
     .respond('["tobi","loki","jane"]')
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/http.meta.js b/tests/lib/mocha-2.1.0/test/http.meta.js
similarity index 95%
rename from tests/lib/mocha-1.17.1/test/http.meta.js
rename to tests/lib/mocha-2.1.0/test/http.meta.js
index 1ab6767005..00c3f9c8b6 100644
--- a/tests/lib/mocha-1.17.1/test/http.meta.js
+++ b/tests/lib/mocha-2.1.0/test/http.meta.js
@@ -1,4 +1,3 @@
-
 var http = require('http');
 
 var server = http.createServer(function(req, res){
@@ -25,7 +24,7 @@ function get(url, body, header) {
   return function(done){
     http.get({ path: url, port: 8889, headers: header }, function(res){
       var buf = '';
-      res.should.have.status(200);
+      res.should.have.property('statusCode', 200);
       res.setEncoding('utf8');
       res.on('data', function(chunk){ buf += chunk });
       res.on('end', function(){
@@ -49,4 +48,4 @@ describe('http requests', function(){
     it('should respond with users',
       get('/users', '["tobi","loki","jane"]', { Accept: 'application/json' }))
   })
-})
\ No newline at end of file
+})
diff --git a/tests/lib/mocha-1.17.1/test/jsapi/index.js b/tests/lib/mocha-2.1.0/test/jsapi/index.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/jsapi/index.js
rename to tests/lib/mocha-2.1.0/test/jsapi/index.js
index 5b5c169ade..2dcdd6dc68 100644
--- a/tests/lib/mocha-1.17.1/test/jsapi/index.js
+++ b/tests/lib/mocha-2.1.0/test/jsapi/index.js
@@ -1,4 +1,3 @@
-
 var Mocha = require('../../')
   , path = require('path');
 
diff --git a/tests/lib/mocha-1.17.1/test/mocha.opts b/tests/lib/mocha-2.1.0/test/mocha.opts
similarity index 100%
rename from tests/lib/mocha-1.17.1/test/mocha.opts
rename to tests/lib/mocha-2.1.0/test/mocha.opts
diff --git a/tests/lib/mocha-2.1.0/test/regression/issue1327/case.js b/tests/lib/mocha-2.1.0/test/regression/issue1327/case.js
new file mode 100644
index 0000000000..295ec12413
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/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/tests/lib/mocha-2.1.0/test/regression/issue1327/control.js b/tests/lib/mocha-2.1.0/test/regression/issue1327/control.js
new file mode 100644
index 0000000000..b77555da02
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/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/tests/lib/mocha-2.1.0/test/reporters/base.js b/tests/lib/mocha-2.1.0/test/reporters/base.js
new file mode 100644
index 0000000000..d285bf8845
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/reporters/base.js
@@ -0,0 +1,136 @@
+var Base = require('../../lib/reporters/base');
+
+describe('Base reporter', function () {
+
+  it('should show diffs with showDiff property set', function () {
+    var err = new Error('test'),
+      stdout = [],
+      stdoutWrite = process.stdout.write,
+      errOut;
+
+    err.actual = "a1";
+    err.expected = "e1";
+    err.showDiff = true;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stdout.write = function (string) {
+      stdout.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stdout.write = stdoutWrite;
+
+    errOut = stdout.join('\n');
+
+    errOut.should.match(/test/);
+    errOut.should.match(/actual/);
+    errOut.should.match(/expected/);
+
+  });
+
+
+  it('should not stringify strings', function () {
+    var err = new Error('test'),
+      stdout = [],
+      stdoutWrite = process.stdout.write,
+      errOut;
+
+    err.actual = "a1";
+    err.expected = "e2";
+    err.showDiff = true;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stdout.write = function (string) {
+      stdout.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stdout.write = stdoutWrite;
+
+    errOut = stdout.join('\n');
+
+    errOut.should.not.match(/"/);
+    errOut.should.match(/test/);
+    errOut.should.match(/actual/);
+    errOut.should.match(/expected/);
+
+  });
+
+
+  it('should stringify objects', function () {
+    var err = new Error('test'),
+      stdout = [],
+      stdoutWrite = process.stdout.write,
+      errOut;
+
+    err.actual = {key:"a1"};
+    err.expected = {key:"e1"};
+    err.showDiff = true;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stdout.write = function (string) {
+      stdout.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stdout.write = stdoutWrite;
+
+    errOut = stdout.join('\n');
+
+    errOut.should.match(/"key"/);
+    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'),
+      stdout = [],
+      stdoutWrite = process.stdout.write,
+      errOut;
+
+    err.actual = "a1";
+    err.expected = "e1";
+    err.showDiff = false;
+    var test = {
+      err: err,
+      fullTitle: function () {
+        return 'title';
+      }
+    };
+
+    process.stdout.write = function (string) {
+      stdout.push(string);
+    };
+
+    Base.list([test]);
+
+    process.stdout.write = stdoutWrite;
+
+    errOut = stdout.join('\n');
+
+    errOut.should.match(/test/);
+    errOut.should.not.match(/actual/);
+    errOut.should.not.match(/expected/);
+
+  });
+});
diff --git a/tests/lib/mocha-2.1.0/test/reporters/json.js b/tests/lib/mocha-2.1.0/test/reporters/json.js
new file mode 100644
index 0000000000..f071e75480
--- /dev/null
+++ b/tests/lib/mocha-2.1.0/test/reporters/json.js
@@ -0,0 +1,61 @@
+var Mocha = require('../../')
+  , Suite = Mocha.Suite
+  , Runner = Mocha.Runner
+  , Test = Mocha.Test;
+
+describe('json reporter', function(){
+  var suite, runner;
+
+  beforeEach(function(){
+    var mocha = new Mocha({
+      reporter: 'json'
+    });
+    suite = new Suite('JSON suite', 'root');
+    runner = new Runner(suite);
+    var mochaReporter = new mocha._reporter(runner);
+  })
+
+   it('should have 1 test failure', function(done){
+     var testTitle = 'json test 1';
+     var error = { message: 'oh shit' };
+
+     suite.addTest(new Test(testTitle, function (done) {
+       done(new Error(error.message));
+     }));
+
+     runner.run(function(failureCount) {
+       failureCount.should.be.exactly(1);
+       runner.should.have.property('testResults');
+       runner.testResults.should.have.property('failures');
+       runner.testResults.failures.should.be.an.instanceOf(Array);
+       runner.testResults.failures.should.have.a.lengthOf(1);
+
+       var failure = runner.testResults.failures[0];
+       failure.should.have.property('title', testTitle);
+       failure.err.message.should.equal(error.message);
+       failure.should.have.properties('err');
+
+       done();
+     });
+  })
+
+  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/tests/lib/mocha-1.17.1/test/reporters/nyan.js b/tests/lib/mocha-2.1.0/test/reporters/nyan.js
similarity index 99%
rename from tests/lib/mocha-1.17.1/test/reporters/nyan.js
rename to tests/lib/mocha-2.1.0/test/reporters/nyan.js
index cd6b4a96a8..8a54458961 100644
--- a/tests/lib/mocha-1.17.1/test/reporters/nyan.js
+++ b/tests/lib/mocha-2.1.0/test/reporters/nyan.js
@@ -1,6 +1,7 @@
 var reporters = require('../../').reporters
    , NyanCat = reporters.Nyan;
 
+
 describe('nyan face', function () {
   it('nyan face:(x .x) when "failures" at least one', function () {
     var nyanCat = new NyanCat({on: function(){}});
diff --git a/tests/lib/mocha-1.17.1/test/runnable.js b/tests/lib/mocha-2.1.0/test/runnable.js
similarity index 59%
rename from tests/lib/mocha-1.17.1/test/runnable.js
rename to tests/lib/mocha-2.1.0/test/runnable.js
index 29d8fd6b96..dd05a7543b 100644
--- a/tests/lib/mocha-1.17.1/test/runnable.js
+++ b/tests/lib/mocha-2.1.0/test/runnable.js
@@ -1,4 +1,3 @@
-
 var mocha = require('../')
   , Runnable = mocha.Runnable
   , EventEmitter = require('events').EventEmitter;
@@ -41,6 +40,14 @@ describe('Runnable(title, fn)', function(){
     })
   })
 
+  describe('#enableTimeouts(enabled)', function(){
+    it('should set enabled', function(){
+      var run = new Runnable;
+      run.enableTimeouts(false);
+      run.enableTimeouts().should.equal(false);
+    });
+  });
+
   describe('#slow(ms)', function(){
     it('should set the slow threshold', function(){
       var run = new Runnable;
@@ -126,6 +133,17 @@ describe('Runnable(title, fn)', function(){
       })
     })
 
+    describe('when timeouts are disabled', function() {
+      it('should not error with timeout', function(done) {
+        var test = new Runnable('foo', function(done){
+          setTimeout(process.nextTick.bind(undefined, done), 2);
+        });
+        test.timeout(1);
+        test.enableTimeouts(false);
+        test.run(done);
+      });
+    });
+
     describe('when async', function(){
       describe('without error', function(){
         it('should invoke the callback', function(done){
@@ -206,6 +224,18 @@ 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) {
+            err.message.should.equal('Caught undefined error, did you throw without specifying what?');
+            done();
+          })
+        });
       })
 
       describe('when an error is passed', function(){
@@ -222,6 +252,32 @@ describe('Runnable(title, fn)', function(){
         })
       })
 
+      describe('when done() is invoked with a non-Error object', function(){
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(done){
+            done({ error: 'Test error' });
+          });
+
+          test.run(function(err){
+            err.message.should.equal('done() invoked with non-Error: {"error":"Test error"}');
+            done();
+          });
+        })
+      })
+
+      describe('when done() is invoked with a string', function(){
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(done){
+            done('Test error');
+          });
+
+          test.run(function(err){
+            err.message.should.equal('done() invoked with non-Error: Test error');
+            done();
+          });
+        })
+      })
+
       it('should allow updating the timeout', function(done){
         var callCount = 0;
         var increment = function() {
@@ -242,5 +298,112 @@ describe('Runnable(title, fn)', function(){
       it('should allow a timeout of 0')
     })
 
+    describe('when fn returns a promise', function(){
+      describe('when the promise is fulfilled with no value', function(){
+        var fulfilledPromise = {
+          then: function (fulfilled, rejected) {
+            process.nextTick(fulfilled);
+          }
+        };
+
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(){
+            return fulfilledPromise;
+          });
+
+          test.run(done);
+        })
+      })
+
+      describe('when the promise is fulfilled with a value', function(){
+        var fulfilledPromise = {
+          then: function (fulfilled, rejected) {
+            process.nextTick(function () {
+              fulfilled({});
+            });
+          }
+        };
+
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(){
+            return fulfilledPromise;
+          });
+
+          test.run(done);
+        })
+      })
+
+      describe('when the promise is rejected', function(){
+        var expectedErr = new Error('fail');
+        var rejectedPromise = {
+          then: function (fulfilled, rejected) {
+            process.nextTick(function () {
+              rejected(expectedErr);
+            });
+          }
+        };
+
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(){
+            return rejectedPromise;
+          });
+
+          test.run(function(err){
+            err.should.equal(expectedErr);
+            done();
+          });
+        })
+      })
+
+      describe('when the promise is rejected without a reason', function(){
+        var expectedErr = new Error('Promise rejected with no or falsy reason');
+        var rejectedPromise = {
+          then: function (fulfilled, rejected) {
+            process.nextTick(function () {
+              rejected();
+            });
+          }
+        };
+
+        it('should invoke the callback', function(done){
+          var test = new Runnable('foo', function(){
+            return rejectedPromise;
+          });
+
+          test.run(function(err){
+            err.should.eql(expectedErr);
+            done();
+          });
+        })
+      })
+
+      describe('when the promise takes too long to settle', function(){
+        var foreverPendingPromise = {
+          then: function () { }
+        };
+
+        it('should give the timeout error', function(done){
+          var test = new Runnable('foo', function(){
+            return foreverPendingPromise;
+          });
+
+          test.timeout(10);
+          test.run(function(err){
+            err.should.be.ok;
+            done();
+          });
+        })
+      })
+    })
+
+    describe('when fn returns a non-promise', function(){
+      it('should invoke the callback', function(done){
+        var test = new Runnable('foo', function(){
+          return { then: "i ran my tests" };
+        });
+
+        test.run(done);
+      })
+    })
   })
 })
diff --git a/tests/lib/mocha-1.17.1/test/runner.js b/tests/lib/mocha-2.1.0/test/runner.js
similarity index 90%
rename from tests/lib/mocha-1.17.1/test/runner.js
rename to tests/lib/mocha-2.1.0/test/runner.js
index 5a7589914d..a11aeedabf 100644
--- a/tests/lib/mocha-1.17.1/test/runner.js
+++ b/tests/lib/mocha-2.1.0/test/runner.js
@@ -1,4 +1,3 @@
-
 var mocha = require('../')
   , Suite = mocha.Suite
   , Runner = mocha.Runner
@@ -53,12 +52,12 @@ describe('Runner', function(){
   describe('.globalProps()', function(){
     it('should include common non enumerable globals', function() {
       var props = runner.globalProps();
-      props.should.include('setTimeout');
-      props.should.include('clearTimeout');
-      props.should.include('setInterval');
-      props.should.include('clearInterval');
-      props.should.include('Date');
-      props.should.include('XMLHttpRequest');
+      props.should.containEql('setTimeout');
+      props.should.containEql('clearTimeout');
+      props.should.containEql('setInterval');
+      props.should.containEql('clearInterval');
+      props.should.containEql('Date');
+      props.should.containEql('XMLHttpRequest');
     });
   });
 
@@ -69,8 +68,8 @@ describe('Runner', function(){
 
     it('should white-list globals', function(){
       runner.globals(['foo', 'bar']);
-      runner.globals().should.include('foo');
-      runner.globals().should.include('bar');
+      runner.globals().should.containEql('foo');
+      runner.globals().should.containEql('bar');
     })
   })
 
@@ -182,6 +181,20 @@ describe('Runner', function(){
     })
   })
 
+  describe('.hook(name, fn)', function(){
+    it('should execute hooks after failed test if suite bail is true', function(done){
+      runner.fail({});
+      suite.bail(true);
+      suite.afterEach(function(){
+        suite.afterAll(function() {
+          done();
+        })
+      });
+      runner.hook('afterEach', function(){});
+      runner.hook('afterAll', function(){});
+    })
+  })
+
   describe('.fail(test, err)', function(){
     it('should increment .failures', function(){
       runner.failures.should.equal(0);
diff --git a/tests/lib/mocha-1.17.1/test/suite.js b/tests/lib/mocha-2.1.0/test/suite.js
similarity index 77%
rename from tests/lib/mocha-1.17.1/test/suite.js
rename to tests/lib/mocha-2.1.0/test/suite.js
index 8cacff8de9..011b3fb2b8 100644
--- a/tests/lib/mocha-1.17.1/test/suite.js
+++ b/tests/lib/mocha-2.1.0/test/suite.js
@@ -1,4 +1,3 @@
-
 var mocha = require('../')
   , Context = mocha.Context
   , Suite = mocha.Suite
@@ -132,7 +131,7 @@ describe('Suite', function(){
 
     describe('wraps the passed in function in a Hook', function(){
       it('adds it to _beforeAll', function(){
-        function fn(){}
+        var fn = function(){};
         this.suite.beforeAll(fn);
 
         this.suite._beforeAll.should.have.length(1);
@@ -140,6 +139,23 @@ describe('Suite', function(){
         beforeAllItem.title.should.equal('"before all" hook');
         beforeAllItem.fn.should.equal(fn);
       });
+
+      it('appends title to hook', function(){
+        var fn = function(){};
+        this.suite.beforeAll('test', fn);
+
+        this.suite._beforeAll.should.have.length(1);
+        var beforeAllItem = this.suite._beforeAll[0];
+        beforeAllItem.title.should.equal('"before all" hook: test');
+        beforeAllItem.fn.should.equal(fn);
+
+        function namedFn(){}
+        this.suite.beforeAll(namedFn);
+        this.suite._beforeAll.should.have.length(2);
+        beforeAllItem = this.suite._beforeAll[1];
+        beforeAllItem.title.should.equal('"before all" hook: namedFn');
+        beforeAllItem.fn.should.equal(namedFn);
+      });
     });
   });
 
@@ -150,7 +166,7 @@ describe('Suite', function(){
 
     describe('wraps the passed in function in a Hook', function(){
       it('adds it to _afterAll', function(){
-        function fn(){}
+        var fn = function(){};
         this.suite.afterAll(fn);
 
         this.suite._afterAll.should.have.length(1);
@@ -158,6 +174,22 @@ describe('Suite', function(){
         afterAllItem.title.should.equal('"after all" hook');
         afterAllItem.fn.should.equal(fn);
       });
+      it('appends title to hook', function(){
+        var fn = function(){};
+        this.suite.afterAll('test', fn);
+
+        this.suite._afterAll.should.have.length(1);
+        var beforeAllItem = this.suite._afterAll[0];
+        beforeAllItem.title.should.equal('"after all" hook: test');
+        beforeAllItem.fn.should.equal(fn);
+
+        function namedFn(){}
+        this.suite.afterAll(namedFn);
+        this.suite._afterAll.should.have.length(2);
+        beforeAllItem = this.suite._afterAll[1];
+        beforeAllItem.title.should.equal('"after all" hook: namedFn');
+        beforeAllItem.fn.should.equal(namedFn);
+      });
     });
   });
 
@@ -168,7 +200,7 @@ describe('Suite', function(){
 
     describe('wraps the passed in function in a Hook', function(){
       it('adds it to _beforeEach', function(){
-        function fn(){}
+        var fn = function(){};
         this.suite.beforeEach(fn);
 
         this.suite._beforeEach.should.have.length(1);
@@ -176,6 +208,23 @@ describe('Suite', function(){
         beforeEachItem.title.should.equal('"before each" hook');
         beforeEachItem.fn.should.equal(fn);
       });
+
+      it('appends title to hook', function(){
+        var fn = function(){};
+        this.suite.beforeEach('test', fn);
+
+        this.suite._beforeEach.should.have.length(1);
+        var beforeAllItem = this.suite._beforeEach[0];
+        beforeAllItem.title.should.equal('"before each" hook: test');
+        beforeAllItem.fn.should.equal(fn);
+
+        function namedFn(){}
+        this.suite.beforeEach(namedFn);
+        this.suite._beforeEach.should.have.length(2);
+        beforeAllItem = this.suite._beforeEach[1];
+        beforeAllItem.title.should.equal('"before each" hook: namedFn');
+        beforeAllItem.fn.should.equal(namedFn);
+      });
     });
   });
 
@@ -186,7 +235,7 @@ describe('Suite', function(){
 
     describe('wraps the passed in function in a Hook', function(){
       it('adds it to _afterEach', function(){
-        function fn(){}
+        var fn = function(){};
         this.suite.afterEach(fn);
 
         this.suite._afterEach.should.have.length(1);
@@ -194,6 +243,23 @@ describe('Suite', function(){
         afterEachItem.title.should.equal('"after each" hook');
         afterEachItem.fn.should.equal(fn);
       });
+
+      it('appends title to hook', function(){
+        var fn = function(){};
+        this.suite.afterEach('test', fn);
+
+        this.suite._afterEach.should.have.length(1);
+        var beforeAllItem = this.suite._afterEach[0];
+        beforeAllItem.title.should.equal('"after each" hook: test');
+        beforeAllItem.fn.should.equal(fn);
+
+        function namedFn(){}
+        this.suite.afterEach(namedFn);
+        this.suite._afterEach.should.have.length(2);
+        beforeAllItem = this.suite._afterEach[1];
+        beforeAllItem.title.should.equal('"after each" hook: namedFn');
+        beforeAllItem.fn.should.equal(namedFn);
+      });
     });
   });
 
diff --git a/tests/lib/mocha-1.17.1/test/utils.js b/tests/lib/mocha-2.1.0/test/utils.js
similarity index 67%
rename from tests/lib/mocha-1.17.1/test/utils.js
rename to tests/lib/mocha-2.1.0/test/utils.js
index f5ea9dc1e7..3810c777b4 100644
--- a/tests/lib/mocha-1.17.1/test/utils.js
+++ b/tests/lib/mocha-2.1.0/test/utils.js
@@ -1,20 +1,26 @@
-
 var mocha = require('..');
 var utils = mocha.utils;
 var clean = utils.clean;
+var isBuffer = utils.isBuffer;
 
-describe('utils', function(){
+describe('utils', function() {
   describe('.clean()', function(){
     it('should remove the wrapping function declaration', function(){
       clean('function  (one, two, three)  {\n//code\n}').should.equal('//code');
-    })
+    });
 
     it('should remove space character indentation from the function body', function(){
       clean('  //line1\n    //line2').should.equal('//line1\n  //line2');
-    })
+    });
 
     it('should remove tab character indentation from the function body', function(){
       clean('\t//line1\n\t\t//line2').should.equal('//line1\n\t//line2');
+    });
+  });
+  describe('.isBuffer()', function(){
+    it('should test if object is a Buffer', function() {
+      isBuffer(new Buffer([0x01])).should.equal(true);
+      isBuffer({}).should.equal(false);
     })
-  })
-})
+  });
+});
-- 
GitLab